繁体   English   中英

如何通过关系显示 has_many 中的唯一记录?

[英]How to display unique records from a has_many through relationship?

我想知道通过 Rails3 中的关系显示 has_many 中唯一记录的最佳方式是什么。

我有三个模型:

class User < ActiveRecord::Base
    has_many :orders
    has_many :products, :through => :orders
end

class Products < ActiveRecord::Base
    has_many :orders
    has_many :users, :through => :orders
end

class Order < ActiveRecord::Base
    belongs_to :user, :counter_cache => true 
    belongs_to :product, :counter_cache => true 
end

假设我想列出客户在其展示页面上订购的所有产品。

他们可能多次订购了一些产品,所以我使用 counter_cache 根据订单数量按降序显示。

但是,如果他们多次订购了一个产品,我需要确保每个产品只列出一次。

@products = @user.products.ranked(:limit => 10).uniq!

当一个产品有多个订单记录时有效,但如果一个产品仅被订购一次,则会生成错误。 (排名是在别处定义的自定义排序 function)

另一种选择是:

@products = @user.products.ranked(:limit => 10, :select => "DISTINCT(ID)")

我不确定我在这里的方法是否正确。

有没有其他人解决过这个问题? 你遇到了什么问题? 我在哪里可以找到更多关于.unique 的区别的信息? 和不同()?

通过has_many,通过关系生成唯一记录列表的最佳方法是什么?

谢谢

您是否尝试在 has_many 关联上指定:uniq 选项:

has_many :products, :through => :orders, :uniq => true

Rails 文档

:uniq

如果为 true,将从集合中省略重复项。 与:通过结合使用有用。

导轨 4 的更新:

在 Rails 4 中, has_many:products, :through =>:orders, :uniq => true已被弃用。 相反,你现在应该写has_many:products, -> { distinct }, through: :orders 有关更多信息,请参阅ActiveRecord 关联文档上的 has_many: :through 关系的不同部分 感谢 Kurt Mueller 在评论中指出这一点。

请注意,从 Rails 4 开始,已经从has_many的有效选项中删除了uniq: true

在 Rails 4 中,您必须提供 scope 来配置这种行为。 范围可以通过 lambdas 提供,如下所示:

has_many :products, -> { uniq }, :through => :orders

rails 指南涵盖了这个和其他可以使用范围过滤关系查询的方法,向下滚动到第 4.3.3 节:

http://guides.rubyonrails.org/association_basics.html#has-many-association-reference

您可以使用group_by 例如,我有一个相册购物车,我希望按哪张照片对订购的商品进行排序(每张照片可以多次订购,并且打印尺寸不同)。 然后返回一个 hash ,其中产品(照片)作为键,每次订购时都可以在照片的上下文中列出(或不列出)。 使用这种技术,您实际上可以为每个给定产品 output 一个订单历史记录。 不确定在这种情况下这是否对您有帮助,但我发现它非常有用。 这是代码

OrdersController#show
  @order = Order.find(params[:id])
  @order_items_by_photo = @order.order_items.group_by(&:photo)

@order_items_by_photo然后看起来像这样:

=> {#<Photo id: 128>=>[#<OrderItem id: 2, photo_id: 128>, #<OrderItem id: 19, photo_id: 128>]

因此,您可以执行以下操作:

@orders_by_product = @user.orders.group_by(&:product)

然后,当您在视图中看到此内容时,只需遍历以下内容:

- for product, orders in @user.orders_by_product
  - "#{product.name}: #{orders.size}"
  - for order in orders
    - output_order_details

这样您就可以避免只返回一个产品时出现的问题,因为您始终知道它将返回 hash,其中一个产品作为键和您的订单数组。

对于您尝试做的事情来说,这可能有点矫枉过正,但除了数量之外,它确实为您提供了一些不错的选择(即订购的日期等)。

在 Rails 6 上,我让它完美地工作:

  has_many :regions, -> { order(:name).distinct }, through: :sites

我无法得到任何其他答案。

在 rails6 使用-> { distinct }在 scope 它将工作

class Person
  has_many :readings
  has_many :articles, -> { distinct }, through: :readings
end
 
person = Person.create(name: 'Honda')
article   = Article.create(name: 'a1')
person.articles << article
person.articles << article
person.articles.inspect # => [#<Article id: 7, name: "a1">]
Reading.all.inspect     # => [#<Reading id: 16, person_id: 7, article_id: 7>, #<Reading id: 17, person_id: 7, article_id: 7>]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM