2011-02-06 63 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只會查看(並因此加載)明確包含在視圖中的列。