Rails 2.3 - реализовать динамический named_scope с использованием mixin
Я использую следующую реализацию method_missing, чтобы дать определенной модели адаптируемую фильтрацию named_scope:
class Product < ActiveRecord::Base
def self.method_missing(method_id, *args)
# only respond to methods that begin with 'by_'
if method_id.to_s =~ /^(by\_){1}\w*/i
# extract column name from called method
column = method_id.to_s.split('by_').last
# if a valid column, create a dynamic named_scope
# for it. So basically, I can now run
# >>> Product.by_name('jellybeans')
# >>> Product.by_vendor('Cyberdine')
if self.respond_to?( column.to_sym )
self.send(:named_scope, method_id, lambda {|val|
if val.present?
# (this is simplified, I know about ActiveRecord::Base#find_by_..)
{ :conditions => ["#{base.table_name}.#{column} = ?", val]}
else
{}
end
})
else
super(method_id, args)
end
end
end
end
Я знаю, что это уже обеспечивается ActiveRecord::Base с помощью find_by_<X>
, но я пытаюсь пойти немного дальше примера, который я привел, и предоставить некоторую настраиваемую фильтрацию для моего приложения. Я хотел бы сделать его доступным для выбранных моделей без необходимости вставлять этот фрагмент в каждый класс моделей. Я подумал об использовании модуля, а затем смешал его с выбранными моделями - я немного расплывчат в синтаксисе.
Я дошел до этого, когда ошибки начали накапливаться (я делаю это правильно?):
module GenericFilter
def self.extended(base)
base.send(:method_missing, method_id, *args, lambda { |method_id, args|
# ?..
})
end
end
Тогда я надеюсь, что смогу использовать это так:
def Product < ActiveRecord::Base
include GenericFilter
end
def Vendor < ActiveRecord::Base
include GenericFilter
end
# etc..
Любая помощь будет отличной - спасибо.
2 ответа
Два способа достижения этого
модуль GenericModule def self.included(base) base.extend ClassMethods конец модуль ClassMethods def method_missing #.... конец конец конец класс YourModel включить GenericModule .. конец
или же
модуль GenericModule def method_missing #... конец конец класс MyModel расширить GenericModule конец
Я бы предложил использовать первый, который кажется мне чище. И как общий совет, я бы избегал переопределения method_missing:).
Надеюсь это поможет.
Вы должны определить область действия в контексте класса, который включает ваш миксин. Оберните ваши области в include_class.class_eval, и для self будет правильно задано значение include_class.
module Mixin
def self.included(klass)
klass.class_eval do
scope :scope_name, lambda {|*args| ... }
end
end
end
class MyModel
include Mixin
end