视图中出现N + 1错误

时间:2014-05-07 15:14:33

标签: mysql ruby ruby-on-rails-3 ruby-on-rails-4

我认为导致此N + 1错误的原因是,由于视图必须呈现集合,因此每个状态更新都需要进行查询调用,以便显示相对于其他状态更新的变量。

这会产生很多疑问。我怎样才能一次性提供所有这些状态更新,只需从状态更新类中调用数组进行这些计算,而不是每次都进入数据库?

我可能会遗漏一些东西,所以任何见解都会很棒!我尝试使用include更改我的查询调用,以及大约100个其他内容。

这是错误的子弹给我:

user: Pablo
N+1 Query detected
  StatusUpdate => [:client]
  Add to your finder: :include => [:client]
N+1 Query method call stack
 /Users/Nick/Code/Rails/gj/app/models/status_update.rb:27:in `prev'
 /Users/Nick/Code/Rails/gj/app/models/status_update.rb:36:in `weight_change'
 /Users/Nick/Code/Rails/gj/app/models/client.rb:11:in `weight_change'
 /Users/Nick/Code/Rails/gj/app/views/status_updates/show.html.erb:39:in    `_app_views_status_updates_show_html_erb__176120213182464780_70358939483460'

status_updates.rb

 def prev
   prev = self.client.status_updates.where("created_at < ?", self.created_at)[-1]
   if prev == nil
     prev = self
   else
    prev 
   end
 end        

 def weight_change
   weight_change = prev.total_weight - total_weight
   cut weight_change
 end 

client.rb

def weight_change(stat_present)
 if stat_present == false
   0
 elsif stat_present == true
   self.status_updates.reverse.first.weight_change
 end
end   

StatusUpdatesController#节目

  def show
    if status_updates?
      current_client.id).limit(7).reverse
      @status_updates = current_client.status_updates.limit(7).reverse
    end
    @status_update = current_client.status_updates.new
  end

show.html

  <% if @status_updates != nil %>
      <%= render(partial: "status_updates", collection: @status_updates) %>
  <% else %>
      <p style="text-align:center">No status updates yet.</p>
  <% end %>    

_status_updates.html

<tr>
    <td class="left"><%= status_updates.entry_date.strftime("%m/%d/%y") %></td>
    <td class="left phase"><%= status_updates.phase %> <a href="#">+</a></td>
    <td><%= status_updates.total_weight %></td>
    <td><%= status_updates.weight_change %></td>
    <td><%= status_updates.lbm_weight %></td>
    <td><%= status_updates.lbm_change %></td>
    <td><%= status_updates.total_lbm_change %></td>
    <td><%= BigDecimal(status_updates.body_fat_pct * 100, 5)%>%</td>
    <td><%= status_updates.fat_change %></td>
    <td><%= status_updates.total_fat_change %></td>
    <td><%= link_to('&times;'.html_safe, status_updates, method: :delete) %></td>
</tr>

client.rb

class Client < ActiveRecord::Base
   belongs_to :trainer
   has_many :status_updates

   validates :firstname, :lastname, presence: true

   def weight_change(stat_present)
     if stat_present == false
       0
     elsif stat_present == true
       self.status_updates.reverse.first.weight_change
     end
   end

   def fat_change(stat_present)
     if stat_present == false
       0
     elsif stat_present == true
       self.status_updates.reverse.first.fat_change
     end
   end

   def lbm_change(stat_present)
     if stat_present == false
       0
     elsif stat_present == true
       self.status_updates.reverse.first.lbm_change
     end
   end

   def bfp_change(stat_present)
     if stat_present == false
       0
     elsif stat_present == true
       self.status_updates.reverse.first.bfp_change
     end
   end

   def total_weight_change(stat_present)
     if stat_present == false
       0
     elsif stat_present == true
       self.status_updates.reverse.first.total_weight_change
     end
   end

end

1 个答案:

答案 0 :(得分:1)

我建议您每次读取 weight_change时不要计算status_update,而是在 {{1}时计算它在它自己的列(status_update)。

通过这种方式阅读记录是直截了当的,并且不需要循环回旧记录。