ActiveRecord находит идентичный набор в моделях many_to_many - PullRequest
0 голосов
/ 25 февраля 2011

У меня есть анти-шаблон в моем коде Rails 3, и мне было интересно, как это сделать правильно.

Допустим, клиент заказывает картофель фри и гамбургер. Я хочу узнать, был ли такой заказ размещен ранее. Для простоты каждый элемент может быть заказан только один раз за заказ (так что «двух гамбургеров, пожалуйста») и повторных заказов тоже нет.

Модели:

Order (attributes: id)
  has_many :items_orders
  has_many :items, :through => :items_orders

Item (attributes: id, name) 
  has_many :items_orders
  has_many :orders,:through => :items_orders

ItemsOrder (attributes: id, item_id, order_id)
  belongs_to :order
  belongs_to :item 
  validates_uniqueness_of :item_id, :scope => :order_id

Способ, которым я делаю это сейчас, заключается в получении всех заказов, которые включают хотя бы одну из позиций. Затем я перебираю их, чтобы найти соответствующий порядок. Излишне говорить, что это не очень хорошо масштабируется и не выглядит красиво.

order = [1, 2]

1 и 2 соответствуют идентификаторам предметов картофеля фри и гамбургеров.

candidates = Order.find(
  :all, 
  :include => :items_orders, 
  :conditions =>  ["items_orders.item_id in (?)", order])

previous_order = nil

candidates.each do |candidate|
  if candidate.items.collect{|i| i.id} == order
    previous_order = candidate
    break
  end 
end

Я использую MySQL и Postgress, поэтому я также открыт для стандартного решения SQL, которое игнорирует большую часть ActiveRecord.

1 Ответ

0 голосов
/ 25 февраля 2011

Если предположить, что вы хотите найти только идентичных ордеров, я хотел бы использовать хеш для достижения этой цели. Я не могу проверить код, который собираюсь написать, поэтому, пожалуйста, проверьте его, прежде чем полагаться на него!

Примерно так: - Создайте новый атрибут order_hash в модели заказа с помощью миграции. - Добавьте хук before_save, который обновляет этот атрибут, например, с помощью MD5 хэш строк заказа. - Добавьте метод поиска одинаковых ордеров, который использует хеш для быстрого поиска других ордеров.

Код будет выглядеть примерно так:

class Order < ActiveRecord
  def before_save
    self.order_hash = calculate_hash
  end

  def find_similar
    Order.where(:order_hash => self.calculate_hash)
  end

  def calculate_hash
    d = Digest::MD5.new()
    self.items.order(:id).each do |i|
      d << i.id
    end
    d.hexdigest
  end
end

Этот код позволит вам создать и оформить заказ, а затем вызов order.find_similar должен вернуть список заказов с такими же прикрепленными элементами. Вы можете применить точно такой же подход, даже если у вас есть количество товара и т. Д. Единственное ограничение заключается в том, что вы всегда должны искать заказы, которые одинаковы , а не просто неопределенно похожи.

Извинения, если код полон ошибок - надеюсь, вы сможете разобраться в этом!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...