在Ruby on Rails中组织和映射记录

时间:2017-04-19 14:17:11

标签: ruby-on-rails

我有一些文章的销售表

id | user_id | article_id | status
1  | 1       | 1          | 0
2  | 1       | 2          | 0
3  | 2       | 2          | 0
4  | 1       | 1          | 1
5  | 2       | 2          | 1

status = 0 未经证实status = 1 已确认

逻辑如下:用户点击按钮购买文章然后,记录以未确认状态保存在表格中。确认付款后,另一条记录将保存在表格中,状态为已确认。两个记录都保存在表中,以保持整个事务的时间表。 id字段确定给定事务中最旧的记录。

在我的申请中,我想获得 5个最畅销文章的列表,这里是我到目前为止的表现:

# In articles_helper.rb

  def get_articles_sold
    # Fetch all Articles that are present in the Sales table
    sales = Article.where(id: Sale.select(:article_id).map(&:article_id))

    sold = []
    sales.each do |s|
      s.status.group_by(&:status).each do |status, sale|
        if status.to_sym == :confirmed
          sold << {article: s, sold: sale.count}
        end
      end
    end

    # Returns the sold array
    sold
  end

# In the Article model there's this Virtual Attribute 'status'
# It returns me the last status from a given transaction

def status
    sales = Sale.where(article_id: self.id).order(id: :desc)

    statuses = []

    sales.group_by(&:user_id).each do |user, sale|
      statuses << sale.first
    end

    statuses
  end

#In my application

@most_sold_articles = get_articles_sold.sort_by{|v| v[:sold]}.reverse

它给我回复:

@most_sold_articles = [
   {article: #<some_article_entity>, sold: 4},
   {article: #<some_article_entity>, sold: 2},
   {article: #<some_article_entity>, sold: 1},
]

这段代码实际上可以运行并给我我想要的东西,但我认为它是Ruby应用程序的很多代码。是否有任何优雅或更简单的方法来获得相同的结果?

1 个答案:

答案 0 :(得分:3)

我认为应该这样做

@articles = Article
  .joins(:sales)
  .select("articles.*, count(sales.article_id) as sold")
  .group('articles.id').order('sold DESC').limit(5)

如果您想要与答案中的格式相同

@most_sold_articles = @articles.map{|a| {article: a, sold: a.sold}}

#=> [
#=>   {article: #<some_article_entity>, sold: 100},
#=>   {article: #<some_article_entity>, sold: 80},
#=>   {article: #<some_article_entity>, sold: 75},
#=>   {article: #<some_article_entity>, sold: 66},
#=>   {article: #<some_article_entity>, sold: 30}
#=> ]