Модели именованной области.масштабы


Предыстория этой проблемы довольно сложна и запутанна, и поскольку я ищу простой ответ, я оставлю его в стороне при объяснении моей проблемы, а вместо этого предоставлю эту гипотетическую ситуацию.

Если у меня есть простая модель 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 3

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 и не выполняет проверку типов.