查询模型以包括相关事务的总和

时间:2014-10-30 18:56:17

标签: ruby-on-rails postgresql view controller sum

我的库存应用程序中有三个模型用于分类,项目和交易。我创建了一个报告,向我展示了我想知道的内容,但我怀疑在视图中查询是不好的做法。我怀疑这是低效的。这是我目前的观点:

<table>
  <tr>
    <th>Category</th>
    <th>Name</th>
    <th>Description</th>
    <th>Total</th>
  </tr>
<% @item_id_list.each do |item_id| %>
  <% item = Item.find(item_id) %>
  <% sum = Transaction.where(item_id: item_id).sum(:amount) %>
  <tr>
    <td><%= item.category.name %></td>
    <td><%= item.name %></td>
    <td><%= item.description %></td>
    <td><%= sum %></td>
  </tr>
<% end %>
</table>

这是我现在的控制人员:

class ReportsController < ApplicationController

  def current
    @item_id_list = Transaction.uniq.pluck(:item_id)
  end

end

供参考,这是我的架构:

ActiveRecord::Schema.define(version: 20141029181100) do

  create_table "categories", force: true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "items", force: true do |t|
    t.integer  "category_id"
    t.string   "name"
    t.text     "description"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "items", ["category_id"], name: "index_items_on_category_id"

  create_table "transactions", force: true do |t|
    t.integer  "item_id"
    t.string   "code"
    t.date     "date"
    t.integer  "amount"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "transactions", ["item_id"], name: "index_transactions_on_item_id"

end

有人可以建议一种更优雅,更有效的方法来获取控制器的@items列表,其中包括来自相应交易的金额的计算总和,看起来像这样(总和使用总和确定)? / p>

#<ActiveRecord::Relation [
  #<Item id: 1, category_id: 1, name: "Stella 16oz", description: "Stella Tall boys", created_at: "2014-10-29 18:05:26", updated_at: "2014-10-29 18:05:26", total: 74>, 
  #<Item id: 2, category_id: 2, name: "Wine Bottle", description: "Red or White", created_at: "2014-10-29 19:59:30", updated_at: "2014-10-30 18:23:48", total: 12>
]> 

而不仅仅是这个:

#<ActiveRecord::Relation [
  #<Item id: 1, category_id: 1, name: "Stella 16oz", description: "Stella Tall boys", created_at: "2014-10-29 18:05:26", updated_at: "2014-10-29 18:05:26">, 
  #<Item id: 2, category_id: 2, name: "Wine Bottle", description: "Red or White", created_at: "2014-10-29 19:59:30", updated_at: "2014-10-30 18:23:48">
]> 

1 个答案:

答案 0 :(得分:2)

您可以将控制器代码更改为:

class ReportsController < ApplicationController

  def current
    @items = Item.select('id, name, description').includes(:category, :transactions).all
  end

end

然后在视图中:

<table>
  <tr>
    <th>Category</th>
    <th>Name</th>
    <th>Description</th>
    <th>Total</th>
  </tr>
  <% @items.each do |item| %>
    <tr>
      <td><%= item.category.name %></td>
      <td><%= item.name %></td>
      <td><%= item.description %></td>
      <td><%= item.transactions.map(&:amount).sum %></td>
    </tr>
  <% end %>
</table>

少数事情:

  1. 您可能不希望在查询时调用控制器中的.all,因为当数据增长时,您的页面加载时间会增加。
  2. 您可能希望通过在item.category.name模型类中设置delegate :name, :to => :category, :prefix => true来修复Item的{​​{1}}视图,以便在视图中您可以说:{ {1}}。
  3. 在视图中进行查询被认为是一种不好的做法。您应始终进行如下查询:控制器中的<%= item.category_name %>不在视图中。
  4. 另外,您可能希望在<% sum = Transaction.where(item_id: item_id).sum(:amount) %>模型类中使用transaction_amount这样的方法:

    Item

    因此,您可以执行以下操作:def transaction_amount transactions.map(&:amount).sum end

    然后最后你的观点将如下所示:

    <%= item.transaction_amount %>