2011-05-05 5 views
1

나는 상호 기본 모델을 제공하여 일부 모델을 일반 named_scope 선언과 컨트롤러 측면에서 더 간단한 쿼리를 활성화하는 필터 메소드를 포함하여 일반화하려고합니다. 이것은 내가 콘솔에서 실행할 때 작동하는 것처럼 보이지만 때 컨트롤러에 실패Rails의 named_scope 상속은 무엇입니까?

분명히 부모 클래스 '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...) 

. 어떤 생각을 고쳐야 할까? 감사.

+1

이 방법으로 문제가 해결되지는 않지만이를 위해 상속 대신 모듈 mixins을 사용해야합니다. 상속은 부모 클래스의 "유형"을 나타내는 하위 클래스를 대상으로합니다. –

+0

사실, @Beerlington, 그건 OP의 문제를 해결할 수 있습니다 :) –

답변

4

ActiveRecord가 말하는 것을 해석하려는 방식 때문에 기차에서 난파가 발생했습니다. 일반적으로 ActiveRecord :: Base에서 파생 된 첫 번째 클래스는 기본 테이블 이름이 무엇인지 정의하는 데 사용되며 하위 클래스는 기본적으로 단일 테이블 상속 (STI)을 사용하도록 정의됩니다. set_table_name을 사용하여이 문제를 해결하고 있지만, 흔히 그렇듯이 레일스에서 ​​곡식을 처리하는 것이 가능하지만 종종 문제가 발생합니다.

Beerlington에서 제안한 믹스 인을 사용하면 훨씬 더 완벽하게이 작업을 수행 할 수 있습니다.

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 

확장 모듈을 포함 할 수 있어야합니다.

class MyModel < ActiveRecord::Base 
    scoped_by_name 
end 
:

class ActiveRecord::Base 
    def scoped_by_name 
    extend ByNameExtension 
    end 
end 

그런 다음 당신이 필요로하는 모든 클래스에 태그를 추가 할 수 있습니다 : 당신이 더욱 이것을 정리하려면이 문제를 유발 액티브 :: 자료에 대한 scoped_by_name 같은 방법을 정의하는 초기화 쓰기

+0

정말 고마워요! - 고마워요! – sa125

+0

멋지게 보입니다. 이니셜 라이저 (ActiveRecord :: Base) 코드 파일은 어디에 두시겠습니까? –

+0

적절한 보석이나 플러그인을 만들지 않았다면 보통'config/initializers'가 좋은 장소입니다. – tadman