Ruby on rails 在Rails中将逻辑从视图移动到模型

Ruby on rails 在Rails中将逻辑从视图移动到模型,ruby-on-rails,ruby,Ruby On Rails,Ruby,我试图更好地将逻辑排除在我的视图和模型之外。我正在构建一个Rails应用程序。它有一个Review模型和一个Album模型。这是相册/show.html.erb视图中的一些逻辑。我想将此移到查看模型,但我不确定如何操作 <% @reviews.each do |r| %> <div> <div class="review-rating" data-number="<%= r.rating %>"> </div>

我试图更好地将逻辑排除在我的视图和模型之外。我正在构建一个Rails应用程序。它有一个
Review
模型和一个
Album
模型。这是相册/show.html.erb视图中的一些逻辑。我想将此移到
查看
模型,但我不确定如何操作

<% @reviews.each do |r| %>
  <div>
    <div class="review-rating" data-number="<%= r.rating %>">
    </div>
    <p class="white"><%= r.comment %></p>
    <p class="grey"><i>posted <%= time_ago_in_words(r.created_at) %> ago</i></p> 
    <% if user_signed_in? %>
      <% if current_user.id == r.user_id %> 
        <%= link_to 'Edit', edit_album_review_path(@album, r.id), class: 'grey' %> |
        <%= link_to 'Delete', album_review_path(@album, r.id), method: :delete, data: {confirm: "Are you sure?"}, class: 'grey' %>
        <br /><br />
      <% end %> 
    <% else %> 
      <br />
    <% end %>
  </div>
<% end %>
review.rb
模型中使用此选项

def time_posted(r)
  "posted  #{time_ago_in_words(r.created_at)} ago"
end
但是Rails抛出了这个错误:

“未定义#的方法'time_posted'”


我们将不胜感激

在视图中保留视图逻辑没有错。在您的案例中,您正在迭代评论,并按照您希望向用户展示的方式对其进行格式化。想一想,如果你想改变你显示“posted”的方式,比如说,前的数字,哪里是修改它的合理位置?模型不要这样认为,模型保留并使用数据操作,视图表示数据,所以您的示例对我来说似乎很好。

在视图中保留视图逻辑没有什么错。在您的案例中,您正在迭代评论,并按照您希望向用户展示的方式对其进行格式化。想一想,如果你想改变你显示“posted”的方式,比如说,前的数字,哪里是修改它的合理位置?模型别这么认为,模型保留并使用数据进行操作,视图表示数据,因此您的示例对我来说似乎很好。

让我们暂时搁置讨论,看看我们如何挽救您的尝试:

class Review
  def time_posted
    "posted  #{ time_ago_in_words(self.created_at) } ago"
  end
end
我们已更改该方法,使其在
self
上工作-表示该方法所属的对象:

<p class="grey"><i><%= r.time_posted %></i></p> 


这使得它变得很好,并且可以进行封装,避免像助手那样将大量方法放入“全局”视图上下文命名空间中。但是,如果它值得的话,额外的复杂性取决于你


有几种宝石可以让演示者模式更容易使用,比如。

让我们先把讨论放在一边,看看我们如何挽救您的尝试:

class Review
  def time_posted
    "posted  #{ time_ago_in_words(self.created_at) } ago"
  end
end
我们已更改该方法,使其在
self
上工作-表示该方法所属的对象:

<p class="grey"><i><%= r.time_posted %></i></p> 


这使得它变得很好,并且可以进行封装,避免像助手那样将大量方法放入“全局”视图上下文命名空间中。但是,如果它值得的话,额外的复杂性取决于你


有几种宝石可以使演示者模式更易于使用,例如。

看看这个。在你对它过于渴望之前,请记住,像这样的显示问题实际上不应该在模型中表达出来。这些通常最好放在
helpers/
区域中。你在这里所做的是很难本地化的。看看这个。在你对这个过于急切之前,请记住,像这样的显示问题实际上不应该在模型中表达出来。这些通常最好放在
helpers/
区域中。您在这里所做的工作很难本地化。对,应该从视图中删除数据库和后台逻辑。模型就是这样的地方。控制器显示视图和数据库对象,并管理它们之间的交互。例如,如果用户希望对列重新排序(尽管排序可能是一个糟糕的示例…),则这可能发生在视图中,而不是模型中。也就是说,您不应该使用不同的
.order
重新查询数据库,只是为了在视图中以不同的方式显示它。对,应该从视图中删除数据库和后台逻辑。模型就是这样的地方。控制器显示视图和数据库对象,并管理它们之间的交互。例如,如果用户希望对列重新排序(尽管排序可能是一个糟糕的示例…),则这可能发生在视图中,而不是模型中。也就是说,您不应该使用不同的
.order
重新查询数据库,而只是为了在视图中以不同的方式显示它。
module ReviewHelper
  def time_posted(r)
    "posted  #{ time_ago_in_words(r.created_at) } ago"
  end
end

<p class="grey"><i><%= time_posted(r) %></i></p> 
class ReviewPresenter < SimpleDelegator
  def time_posted(r)
    "posted  #{ time_ago_in_words(r.created_at) } ago"
  end
end

class Review
  def present 
    @presenter ||= ReviewPresenter.new(self)
  end
end
<% @reviews.map(:present).each do |r| %>
  <p class="grey"><i><%= r.time_posted %></i></p> 
<% end %>