Rails:将逻辑移出视图

时间:2015-12-18 21:39:02

标签: ruby-on-rails views messaging

总之,我的视图中有一些if / else逻辑,我认为它作为控制器方法或帮助器会更有效。也就是说,我不确定将其转化为方法的最佳方式是或者最好的方法。

我正在为我的Rails应用构建一个用户消息系统。在我的应用程序中,配置文件有许多对话(在两个配置文件之间),其中有许多消息。我正在尝试构建会话索引,它基本上就像收件箱一样。作为Rails初学者,我不太清楚将if / else部分移出视图的最有效/最佳方法是因为它在.each循环中运行。现在我的观点看起来像这样:

<% @conversations.each do |conversation| %>
<% if conversation.sender_id == current_user.profile.id %>
  <% recipient = Profile.find(conversation.recipient_id) %>
<% else %>
  <% recipient = Profile.find(conversation.sender_id) %>
<% end %>
<%= link_to recipient.first_name, conversation_messages_path(conversation)%>
  

供参考我的对话控制器索引操作:

def index
  @profiles = Profile.all
  @conversations = Conversation.involved(current_user.profile.id)
end

我的谈话模型

class Conversation < ActiveRecord::Base
  belongs_to :sender, :foreign_key => :sender_id, class_name: 'Profile'
  belongs_to :recipient, :foreign_key => :recipient_id, class_name: 'Profile'
  has_many :messages, dependent: :destroy
  accepts_nested_attributes_for :messages

  validates_uniqueness_of :sender_id, :scope => :recipient_id

  scope :between, -> (sender_id,recipient_id) do
   where("(conversations.sender_id = ? AND conversations.recipient_id =?) OR (conversations.sender_id = ? AND conversations.recipient_id =?)", sender_id,recipient_id, recipient_id, sender_id)
  end

  scope :involved, -> (user) do
   where("(conversations.sender_id = ? OR conversations.recipient_id =?)", user, user)
  end
end

这是我的第一个stackoverflow问题,所以如果我没有关注此问题的任何最佳做法,请告诉我们!

3 个答案:

答案 0 :(得分:1)

欢迎使用StackOverflow!

在这种情况下,您只是根据是否conversation.sender == current_user打印个人资料的名称。在Conversation模型上,您可以使用:display_name方法接收用户。

def display_name(profile)
  (sender == profile ? recipient : sender).name
end

这是表示方法,所以它可能更适合Helper,Presenter,Decorator或许多其他解决方案,但这应该可以解决问题。在您的观看中,请致电:link_to conversation.display_name(current_user.profile), ...

答案 1 :(得分:1)

就个人而言,我会说你的if / else逻辑适合于一个视图;它是每个块中最好避免的查询。你基本上有什么称为n + 1查询(你在@conversations中有n个对象,你在数据库中查询每个对象的Profile对象,并且你的原始查询填充@conversations,因此n +1)。

在控制器中,您可以像这样加载发件人和收件人:

scope :involved_with_profiles -> (user) do
  includes(:sender, :recipient).where(...same logic as your :involved scope...)
end

使用此范围代替:involved加载@conversations。然后你可以在视图中保留你的if / else逻辑,但不是查询一个Profile,你可以这样做:

<% recipient = conversation.recipient %>

<% recipient = conversation.sender %>

因为这些已经从单个查询加载到@conversations。

答案 2 :(得分:0)

它很好。

将它放在帮手中除了可以在其他地方重复使用外,不会给你任何东西。