Rails: specifying a different database in the model - mysql

I'm trying to set up Rails (v3.2.2) to use multiple databases. I'm doing this based on this Connecting Rails 3.1 with Multiple Databases.
My model:
class Category < ActiveRecord::Base
establish_connection :category_database
self.primary_key = "cat_id"
validates_presence_of :name, :display_name, :description, :icon, :image, :parent_category_id, :create_time
end
database.yml:
category_database:
adapter: mysql2
encoding: utf8
reconnect: false
database: main_cat
pool: 5
username: root
password: blah
socket: /var/run/mysqld/mysqld.sock
When I run this spec file:
require 'spec_helper'
describe Category do
puts "ENV: #{Rails.env}"
it { should validate_presence_of :name }
it { should validate_presence_of :display_name }
it { should validate_presence_of :description }
it { should validate_presence_of :icon }
it { should validate_presence_of :image }
it { should validate_presence_of :parent_category_id }
it { should validate_presence_of :create_time }
end
like this:
>rspec /path/to/category_spec.rb
I get:
/home/user/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract/connection_specification.rb:45:in `resolve_hash_connection': database configuration does not specify adapter (ActiveRecord::AdapterNotSpecified)
I've also tried setting establish_connection like this:
establish_connection(
:adapter => "mysql2",
:encoding => "utf8",
:reconnect => false,
:database => "main_cat",
:pool => 5,
:username => "root",
:password => "blah",
:socket => "/var/run/mysqld/mysqld.sock")
which results in the same exception. (AdapterNotSpecified)
What's strange is that if I abandon establish_connection altogether and apply the exact same connection configuration via the database.yml file like this:
test:
adapter: mysql2
encoding: utf8
reconnect: false
database: main_cat
pool: 5
username: root
password: blah
socket: /var/run/mysqld/mysqld.sock
it works.
It seems that Rails is ignoring establish_connection altogether...am I missing some application-level config setting or something? How do I get Rails to recognize establish_connection so that I can place different models in different databases?
Much appreciated!

So it turns out that Rails requires the presence of a default configuration. In this case, the database.yml file still requires a test database. Otherwise, Rails will throw an exception as it expects to establish some connection before the models are initialized. Once the default configuration is loaded, Rails goes on later to initialize the models and then model-level database configuration can take place via establish_connection.
I hope this helps someone else out there. It took me a considerable amount of time running the debugger through
activerecord-3.2.2/lib/active_record/connection_adapters/abstract/connection_specification.rb
to figure this out.

I was experiencing the same error for much the same reason, however I did have a test: configuration in my database.yml; but the problem was in my provisioning of the "establish connection" method within the model definition:
establish_connection 'cm_inv_mgmt_' + Rails.env.downcase
although I provided the sections of database.yml for the production/staging and development environments, I was missing cm_inv_mgmt_test!

Related

ActiveRecord MySQL Lost connection to MySQL server during query

I'm having an issue connecting to an external AWS Aurora MySQL in my Rails app in production.
Here is the setup:
One main PostgreSQL database for the app
One external (AWS Aurora MySQL) database used as a reader for huge datasets
In development, everything works fine, but when I deploy to Heroku, I can only successfully query one table of the external database. When I create another table I get this error message:
ActionView::Template::Error (Mysql2::Error::ConnectionError: Lost connection
to MySQL server during query: SELECT `TMC_Identification`.`direction`,
`TMC_Identification`.`miles`, `TMC_Identification`.`road`,
`TMC_Identification`.`tmc` FROM `TMC_Identification`) :
1: <%= raw(#tmcs.to_json) %>
Rails 5.2
Ruby 2.5.3
Models:
class TmcReading < ApplicationRecord
establish_connection(:tmc_data)
self.table_name = "TMC_Readings"
end
class TmcIdentification < ApplicationRecord
establish_connection(:tmc_data)
self.table_name = "TMC_Identification"
end
database.yml:
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
production:
<<: *default
database: production
username: admin
password: <%= ENV['DATABASE_PASSWORD'] %>
tmc_data:
adapter: mysql2
encoding: utf8
database: tmc_data
username: <%= Rails.application.credentials.tmc_data_db[:username] %>
password: <%= Rails.application.credentials.tmc_data_db[:password] %>
host: tmc-data.cluster-ro-xyz.us-east-1.rds.amazonaws.com
port: 3306
Controller Action
def tmc_identifications
#tmcs = TmcIdentification.all.select(:direction, :miles, :road, :tmc)
end
View
<%= raw(#tmcs.to_json) %>
Everything works fine in development, but not in production. The same database and credentials are used in production for the "tmc_data" connection.
I assume I'm having some thread safety issues, but I'm not sure how to fix that.
The way I solved this problem is the following way:
Models:
class TmcData < ActiveRecord::Base
self.abstract_class = true
establish_connection(:tmc_data)
end
class TmcReading < ApplicationRecord
self.table_name = "TMC_Readings"
end
class TmcIdentification < ApplicationRecord
self.table_name = "TMC_Identification"
end
More details: https://www.thegreatcodeadventure.com/managing-multiple-databases-in-a-single-rails-application/
Also, I stopped connecting to the same secondary database with my development and production environment.

Rails connect to remote db

How to properly connect to remote db?
Now i have
def db_params
{:adapter => "mysql2",
:host => "host",
:username => "name",
:password => "pass",
:database => "mydb"}
end
def connect_to_remote_db
ActiveRecord::Base.establish_connection(db_params)
end
When i write connect_to_remote_db it seems ok
I know that remote db has table 'Team'
but when i write Team
in console it returns me uninitialized constant Team
How to handle it properly?
When you call Team ActiveRecord's primary connection is looked up, hence the error.
You could probably wrap that in class.
Since I had dealt with similar situation, you could have that connection in database.ymlitself and use.
development:
adapter: mysql2
other stuff...
db_2:
adapter: mysql2
other stuff..
Then create a class
class Team < ActiveRecord::Base
establish_connection(:db_2)
self.table_name = "teams"
end
from - https://stackoverflow.com/a/26574386/2231236
You need to create model in your application ( of that remote db table) and establish connection. Example:
team.rb
class Team< ActiveRecord::Base
establish_connection "remote_db"
end
If you have multiple table you want to use from that remote db, you can make module and just include it in every model for remote db table.
Module example:
module RemoteConnection
extend ActiveSupport::Concern
included do
establish_connection "remote_db"
end
end
and than
class Team< ActiveRecord::Base
include RemoteConnection
end
Use database.yml file to store connections:
...
remote_db:
:adapter => "mysql2",
:host => "host",
:username => "name",
:password => "pass",
:database => "mydb"
...

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 :/

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