This project is archived and is in readonly mode.

#6491 new
Sebastian Vogelsang

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

    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

    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

    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

    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>

People watching this ticket

Pages