Модели именованной области.масштабы
Предыстория этой проблемы довольно сложна и запутанна, и поскольку я ищу простой ответ, я оставлю его в стороне при объяснении моей проблемы, а вместо этого предоставлю эту гипотетическую ситуацию.
Если у меня есть простая модель ActiveRecord под названием Automobile, с named_scopes, как показано ниже:
named_scope :classic, :conditions => { :build_date <= 1969 }
named_scope :fast, lambda { |speed| :top_speed >= speed }
Игнорируя сами прицелы, если бы я позвонил:
Automobile.scopes
Что именно это будет возвращением? То, что я вижу в консоли:
[ :classic => #<Proc:0x01a543d4@/Users/user_name/.gem/ruby/1.8/gems/activerecord-2.3.4/lib/active_record/named_scope.rb:87>,
:fast => #<Proc:0x01a543d4@/Users/user_name/.gem/ruby/1.8/gems/activerecord-2.3.4/lib/active_record/named_scope.rb:87> ]
Это мне кажется, что это массив ключей / значений, ключ является символом именованной области, а значение-это Proc, указывающий на named_scope.файл rb в ActiveRecord.
Если я хочу, чтобы хэш или Proc были заданы как фактическая именованная область (что означает: classic, я получу ": conditions = > {: build_date
Я пишу плагин, который условно объединяет некоторые named_scopes, и я сталкиваюсь с некоторым сопротивлением в отношении этого. Я в настоящее время для объединения этих областей используется следующее:
scopes_to_use = Automobile.scopes
scoped_options = {}
Automobile.scopes.each do |scope|
scoped_options.safe_merge!(eval "Automobile.#{scope}(self).proxy_options")
end
Игнорируя "правильность" того, что я делаю здесь, есть ли лучший способ, которым я могу получить фактический хэш или Proc, заданный named_scope? Мне не нравится использовать 'eval' в этой функции, и если бы я действительно мог получить хэш или Proc, то я мог бы ввести гораздо более мощную логику слияния. Любые мысли по этому поводу были бы очень ценны. Спасибо.
1 ответ:
Ни одна именованная область, определенная в вашем примере, не будет ничего делать. Они неверны синтаксически. Это может вызвать проблемы, которые у вас могут возникнуть.
Предположим, что примеры были созданы наспех, и у вас есть рабочие. Перейдем к ответу.
Как я могу найти хэш или Proc, заданный как фактическая именованная область.
Model.scopes[:scope_name]
дает вам proc.Model.send(:scope_name).proxy_options
дает вам хэш опций, заданный области ie:{ :conditions => ["build_date <= ?", 1969] }
Программно получить хэш параметров каждой именованной области в модели можно следующим образом:
scopes_to_use = Automobile.scopes scoped_options = {} Automobile.scopes.keys.each do |scope| scoped_options.safe_merge!(Automobile.send(scope).proxy_options) end
Это не так хорошо работает для областей, требующих аргументов, потому что они могут вызывать исключения. К сожалению, я не могу придумать простой способ обойти это.
Лучшее, что я могу придумать, - это проверить arity proc, а затем предоставить уникальные фиктивные Аргументы и проанализировать возвращенные параметры прокси, чтобы выяснить, что изменилось. Но это большая работа, потому что arity любой именованной области -2. Лучшее, что вы можете сделать при извлечении arity, - это вызвать proc, спасти ошибку аргумента и проанализировать ее на ожидаемое число или аргументы. Затем используйте это количество фиктивных аргументов.
Весь процесс требует спасательного блока и некоторой магии оценки, чтобы работать. И это до того, как вы сможете обработать хэш proxy_options для вашего безопасного слияния.Короче говоря, вы захотите сделать что-то близкое к этому, это не красиво, но это работает:
scopes_to_use = Automobile.scopes scoped_options = {} Automobile.scopes.each do |scope,proc| next if scope == :scoped number_of_args = 1 begin scoped_options.safe_merge! Automobile.send(scope, "#{scope}_argument_1").proxy_options rescue $!.to_s.match /(\d+)\)$/ number_of_args = $1.to_i puts number_of_args end scoped_options.safe_merge!(Automobile.send(scope, *(1..number_of_args).map{|i| "#{scope}_argument_#{i}"}.proxy_options) end
Который должен быть безопасным, потому что proxy_options не выполняет SQL и не выполняет проверку типов.