views:

456

answers:

2

Is it possible in ActiveRecord to customize/override the name of an attribute so that it does not match the column name in the database?

My specific case involves a legacy column, "revision", that I can't remove at this time. The column name conflicts with acts_as_audited. Which of course errors out the legacy code that I need until my migrations are complete.

My desired solution would be to override the attribute name for this column, and update the few areas that call it. Thus allowing the legacy column to live alongside acts_as_audited.

A: 

Create a migration to rename the column from revision to whatever-you-want. Then you can declare an attr_accessor :revision and use it without the need to map the attribute to a database field.

Simone Carletti
attr_accessor wouldn't work with acts_as_audited, b/c it is has an attribute revision for any model that is being audited. That override is causing my problem. The attribute itself needs a new name, but I'm trying accomplish this w/o changes to the database. I'm leaving that as a last resort.
catalpa
+2  A: 

I haven't used acts_as_audited, but I'm assuming its implementation is overriding the accessor for that column. In that case, you should be able to just do something like this:

class ActiveRecord::Base
  def self.name_column(column_name, new_name)
    define_method(new_name) {read_attribute column_name}
    define_method("#{new_name}=") {|value| write_attribute column_name, value}
    define_method("#{new_name}?") {attribute_present? column_name}
  end
end

These will directly access the column named in column_name without going through the overridden accessor.

Oh, bonus duplication-destroying metaprogramming answer:

class ActiveRecord::Base
  def self.name_column(column_name, new_name)
    { ''  => :read_attribute, 
      '=' => :write_attribute, 
      '?' => :attribute_present? }.each do |suffix,method|
      define_method("#{new_name}#{suffix}") {|*args| send method, column_name, *args}
    end
  end
end

Just because I like to show how it can be done.

Chuck
I'll give this a shot, and let you know. Nice meta.
catalpa
This gives me an error:NoMethodError: undefined method 'define_method'
catalpa
catalpa
I guess line breaks don't show... sorry the format is lost.
catalpa
Sorry about that. Should have been a class method, but I made it an instance method instead. Now you should be able to just do it in the class context and you'll be fine.
Chuck