Пользовательский ActiveRecord Finder, вызывающий именованные области? - PullRequest
3 голосов
/ 03 февраля 2010

У меня есть пользовательский искатель, определенный ниже:

class ContainerGateIn << ActiveRecord::Base
  ...
  def self.search(text)
    result = if text
      text.split(' ').inject(self) do |result, criteria|
        case criteria
          when /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/
            result.search_by_date(criteria.to_date)
          else
            result.search_by_text(criteria)
        end
      end
    else
      self
    end
  end
  ...
end

Где search_by_date и search_by_text являются именованными областями, а eager является загружаемой именованной областью действия, определяемой как:

named_scope :eager, :include => [{:container_inventory => {:container => [:size_type, :grade]}}, :company, :truck, :hauler]

Ассоциация настраивается через HMT (has_many: through):

class ContainerDepot << ActiveRecord::Base
  has_many :container_inventories
  has_many :container_gate_ins, :through => :container_inventories do
end

Проблема в том, что, если искатель вызывается через вложенность ассоциации из ContainerDepot, он завершается ошибкой с ActiveRecord :: Statement :: Invalid, говоря, что таблица была указана более одного раза.

ContainerDepot.first.container_gate_ins.eager.search(text)
=> ActiveRecord::StatementInvalid: PGError: ERROR:  table name "container_inventories" specified more than once

Я мог бы исправить это, скопировав весь пользовательский искатель как расширение ассоциации:

class ContainerDepot << ActiveRecord::Base
  ...
  has_many :container_gate_ins, :through => :container_inventories do
    def search(text)
      ... custom finder code from ContainerGateIn ...
    end
  end
  ...
end

Хотя это не очень СУХОЙ и вносит очень ненужную и потенциально проблематичную избыточность, так как пользовательский искатель будет время от времени изменяться, чтобы приспособить дополнительную логику поиска.

Какие-нибудь идеи о том, как это можно сделать лучше?

1 Ответ

0 голосов
/ 17 апреля 2010

Вы можете использовать named_scope с лямбдой, что позволяет передавать параметры в метод определения объема:

named_scope :eager, lambda {|text| {:conditions=>{:name=>text}, :include => [{:container_inventory => {:container => [:size_type, :grade]}}, :company, :truck, :hauler]}}

Это должно позволить вам включать и фильтровать только одну именованную область.

...