Rails 选择 GROUP 中 COUNT 最高的对象

Wes*_*ter 3 ruby-on-rails ruby-on-rails-4

我们的目标是选择Store哪一个中Coupon使用最多的。

目前,我有这个,它有效(分解以供解释):

# coupon.rb
  has_many :redemptions
  has_and_belongs_to_many :stores

  def most_popular_store
    stores.find(        # Return a store object
      redemptions       # Start with all of the coupon's redemptions
      .group(:store_id) # Group them by the store_id
      .count            # Get a hash of { 'store_id' => 'count' } values
      .keys             # Create an array of keys
      .sort             # Sort the keys so highest is first
      .first            # Take the ID of the first key
    )
  end
###
Run Code Online (Sandbox Code Playgroud)

它是这样使用的:

describe 'most_popular_store' do
    it 'returns the most popular store' do
        # Create coupon
        coupon = FactoryGirl.create(:coupon)

        # Create two different stores
        most_popular_store = FactoryGirl.create(:store, coupons: [coupon])
        other_store        = FactoryGirl.create(:store, coupons: [coupon])

        # Add redemptions between those stores
        FactoryGirl.create_list(:redemption, 2, coupon: coupon, store: other_store)
        FactoryGirl.create_list(:redemption, 5, coupon: coupon, store: most_popular_store)

        # Verify
        expect(coupon.most_popular_store.title).to eq most_popular_store.title
    end
end
Run Code Online (Sandbox Code Playgroud)

就像我说的,该方法有效,但它看起来像猴子补丁。如何重构我的most_popular_store方法?

小智 6

我认为你的方法实际上不起作用。count给你一个键作为 store_ids 和值作为计数keys的散列,然后你在散列上运行,它给你一个 store_ids 数组。从那时起,您已经失去了计数,您正在按 store_ids 排序并获取第一个。您的测试通过的唯一原因是您在另一个之前创建了流行商店,因此它的 id 较低(sort默认情况下按升序排序)。要获得正确的结果,请进行以下更改:

redemptions       # Start with all of the coupon's redemptions
  .group(:store_id) # Group them by the store_id
  .count            # Get a hash of { 'store_id' => 'count' } values
  .max_by{|k,v| v}  # Get key, val pair with the highest value
                    # output => [key, value]
  .first            # Get the first item in array (the key)
Run Code Online (Sandbox Code Playgroud)