ActiveRecord 在多对多模型中找到相同的集合

发布于 2024-10-18 22:23:15 字数 1040 浏览 1 评论 0原文

我的 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 对应薯条和汉堡的 Item id。

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,因此我也愿意采用忽略大部分 ActiveRecord 的标准 SQL 解决方案。

I have an anti-pattern in my Rails 3 code and I was wondering how to do this properly.

Let's say a customer orders french fries and a hamburger. I want to find out if such an order has been placed before. To keep it simple each item can only be ordered once per order (so no "two hamburgers please") and there are no duplicate orders either.

The models:

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

The way I do it now is to fetch all orders that include at least one of the line items. I then iterate over them to find the matching order. Needless to say that doesn't scale well, nor does it look pretty.

order = [1, 2]

1 and 2 correspond to the Item ids of fries and hamburgers.

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

I'm using MySQL and Postgress so I'm also open for a standard SQL solution that ignores most of ActiveRecord.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

月隐月明月朦胧 2024-10-25 22:23:15

假设您只想找到相同订单,我会尝试使用哈希来实现此目的。我无法测试我将要编写的代码,因此请在依赖它之前检查它!

像这样的东西:
- 使用迁移在订单模型中创建一个新属性 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 应该返回附加了相同商品的订单列表。即使您有商品数量等,您也可以应用完全相同的方法。唯一的限制是您必须始终寻找相同的订单,而不仅仅是模糊相似。

如果代码充满错误,我们深表歉意 - 希望您能理解它!

Assuming you only want to find identical orders, I'd be tempted to use a hash to achieve this. I'm not able to test the code I'm about to write, so please check it before you rely on it!

Something like this:
- Create a new attribute order_hash in your Order model using a migration.
- Add a before_save hook that updates this attribute using e.g. an MD5 hash of the order lines.
- Add a method for finding like orders which uses the hash to find other orders that match quickly.

The code would look a little like this:

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

This code would allow you to create and order, and then calling order.find_similar should return a list of orders with the same items attached. You could apply exactly the same approach even if you had item quantities etc. The only constraint is that you have to always be looking for orders that are the same, not just vaguely alike.

Apologies if the code is riddled with bugs - hopefully you can make sense of it!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文