views:

358

answers:

1

Im working on a legacy oracle database with a slightly odd table naming convention where each column name is prefixed with the tables initial letters - eg policy.poli_id.

To make this database easier to work with I have a method set_column_prefix that creates accessors for each column with the prefix removed. ie:

# Taken from wiki.rubyonrails.org/rails/pages/howtouselegacyschemas
class << ActiveRecord::Base
  def set_column_prefix(prefix)
    column_names.each do |name|
      next if name == primary_key

      if name[/#{prefix}(.*)/e]
        a = $1

        define_method(a.to_sym) do
          read_attribute(name)
        end

        define_method("#{a}=".to_sym) do |value|
          write_attribute(name, value)
        end

        define_method("#{a}?".to_sym) do
       self.send("#{name}?".to_sym)
        end

      end
    end
  end
end

This is in a file (insoft.rb) in my lib/ directory, and required from from my config/environment.rb after the Rails::Initializer.run block.

This has been working fine in development, but when I try to run the application in production mode, I get the following error in all of my models:

dgs@dgs-laptop:~/code/voyager$ RAILS_ENV=production script/server 
=> Booting Mongrel
=> Rails 2.3.2 application starting on http://0.0.0.0:3000
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:1964:in `method_missing': 
undefined method `set_column_prefix' for #<Class:0xb3fb81d8> (NoMethodError)
    from /home/dgs/code/voyager/app/models/agent.rb:16

This error is triggered by the 'config.cache_classes = true' line in config/environments/production.rb. If I set this to false, then rails will start up, but won't be caching classes. I'm guessing this makes rails cache all the models before it runs the Initializer block

If I move the 'require "insoft.rb'" to before the start of the Rails::Initializer.run block, then I get errors because ActiveRecord hasn't been initialized yet:

usr/lib/ruby/gems/1.8/gems/activesupport-2.3.2/lib/active_support/dependencies.rb:443:in `load_missing_constant': uninitialized constant ActiveRecord (NameError)
    from /usr/lib/ruby/gems/1.8/gems/activesupport-2.3.2/lib/active_support/dependencies.rb:80:in `const_missing'
    from /usr/lib/ruby/gems/1.8/gems/activesupport-2.3.2/lib/active_support/dependencies.rb:92:in `const_missing'
    from /home/dgs/code/voyager/lib/insoft.rb:1

Where should I be including this custom lib and set_column_prefix method in order for it to be picked up before the models are cached, but after all the activerecord files have loaded?

Cheers

Dave Smylie

+2  A: 

Where should I be including this custom lib and set_column_prefix method in order for it to be picked up before the models are cached, but after all the activerecord files have loaded?

Try setting up an initializer. You can call it config/initializers/insoft.rb with the contents of your monkey patch:

class << ActiveRecord::Base
  def set_column_prefix(prefix)
    column_names.each do |name|
      next if name == primary_key

      if name[/#{prefix}(.*)/e]
        a = $1

        define_method(a.to_sym) do
          read_attribute(name)
        end

        define_method("#{a}=".to_sym) do |value|
          write_attribute(name, value)
        end

        define_method("#{a}?".to_sym) do
          self.send("#{name}?".to_sym)
        end

      end
    end
  end
end
rnicholson
Thanks guys. That seems to have fixed the problem.
Dave Smylie