ActiveRecord 在多对多模型中找到相同的集合
我的 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
假设您只想找到相同订单,我会尝试使用哈希来实现此目的。我无法测试我将要编写的代码,因此请在依赖它之前检查它!
像这样的东西:
- 使用迁移在订单模型中创建一个新属性
order_hash
。- 添加一个
before_save
挂钩,使用订单行的 MD5 哈希值更新此属性。- 添加查找类似订单的方法,该方法使用哈希来查找快速匹配的其他订单。
代码看起来有点像这样:
此代码允许您创建和订购,然后调用 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:
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!