Rails惯例 - 将视图与控制器和部分

时间:2016-04-05 03:06:22

标签: ruby-on-rails ruby-on-rails-4 model-view-controller

如果当前用户发送消息,则显示绿色,否则显示蓝色。遵循Rails约定,该逻辑属于哪个?

概论

用户将访问/group/:id以查看消息列表,因此相应的视图为 views / groups / show.html.erb ,相应的控制器为 controllers / groups_controller.rb

我们要显示的消息位于 @group 的数组中,如 @ group.messages 。数组按时间戳排序。

设置邮件颜色样式的代码并不重要,但为简单起见,我们会说有两个类选择器(一个用于来自,一个用于 )我们可以简单地将一个类属性添加到消息所在的div中以改变其颜色。

用户发送和接收的消息都保存在数组 @ group.messages 中。
如果我们在消息中存储了单个消息,我们可以测试它是否是由当前用户发送的:

if session[:user_id] == message.user_id

问题

消息按时间戳排序,需要按顺序显示。出于这个原因,我看不到任何干净的方法来处理控制器中的逻辑。

我希望尽可能多地保留视图中的逻辑,尤其是偏离部分,但在考虑了呈现已发送已接收消息的选项之后不同的方式,我发现最干净的选择是将逻辑放在消息中。

处理消息partial:

中的逻辑
<% if message.user.id == session[:user_id] %>
  <div class="to">
    <p> <%= message.body %> </p>
  </div>
<% else %>
  <div class="from">
    <p> <%= message.body %> </p>
  </div>
<% end %>    

优点:

  • 此方法使用一个干净且简单的if语句处理逻辑

  • 它允许我们将代码设置为DRY,因为如果我们想在其他页面上使用逻辑,我们就不必在其他地方使用逻辑

  • 由于每封邮件只有一个正文,因此我们不必另外部分展示没有此格式的邮件

缺点:

  • 逻辑是局部的!我认为与我合作的人或其他程序员甚至是我自己都会先在控制器然后中查看然后中的部分进行任何更改或查看代码

  • 这不像正常的Rails惯例感觉

处理视图中的逻辑:

可能是两个干净的解决方案 -
1)在逻辑 中设置消息样式 2)为发送/接收的消息呈现不同的部分

在逻辑中设置样式:

<% @group.messages.each do |message| %>
  <% if message.user.id == session[:user_id] %>
    <div class="to">
      <p> message.body </p>
    </div>
  <% else %>
    <div class="from">
      <p> message.body </p>
    </div>
  <% end %>
<% end %>   

渲染不同的部分:

<% @group.messages.each do |message| %>
  <% if message.user.id == session[:user_id] %>
    <%= render :partial => '/messages/sent_message', :message => message %>
  <% else %>
    <%= render :partial => '/messages/received_message', :message => message %>
  <% end %>
<% end %>  

优点:

  • 任何一个视图解决方案都会将逻辑排除在部分

  • 之外
  • 在视图中决定以某种颜色显示某种颜色是有意义的

  • 使用两个部分的视图解决方案是干净的,允许我们避免在逻辑中设置样式,这也意味着我们可以改变局部内的样式并影响到处的消息外观。

缺点:

  • 两个视图选项都意味着我们的代码不再是DRY。使用这些方法意味着如果我们想要在其他3个页面上使用相同的功能,我们将需要再次编写相同的代码3次

  • 视图不应该决定任何事情

  • 使用两个局部视图的视图解决方案意味着我们将使用partials来包含views / messages文件夹,并且仍然没有用于呈现消息的默认部分

  • 我认为这两种观点解决方案都让人感觉很脏

关于我的解决方案的主要观点 -

  • 没有选项允许在控制器中保存逻辑

  • 将逻辑放在视图中意味着要在多个页面上提供相同的功能,相同的代码将被写入多个位置

  • 看起来最干净且对我来说最有意义的选项意味着将逻辑置于局部,而必须是更好的方式..对吗?

  • 所有解决方案似乎都不遵循Rails惯例

我编码最佳的三个选项中的哪一个遵循Rails约定?

是否可以将逻辑放在控制器中?

有没有更好的方法来设计它,以便在Rails约定之后有一个明确的解决方案?

2 个答案:

答案 0 :(得分:2)

您可能已经意识到,您描述的三个版本中的每一个都不是干的或不可扩展的。你在分析每个选项的优缺点方面做得很好,所以我很少添加。 :)

要向模型添加演示功能,Rails社区使用演示者。有一篇关于演示者here的文章很好地解释了它们。

基本上,您希望有一个部分消息:

<div class=<%=@presenter.css_class%>>
  <p> <%= message.body %> </p>
</div>

然后主持人:

class MessagesPresenter
  def initialize(message, current_user)
    @message = message
    @current_user = current_user
  end

  def css_class
    message.user == current_user ? 'to' : 'from'
  end

  private

  attr_reader :message, :current_user
end

和控制器:

@presenter = MessagesPresenter.new(@message, current_user)

瞧!演示者可以在视图和部分视图中使用,是存放所有演示逻辑的好地方。

答案 1 :(得分:1)

由于CSS类中这些示例的唯一区别,你重复自己很多。您是否无法在代码上添加或删除某个类,具体取决于代码是否属于<div id="colorDiskWrapper"> <div id="colorDisk"></div> <div id="colorDiskCursor"></div> </div> <script src="https://rawgit.com/PitPik/colorPicker/master/colors.js"></script>

这实际上是一个演示问题,您可以使用装饰器(http://johnotander.com/rails/2014/03/07/decorators-on-rails/)处理这个简单的逻辑来显示正确的CSS标记。我建议使用Draper(https://github.com/drapergem/draper)。

首先,为简单起见,向current_user添加current_user辅助方法以返回经过身份验证的用户。

添加装饰器:

MessageDecorator.rb

application_controller.rb

现在你的观点可以有更清晰的逻辑

视图

消息部分:

def recipient_class
  user_id == current_user.id ? "to" : "from"  # (user_id delegates to message object)
end
主视图中的

集合部分:

<div class="<%= message.recipient_class %>">
  <p><%= message.body %></p>
</div>

最后,在控制器操作中的消息上调用<%= render partial: "message", collection: @messages, as: :message %>

decorate

修改

您也可以使用简单的辅助方法而不是装饰器:

@messages = @group.messages.decorate