如何在 Rails 视图中呈现所有评论?

Posted

技术标签:

【中文标题】如何在 Rails 视图中呈现所有评论?【英文标题】:How do I render all Comments in a Rails view? 【发布时间】:2010-12-19 08:59:10 【问题描述】:

我是 Rails 新手,所以请轻松一点。我创建了一个博客。我已经成功实现了 cmets 并将它们附加到每个帖子中。现在...我想在侧边栏中显示所有帖子中最新的 cmets 列表。我认为这里涉及两件事,对 comment_controller.rb 的更新,然后是来自实际页面的调用。这是 cmets 控制器代码。

class CommentsController < ApplicationController

  def create
    @post = Post.find(params[:post_id])
    @comment = @post.comments.create!(params[:comment])

    respond_to do |format|
      format.html  redirect_to @post
      format.js
    end
  end
end

【问题讨论】:

【参考方案1】:

如果您想以最近的顺序显示任何帖子中的所有 cmets,您可以这样做:

@comments = Comment.find(:all, :order => 'created_at DESC', :limit => 10)

在视图中你可以这样做:

<% @comments.each do |comment| -%>
    <p>
        <%= comment.text %> on the post <%= comment.post.title %>
    </p>
<% end -%>

【讨论】:

这看起来像我要找的。刚试了一下,还是不行。我怀疑这是因为我错误地引用了它。第二部分(视图)被放入帖子的布局文件夹中......这是否会将@cmets 更改为 cmets,反之亦然? 如果你把它放在布局中,那么你可能只想像这样将 find 语句内联到布局中: 'created_at DESC' , :limit => 10).each 做 |comment| -%> 我不确定这将如何在评论中格式化,但希望这是有道理的。一般来说,将逻辑放在视图中是不受欢迎的,但我认为您可以访问每个页面上的 @cmets 变量的唯一另一种方法是,如果您在 ApplicationController 中的每个方法之前放置一个运行挂钩。【参考方案2】:

我发布了一个单独的答案,因为代码在 cmets 中的格式显然完全不正确。

我猜你在上一个答案中遇到的问题是你在放

@comments = Comment.find(:all, :order => 'created_at DESC', :limit => 10)

在您的控制器方法之一中。但是,您希望 @cmets 可用于布局文件,因此您必须将其放在每个控制器的每个控制器方法上才能使其工作。尽管不赞成将逻辑放入视图中,但我认为在布局文件中执行以下操作是可以接受的:

<% Comment.find(:all, :order => 'created_at DESC', :limit => 10).each do |comment| -%>
    <p>
        <%= comment.text %> on the post <%= comment.post.title %>
    </p>
<% end -%>

虽然我们可以将其移到 Comment 模型中,但要从视图中获取一些逻辑

class Comment < ActiveRecord::Base
  named_scope :recent, :order => ["created_at DESC"], :limit => 10

现在您可以在视图中执行此操作:

<% Comment.recent.each do |comment| -%>
    <p>
        <%= comment.text %> on the post <%= comment.post.title %>
    </p>
<% end -%>

这是一个不错的fat model and skinny controller

【讨论】:

我喜欢命名范围,尽管视图代码非常干净,但它完全绕过了控制器。我想我的第一枪是在 App Controller 的 before_filter 中调用 Comment.recent,但我可能错了。 +1 表示命名范围,但安迪是对的。这属于应用程序控制器中的前置过滤器。它仍然有效,但视图不应直接处理模型。 我看到了关于 before 过滤器的观点,但我认为这次我实际上更喜欢视图中的逻辑。在我看来,它比 Application 控制器中的之前的过滤器更干净,更能揭示意图,在这种情况下,您可能会在阅读代码后想知道 @cmets 变量的来源而挠头。至少如果您要将过滤器放在应用程序控制器中,您应该选择一个非常独特的变量名称,以免污染命名空间。所以@recent_cmets_for_layout 而不是@cmets。 我不同意这种方法,将逻辑排除在视图之外。 ApplicationController 中应该有一个before_filter,或者把一个方法做成一个helper,可以在所有视图中访问。 我不喜欢在 Application 控制器中将其用作前置过滤器的另一个原因是,即使您没有为此显示 cmets,您也会访问数据库以获取每个控制器方法的 cmets方法(例如更新,或者如果您获取的是 xml 而不是 html)。除非您要在多个地方使用它,否则辅助方法似乎是不必要的,而且在我看来,它实际上只会在一个布局视图中使用。【参考方案3】:

我倾向于为此使用助手:

# in app/helpers/application_helper.rb:
def sidebar_comments(force_refresh = false)
  @sidebar_comments = nil if force_refresh
  @sidebar_comments ||= Comment.find(:all, :order => 'created_at DESC', :limit => 10)
  # or ||= Comment.recent.limited(10) if you are using nifty named scopes
end

# in app/views/layouts/application.html.erb:
<div id='sidebar'>
  <ul id='recent_comments'>
    <% sidebar_comments.each do |c| %>
      <li class='comment'>
        <blockquote cite="<%= comment_path(c) -%>"><%= c.text -%></blockquote>
      </li>
    <% end %>
  </ul>
</div>

【讨论】:

以上是关于如何在 Rails 视图中呈现所有评论?的主要内容,如果未能解决你的问题,请参考以下文章

在视图中呈现现有类别,rails

我应该如何在 Rails 中组织复杂的 SQL 视图?

如何在 Rails 视图中使用 AJAX

rails如何选择要呈现的实例变量版本?

Rails 3在另一个控制器中呈现部分形式

如何改进 Ruby on Rails 视图中的代码