2011-02-06 62 views
7

我有一个遗留数据库,我试图使用Rails进行建模。其中一个表有一个名为attributes的列,我认为这是一个由Rails保留的名称。如何永久地忽略ActiveRecord :: Base类中的数据库列?

下面是表的SQL:

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', 
    ... 
); 

这里是我的ActiveRecord类:

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

这里是当我尝试实例化一个实例会发生什么:

[email protected]:~/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/[email protected]/gems/activerecord-3.0.3/lib/active_record/attribute_methods.rb:23:in `instance_method_already_implemented?' 
    from /Users/hornairs/.rvm/gems/[email protected]/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/[email protected]/gems/activemodel-3.0.3/lib/active_model/attribute_methods.rb:262:in `each' 
    from /Users/hornairs/.rvm/gems/[email protected]/gems/activemodel-3.0.3/lib/active_model/attribute_methods.rb:262:in `block in define_attribute_methods' 
    from /Users/hornairs/.rvm/gems/[email protected]/gems/activemodel-3.0.3/lib/active_model/attribute_methods.rb:261:in `each' 
    from /Users/hornairs/.rvm/gems/[email protected]/gems/activemodel-3.0.3/lib/active_model/attribute_methods.rb:261:in `define_attribute_methods' 
    from /Users/hornairs/.rvm/gems/[email protected]/gems/activerecord-3.0.3/lib/active_record/attribute_methods.rb:13:in `define_attribute_methods' 
    from /Users/hornairs/.rvm/gems/[email protected]/gems/activerecord-3.0.3/lib/active_record/attribute_methods.rb:41:in `method_missing' 
    from /Users/hornairs/.rvm/gems/[email protected]/gems/thwart-0.0.4/lib/thwart/canable.rb:27:in `method_missing' 
    from (irb):2 
    from /Users/hornairs/.rvm/gems/[email protected]/gems/railties-3.0.3/lib/rails/commands/console.rb:44:in `start' 
    from /Users/hornairs/.rvm/gems/[email protected]/gems/railties-3.0.3/lib/rails/commands/console.rb:8:in `start' 
    from /Users/hornairs/.rvm/gems/[email protected]/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 > 

它看起来好像attributes名称是保留的,所以我想找到一些方法来忽略它查询并在反映模式以定义模型类时让AR忽略它。有什么建议么?谢谢!

+0

我不知道解决方案,但我发现与某人有相同问题的线程:。不知道它会有帮助。 – Robin 2011-02-06 02:48:36

回答

9

解决了这个利用罗宾的链接的东西组合和一些其他的SO答案

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 

的伎俩。我用了一个很大的改变来返回true,而不是从attributes开始的所有方法都抛出一个错误,我不认为它在其他地方引起了任何问题。

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

这个补丁是很好,大部分是为我工作,但是当你检查像 Album.column_names和Album.columns.collect(&:名字),你仍然会得到所有列。 这也会失败。

a = Album.last 
a = Album.new(a.attributes) 

要让rails完全忽略列,你可以这样做。

class Album < ActiveRecord::Base 
    set_table_name "album" 
    ## --------------------- Ignore columns patch ------ 
    @@ignore_column_pattern = /^column_one|^column_two/ 

    class << self 
     alias :all_columns :columns 
     def columns 
     @columns_filt ||= all_columns.reject { |col| col.name =~ @@ignore_column_pattern } 
     end 
    end 

    alias :all_attribute_names :attribute_names 
    def attribute_names 
     @attr_names_filt ||= all_attribute_names.reject { |att| att =~ @@ignore_column_pattern } 
    end 
    ## -------------------/Ignore columns patch ------ 
    belongs_to :artist 
    has_many :tracks, :through => :album_tracks 
    end 

而且我用了一个数组来存储我不想在列,但你仍然可以使用正则表达式的方式呢!现在,您可以了解该列的唯一方法是使用连接ie。

Album.connection.columns("albums").collect(&:name) 
3

(这是一个老问题,但在谷歌还是人物,所以我会添加一个迟来的答案)

我发现,以限制ActiveRecord模型加载数据的最佳方式是创建一个数据库视图只包含你想加载的列。您可以使用ActiveRecord的table_name方法将ActiveRecord模型指向受限视图。原生SQL工具仍然可以操作底层表,但ActiveRecord只会查看(并因此加载)明确包含在视图中的列。