make queries on multiple db in same action controller with transaction rails? - mysql

I have in my database.yml :
default: &default
[...]
development_1:
<<: *default
database: dev1
development_2:
<<: *default
database: dev2
I need to make many queries in foo action but using these 2 DB :
class UsersController < ApplicationController
def foo
users_nb = User.count #this use my default db : dev1
other_connexion = ActiveRecord::Base.establish_connection("#{Rails.env}_2").connection
users_nb_other_site = connexion.execute("SELECT COUNT(*) FROM users").first[0]
end
end
that works, BUT I encapsulate all action controller in transaction like :
ActiveRecord::Base.transaction do
begin
yield
rescue Exception => e
raise ActiveRecord::Rollback
end
with this, my previous code doesn't works, it raise an error :
ActiveRecord::StatementInvalid in UsersController#foo NoMethodError:
undefined method `query' for nil:NilClass Did you mean? to_query:
ROLLBACK
the line of error is : ActiveRecord::Base.transaction do
So how can I do to make my connexion and queries on another db in same time that my principal db?

Ok, my problem was I don't understand ActiveRecord::Base.establish_connection overwrite my first connexion and the transaction too.
I create an abstract class like said here : https://makandracards.com/makandra/10169-when-connecting-to-a-second-database-take-care-not-to-overwrite-existing-connections
class ReadDatabaseConnection < ActiveRecord::Base
def self.abstract_class?
true # So it gets its own connection
end
end
ReadDatabaseConnection.establish_connection(slave_settings)
I keep my 2 connexion like that, without pb !

Related

Running Stored procedure giving error can't return a result set in the given context

I know this problem has been asked many times. But I tried the solutions and they didn't work for me. I have a web application built on rails 3.2.12 and ruby 1.9.2p180. I have a stored procedure in it which returns me data of a query having 5 inner joins. Multiple rows approximately 600 are returned in present case. On the local the stored procedure runs fine with no issues. But when I tried it on the server it is throwing:
ActiveRecord::StatementInvalid: Mysql2::Error: PROCEDURE test.sp_procedure can't return a result set in the given context: call sp_procedure('2015-02-14 00:00:00 -0500', '2015-03-03 23:59:00 -0500', 5, '13')
I have searched for this issue and found that I need to set CLIENT_MULTI_RESULTS flag when establishing connection to MySQL server. For this I have done monkey patching as said. Here is the file in initializers:
module ActiveRecord
class Base
def self.mysql2_connection(config)
config[:username] = 'deploy' if config[:username].nil?
if Mysql2::Client.const_defined? :FOUND_ROWS
config[:flags] = config[:flags] ? config[:flags] | Mysql2::Client::FOUND_ROWS : Mysql2::Client::FOUND_ROWS
end
client = Mysql2::Client.new(config.symbolize_keys)
options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config)
end
def self.select_sp(sql, name = nil)
connection = ActiveRecord::Base.connection
begin
connection.select_all(sql, name)
rescue NoMethodError
ensure
connection.reconnect! unless connection.active?
end
end
end
end
In my database.yml I have added: flags: <%= 65536 | 131072 %> and also tried with flags: 131072. But it didn't work.
However using the following works:
client = Mysql2::Client.new(:host => "localhost", :username => "root", :flags => Mysql2::Client::MULTI_STATEMENTS )
result = client.query( 'CALL sp_procedure('2015-02-14 00:00:00 -0500', '2015-03-03 23:59:00 -0500', 5, '13')')
This worked on the server too. But each time the stored procedure will run it will create a new connection which I don't want.
And also one thing to note while I am doing this on local as soon as I call the stored procedure I have to execute this:
ActiveRecord::Base.connection.reconnect!
If I don't write this it throws an error:
ActiveRecord::StatementInvalid: Mysql2::Error: Commands out of sync; you can't run this command now
So this is also the same thing means it creates a new connection each time. So I am finding for a solution which saves me from doing this.
And if the monkey patching is correct then what am I missing. Please help.

Rails 4.1.1 Postgres app with Mysql Legacy database Import

I've been building a rails app using a postgres database but of course I also have been tasked with importing data from a legacy mysql database.
The way I've been handling this so far:
# config/database.yml
development:
adapter: postgresql
encoding: unicode
database: myapp_development
pool: 10
username: myuser
password:
legacy_development:
adapter: mysql2
encoding: utf8
reconnect: false
database: myapp_legacy
pool: 10
username: myuser
password:
socket: /tmp/mysql.sock
# app/models/legacy.rb
class Legacy < ActiveRecord::Base
self.abstract_class = true
establish_connection "legacy_#{Rails.env}".to_sym
def self.import
self.find_each do |object|
imported_model = object.class.model.new object.attribute_map
object.report_failures unless imported_model.save
end
end
def self.import_all
Rails.application.eager_load!
self.subclasses.each {|subclass| subclass.import }
end
end
# app/models/legacy/chapter.rb
# a bunch of different subclasses like this
class Legacy::Chapter < Legacy
self.table_name = 'chapters'
def self.model
'Chapter'.constantize
end
def attribute_map
{
id: id,
name: name,
body: chapterBody
}
end
end
Then I have a rake task that runs Legacy.import_all. A lot of this was stolen from this post.
There's a few things wrong with this:
The main problem is, when i run Legacy.import_all it makes it through about half of the tables then I get an error like:
NoMethodError: undefined method 'import' for Legacy::SomeSubclass(Table doesn't exist):Class
I think this is because we just have too many connections in the pool. It seems though like it is looking for the SomeSubClass table_name from within the postgres database, but it should be looking on the mysql database.
This is probably because of the methods like:
def self.model
'Chapter'.constantize
end
in the above subclass. I am doing it like that instead of:
def self.model
Chapter
end
because I have a normal model (non-legacy) in my app also called Chapter and I was running into scoping issues there as well.
Anyways this is a huge mess and any thoughts about where I should dig would be greatly appreciated.
Thanks
Can you try prefixing subclass.import with ::
def self.import_all
Rails.application.eager_load!
self.subclasses.each {|subclass| ::subclass.import }
end

How to make a model point to non-default schema

I've searched all over and I can't find anything related to this.
Basically I have the default schema set to abc
In abc I have some tables, etc ...............
I want to make a model that uses table mobile_activity_logs in schema def
The default rails model looks like this:
class MobileActivityLogs < ActiveRecord::Base
# attr_accessible :title, :body
end
but the query is on abc.mobile_activity_logs and not def.mobile_activity_logs
abc.mobile_activity_logs doesn't exist
In the database.yml file:
tester:
adapter: mysql2
database: def
host:
port:
username:
password:
enable_call: true
flags: CLIENT_MULTI_RESULTS
In the model:
class MobileActivityLogs < ActiveRecord::Base
establish_connection "tester"
self.table_name = "mobile_activity_logs"
end
This is a bit ugly though as it will make a second connection just to access a different schema :/

500 Error in production adapter rails when starting new user session

I have been having this issue ever since I deployed and i can't figure it out.
I'll give some information and let me know if you need anything else! Thanks!
I, [2013-09-08T12:44:31.935143 #19456] INFO -- : Started POST "/sessions" for {IP ADDRESS} at 2013-09-08 12:44:31 -0700
I, [2013-09-08T12:44:31.937969 #19456] INFO -- : Processing by SessionsController#create as HTML
I, [2013-09-08T12:44:31.938102 #19456] INFO -- : Parameters: {"utf8"=>"✓", "authenticity_token"=>"{AUTHENTICITY TOKEN}", "email"=>"mike#test.com", "password"=>"[FILTERED]", "commit"=>"Log In"}
I, [2013-09-08T12:44:31.941064 #19456] INFO -- : Completed 500 Internal Server Error in 3ms
F, [2013-09-08T12:44:31.943631 #19456] FATAL -- :
ActiveRecord::StatementInvalid (Could not find table 'users'):
app/controllers/sessions_controller.rb:6:in `create'
Obviously it's telling me that the "users" table doesn't exist, but that BS, because it does. Perhaps it can't find the table? Which i ALSO think is wierd, because I created the table using Rails migrations.
Here is my production Adapter just for reference:
production:
adapter: mysql
database: {DATABASENAME}
username: {USERNAME}
password: {PASSWORD}
host: localhost
port: 3306
Here is my seeds file:
User.create([{ email: 'mike#test2.com' }, { password_digest: 'password' }])
And my user model:
class User < ActiveRecord::Base
has_secure_password
validates_uniqueness_of :email
end
And my sessions controller (handles the login):
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to root_url, notice: "Logged in!"
else
flash.now.alert = "Email or password is invalid"
render "new"
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, notice: "Logged out!"
end
end
I created the user directly in the database, so the issue isn't that the user doesnt exist, the log file is saying the table 'users' doesnt exist, but that is false as well...i really don't know whats going on...
OH, BTW this all works in development. Login, user creation, everything. I was using sqlite3 for development and switched to mysql for production, just screwed everything up....
Any help is appreciated!
For future reference, this is the fix if anyone else is having an issue with their seeds not working:
This is what I was using:
User.create([{ email: 'mike#test2.com' }, { password_digest: 'password' }])
This is what it should be:
users =User.create!(:email 'mike#test2.com', :password 'password', :password_confirmation 'password')
users.save
Using
Create!
instead of just plain
Create
enables validation, and the seed will fail and explain the problem. In my case, it was that I was using password_digest, which is the column name, instead of password and password_confirmation.
Also, save the seed creation in a variable (users in my case), then save said variable by doing this:
users.save
Simple as that!
Hope this helps a fellow newbie in the future!

Multiple DB connection in rails

I am trying to connect multiple database in ROR application.My database.yml is look like this
in your database.yml file
development:
adapter: mysql
username: root
password:
database: example_development
private:
adapter: mysql
username: root
password:
database: example_private_development
It is possible to connect using establish_connection :private
My doubt is that how use rake db:create.I am not able get solution from google.
Please help me to clear it.
Try
rake db:create:all
And yes, it's possible to have multiple db connections in a Rails application.
This is what I did once, I have created two classes which inherit from ActiveRecord::Base and set the connections inside those classes.
Then I inherited all my models in one of those classes instead of direct ActiveRecord
Below is an example:
database.yml file
#app uses two database
#1 - test1
#2 - test2
test1:
adapter: mysql
encoding: utf8
database: test1
username: root
password: xxx
host: localhost
test2:
adapter: mysql
encoding: utf8
database: test2
username: root
password: xxx
host: localhost
Then I have two models for both test1 and test2 databases:
class Test1Base < ActiveRecord::Base
self.abstract_class = true
establish_connection("test1")
end
class Test2Base < ActiveRecord::Base
# No corresponding table in the DB.
self.abstract_class = true
establish_connection("test2")
end
Then I inherit my models according to database:
class School < Test1Base
#code
end
class Student < Test2Base
#code
end
Thanks for reply.
we can migrate a model for particular DB, for example
db:migrate RAILS_ENV="portal_development"'.
And more change for establishing connection with DB.check the corrected below
class Test1Base < ActiveRecord::Base
self.abstract_class = true
establish_connection :development
end
class Test2Base < ActiveRecord::Base
# No corresponding table in the DB.
self.abstract_class = true
establish_connection :portal_development
end
Thanks sameera for your valuable reply.
cheers
Shamith c
Possibly use active_delegate?
http://railslodge.com/plugins/595-active-delegate