Rails,在视图中查找对象是否可以?

时间:2011-09-27 21:28:36

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

控制器指向视图。在该视图中,找到对象<% @XXX = XXXX.where(..... %>还是那么糟糕?

尝试解决性能问题,这就是我要问的原因。感谢

1 个答案:

答案 0 :(得分:3)

在模型中放置查询逻辑更多地与可维护性有关,然后与性能有关。由于大多数ActiveRecord / ARel逻辑处理的轻量级关系对象只触发基于某些方法的实际查询,通常是通过Enumerable(每个/ map / inject / all / first)提供的,通常从视图中调用,实际查询在视图中触发,而不是在其他任何地方触发。

以下是我正在处理atm的应用程序中limit(3)和first(3)之间差异的示例。

ruby-1.9.2-p180 :018 > PressRelease.limit(3).is_a? ActiveRecord::Relation
 => true 
ruby-1.9.2-p180 :019 > PressRelease.first(3).is_a? ActiveRecord::Relation
  PressRelease Load (2.8ms)  SELECT "press_releases".* FROM "press_releases" ORDER BY published_at DESC
 => false

正如您所看到的,限制实际上并不会触发查询,首先是。

在性能方面,您通常会尝试确保在控制器/模型中不执行查询,以便将它们包装在视图中的缓存块中,从而消除大多数请求中的查询。在这种情况下,您确实希望通过调用任何Enumerable方法确保您不在控制器中执行查询。

一个博客的简短示例,其中列出了主页上使用缓存设置的最后10篇博文可能如下所示。

# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def index
    # Something like this would trigger the query at this point and should be
    # avoided in the controller
    # @posts = Post.first(10)
    # So @posts here will be the Relation returned from the last_ten scope, not
    # an array
    @posts = Post.last_ten
  end
  ...
end

# app/models/post.rb
class Post < ActiveRecord::Base
  # Will return an ActiveRecord::Relation
  scope :last_ten, order('created_at DESC').limit(10)
end

# app/views/posts/index.html.erb
<ul>
  # The query will actually trigger within the cache block on the call to each,
  # preventing the query from running each time and also reducing the template
  # rendering within the cache block.
  <%= cache(posts_cache_key) do %>
    <% @posts.each do |post| %>
      ..
    <% end %>
  <% end %>
</ul>

为清楚起见,所有这些都与做

完全相同
# app/views/posts/index.html.erb
<ul>
  <%= cache(posts_cache_key) do %>
    <% Post.order('created_at DESC').limit(10).each do |post| %>
      ...
    <% end %>
  <% end %>
</ul>

除非您现在想要修改它如何提取查询的逻辑,否则您希望添加类似where(:visible => true).where('published_at' <= Time.now)的内容,跳转到您的视图中,而不是在逻辑应该在模型中进行更改。性能方面,差异是微不足道的,维护方面,后者很快变成了一个小问题。