This project is archived and is in readonly mode.
Arel not picking up on ActiveRecord establish_connection settings
Reported by Sebastian Vogelsang | March 1st, 2011 @ 11:46 AM
Hi there,
in my 3.0.4 application I'm trying to set an individual
databases for some of my models in the following way within the
environment.rb:
models.each do |klass|
next unless klass < ActiveRecord::Base
klass.establish_connection "processing_#{Rails.env}"
end
When doing a Channel.connection.instance_eval
{@config[:database]}
afterwards (Channel being one of my
models), all appears correct. However, when doing a
Channel.arel_engine.connection.instance_eval
{@config[:database]}
, I get the standard ActiveRecord
database connection returned. It appears as if Arel does not pick
up on the modified active_record
connection. The funny
thing is that this only appears for some of my models. Others
return the correct database for both connection and
arel_engine.
Another thing to notice is that while Channel.first
works fine, I get the following error, when doing a
Channel.find(1)
:
NoMethodError: undefined method `eq' for nil:NilClass
Regards,
Sebastian
Comments and changes to this ticket
-
Sebastian Vogelsang March 1st, 2011 @ 06:21 PM
ok, I got it working by changing my code to the following:
models.each do |klass| next unless klass < ActiveRecord::Base klass.establish_connection "processing_#{Rails.env}" klass.class_eval do @arel_engine = klass @arel_table = Arel::Table.new(klass.table_name, klass) @relation = ActiveRecord::Relation.new(klass, @arel_table) end end
I hope this is not the way we have to do it from now?!? Shouldn't establish_connection take care of setting up the AREL Relations appropriately?
Sebastian
-
atomgas March 22nd, 2011 @ 11:20 AM
HasAndBelongsToMany did not work with multiple database, this fixed it for me:
module ActiveRecord # = Active Record Has And Belongs To Many Association module Associations class HasAndBelongsToManyAssociation < AssociationCollection protected def insert_record(record, force = true, validate = true) if record.new_record? if force record.save! else return false unless record.save(:validate => validate) end end if @reflection.options[:insert_sql] @owner.connection.insert(interpolate_and_sanitize_sql(@reflection.options[:insert_sql], record)) else # IMPORTANT!!! # here active record does not pass the engine to Arel::Table and thus Arel::Table uses Table.engine = ActiveRecord::Base # IMPORTANT!!! relation = Arel::Table.new(@reflection.options[:join_table], @owner.class.arel_engine) timestamps = record_timestamp_columns(record) timezone = record.send(:current_time_from_proper_timezone) if timestamps.any? # debugger attributes = Hash[columns.map do |column| name = column.name value = case name.to_s when @reflection.primary_key_name.to_s @owner.id when @reflection.association_foreign_key.to_s record.id when *timestamps timezone else @owner.send(:quote_value, record[name], column) if record.has_attribute?(name) end [relation[name], value] unless value.nil? end] relation.insert(attributes) end return true end def delete_records(records) if sql = @reflection.options[:delete_sql] records.each { |record| @owner.connection.delete(interpolate_and_sanitize_sql(sql, record)) } else # IMPORTANT!!! # here active record does not pass the engine to Arel::Table and thus Arel::Table uses Table.engine = ActiveRecord::Base # IMPORTANT!!! relation = Arel::Table.new(@reflection.options[:join_table], @owner.class.arel_engine) relation.where(relation[@reflection.primary_key_name].eq(@owner.id). and(relation[@reflection.association_foreign_key].in(records.map { |x| x.id }.compact)) ).delete end end end end end
-
Sebastian Vogelsang April 12th, 2011 @ 11:52 AM
anyone? This is a rather serious issue! I can't imagine that nobody else has encountered these problems when connecting to multiple databases?!
-
Ibrahim April 13th, 2011 @ 12:55 PM
You don't need to do this in the environment.rb If you want separate connections in your models, use the ActiveRecord::Base.establish_connection method that takes a options hash. Place your database configuration in the appropriate config file and use that in your model:
class User < ActiveRecord::Base establish_connection( :adapter => "mysql" :host => "localhost" ) end
If you want to use your YAML, it is available as a symbol within ActiveRecord::Base like so:
class User < ActiveRecord::Base establish_connection :from_yaml end
And to keep things dry, you can setup a parent model that establishes the connection to the other database and let your models inherit from it, since establish_connection stays in the family!
class Person < ActiveRecord::Base establish_connection :private_government_database end class User < Person end class Admin < User end
Hope this helps you ;-)
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>