Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I permanently ignore a database column in my ActiveRecord::Base class?

I have a legacy database which I'm trying to model using Rails. One of the tables has a column named attributes, which is a name reserved by Rails I think.

Here is the SQL for the table:

CREATE TABLE `album` (
  `id` int(11) NOT NULL,
  `artist` int(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  `gid` char(36) NOT NULL,
  `modpending` int(11) DEFAULT '0',
  `attributes` int(11) DEFAULT '0',
  ...
);

Here's my ActiveRecord class:

class Album < ActiveRecord::Base
  set_table_name "album"
  belongs_to :artist
  has_many :tracks, :through => :album_tracks
end

Here's what happens when I try to instantiate an instance:

hornairs@bishop:~/Sites/logdb (master *)$ rails c
Loading development environment (Rails 3.0.3)
no such file to load -- irbtools
ruby-1.9.2-p0 > x = Album.find_by_name("Champ")
 => #<Album id: 969139, artist: 354493, name: "Champ", gid: "15a9a4b8-9dd9-4f6f-b4e9-7c69948af88f", modpending: 0, attributes: 1100, page: 143735328, language: 120, script: 28, modpending_lang: nil, quality: -1, modpending_qual: 0> 
ruby-1.9.2-p0 > x.name
ActiveRecord::DangerousAttributeError: attributes_before_type_cast is defined by ActiveRecord
  from /Users/hornairs/.rvm/gems/ruby-1.9.2-p0@logdb/gems/activerecord-3.0.3/lib/active_record/attribute_methods.rb:23:in `instance_method_already_implemented?'
  from /Users/hornairs/.rvm/gems/ruby-1.9.2-p0@logdb/gems/activemodel-3.0.3/lib/active_model/attribute_methods.rb:263:in `block (2 levels) in define_attribute_methods'
  from /Users/hornairs/.rvm/gems/ruby-1.9.2-p0@logdb/gems/activemodel-3.0.3/lib/active_model/attribute_methods.rb:262:in `each'
  from /Users/hornairs/.rvm/gems/ruby-1.9.2-p0@logdb/gems/activemodel-3.0.3/lib/active_model/attribute_methods.rb:262:in `block in define_attribute_methods'
  from /Users/hornairs/.rvm/gems/ruby-1.9.2-p0@logdb/gems/activemodel-3.0.3/lib/active_model/attribute_methods.rb:261:in `each'
  from /Users/hornairs/.rvm/gems/ruby-1.9.2-p0@logdb/gems/activemodel-3.0.3/lib/active_model/attribute_methods.rb:261:in `define_attribute_methods'
  from /Users/hornairs/.rvm/gems/ruby-1.9.2-p0@logdb/gems/activerecord-3.0.3/lib/active_record/attribute_methods.rb:13:in `define_attribute_methods'
  from /Users/hornairs/.rvm/gems/ruby-1.9.2-p0@logdb/gems/activerecord-3.0.3/lib/active_record/attribute_methods.rb:41:in `method_missing'
  from /Users/hornairs/.rvm/gems/ruby-1.9.2-p0@logdb/gems/thwart-0.0.4/lib/thwart/canable.rb:27:in `method_missing'
  from (irb):2
  from /Users/hornairs/.rvm/gems/ruby-1.9.2-p0@logdb/gems/railties-3.0.3/lib/rails/commands/console.rb:44:in `start'
  from /Users/hornairs/.rvm/gems/ruby-1.9.2-p0@logdb/gems/railties-3.0.3/lib/rails/commands/console.rb:8:in `start'
  from /Users/hornairs/.rvm/gems/ruby-1.9.2-p0@logdb/gems/railties-3.0.3/lib/rails/commands.rb:23:in `<top (required)>'
  from script/rails:6:in `require'
  from script/rails:6:in `<main>'
ruby-1.9.2-p0 > 

It looks as if the attributes name is reserved, so I'd like to find some way to ignore it for all queries and have AR ignore it when reflecting on the schema to define the model class. Any suggestions? Thanks!

like image 442
hornairs Avatar asked Feb 06 '11 02:02

hornairs


2 Answers

(This is an old question but still figures in Google so I'll add a belated answer)

I've found the best way to restrict data loaded by an ActiveRecord model is to create a database view that only contains the columns you wish to load. You can point your ActiveRecord model at the constrained view using ActiveRecord's table_name method. Native SQL tools can still manipulate the underlying table, but ActiveRecord will only see (and consequently load) the columns explicitly included in the view.

like image 92
Ivar Avatar answered Oct 25 '22 10:10

Ivar


Solved this using a combination of stuff from Robin's link and some other SO answers

class Album < ActiveRecord::Base
  set_table_name "album"

  class << self
    def instance_method_already_implemented?(method_name)
      return true if method_name =~ /^attributes/
      super
    end
  end

  belongs_to :artist
  has_many :tracks, :through => :album_tracks
end

Did the trick. I used a big sweeping change to return true without throwing an error for all methods starting with attributes, and I don't think its caused any problems elsewhere.

like image 43
hornairs Avatar answered Oct 25 '22 10:10

hornairs