2011-05-05 105 views
1

我試圖通過提供一個通用的基礎模型來繼承一些我的模型,該模型包含一些相互的named_scope聲明和一個過濾器方法,用於激活在控制器端更簡單的查詢。這似乎當我在控制檯中運行其上工作,但未能在控制器中時:Rails的named_scope繼承?

# in the base model 
class GenericModel < ActiveRecord::Base 

    named_scope :by_name, lambda { |name| 
    (name.blank?) ? {} : { :conditions => [ "#{self.table_name}.name like ?", "%#{name}%" ] } 
    } 

    def filter(params) 
    res = [] 
    res = self.by_name((params[:name] or '')) if params[:name] 
    return res 
    end 

end 

class MyModel < GenericModel 
    set_table_name 'my_models' 
end 

# works in in console! 
>> params = { :name => 'jimmy' } 
>> MyModel.filter(params) 
=> [ <#MyModel ...>, ... ] 
nil 

# fails in controller 
@model = MyModel.filter(params) 

# ActiveRecord::StatementInvalid (Mysql::Error Unknown column 'generic_models.name' in where clause...) 

顯然父類named_scope被稱爲軌道的時候,但工作在軌控制檯罰款。任何想法如何修補這個?謝謝。

+1

這不是說這可以解決你的問題,但是你應該使用模塊mixins代替繼承。繼承適用於代表父類「類型」的子類。 – 2011-05-05 12:37:30

+0

其實,@Beerlington,可能解決OP的問題:) – 2011-05-05 13:39:43

回答

4

由於ActiveRecord試圖解釋你所說的話,這有點像火車殘骸。通常,派生自ActiveRecord :: Base的第一個類用於定義基表名稱,其中的子類默認定義爲使用單表繼承(STI)。你正在通過使用set_table_name來解決這個問題,但通常情況下,雖然有可能在Rails中反對穀物,但事情往往會變得混亂。

您應該可以像Beerlington所建議的那樣,使用mixin更乾淨地做到這一點。

module ByNameExtension 
    def self.extended(base) 
    # This method is called when a class extends with this module 

    base.send(:scope, :by_name, lambda { |name| 
     name.blank? ? nil : where("#{self.table_name}.name LIKE ?", "%#{name}%") 
    }) 
    end 

    def filter(params) 
    params[:name].present? ? self.by_name(params[:name]) : [ ] 
    end 
end 

class MyModel < ActiveRecord::Base 
    # Load in class-level methods from module ByNameExtension 
    extend ByNameExtension 
end 

您應該能夠將您的擴展包含在該模塊中。如果您想進一步清理它,編寫定義像scoped_by_name的方法ActiveRecord的::基地初始化觸發此行爲:

class ActiveRecord::Base 
    def scoped_by_name 
    extend ByNameExtension 
    end 
end 

然後你就可以標記需要這一切類:

class MyModel < ActiveRecord::Base 
    scoped_by_name 
end 
+0

很酷 - 謝謝! – sa125 2011-05-08 05:38:55

+0

這看起來不錯。你在哪裏把初始化器(ActiveRecord :: Base)的代碼文件? – 2011-07-31 16:38:21

+0

除非你已經做出了正確的寶石或插件,通常'config/initializers'是個好地方。 – tadman 2011-07-31 21:15:45