我首先要说的是,我知道你应该不在模型调用中访问当前用户。但我刚刚遇到了一个需要代码的情况。这就是我发布这个问题的原因 - 我需要知道如何做到这一点的最佳实践。
我的Nodes.rb中有一个方法,需要访问current_user
才能生成正确的结果:
Node.rb
def tagged_users
tag_list = self.user_tag_list
email_tags = tag_list.select { |x| x.match("@") }
id_tags = tag_list.select { |x| x.match(/^[^@]*$/) }
users = User.where(email: email_tags, invitation_token: nil).where(id: current_user.memberships.pluck(:user_id).compact)
members_email = Member.where(email: email_tags).where(id: current_user.memberships.pluck(:member_id).compact)
members_id = Member.find_by_full_name(id_tags, current_user)
users + members_email + members_id
end
我必须在一些部分和集合上访问此实例方法,如下所示:
_user_tag_list.html.erb
<% node.tagged_users.each do |tag| %>
<div class="card-back__tagged-user">
<div class="tagged-user__avatar">
<img src="<%= avatar_url(tag) %>" alt="" class="tagged-user__photo">
</div>
<div class="tagged-user__title">
<h4 class="tagged-user__title-text"><%= tag.first_name %> <%= tag.last_name %></h4>
</div>
<%= link_to node_path(node, remove_tag: tag.first_name + ' ' + tag.last_name), class:'tagged-user__action', remote: true, method: :patch do %>
<i class="icon-close"></i>
<% end %>
</div>
<% end %>
从另一个部分
调用_node.html.erb
<div class="tagged_users">
<%= render partial: "nodes/user_tag_list", locals: {node: node} %>
</div>
在其他一些集合和js.erb中也会调用 tagged_users
。我是否将其移至控制器,是否修改了模型中的方法等?您的答案表示赞赏。谢谢!
答案 0 :(得分:2)
如果是我,我会将该方法转移到它自己的服务中,我倾向于放置像这些模型这样的方法,因为我倾向于Single-Responsibility原则。
class TaggedUsers
def self.call(node, current_user)
tag_list = node.user_tag_list
email_tags = tag_list.select { |x| x.match("@") }
id_tags = tag_list.select { |x| x.match(/^[^@]*$/) }
users = User.where(email: email_tags, invitation_token: nil).where(id: current_user.memberships.pluck(:user_id).compact)
members_email = Member.where(email: email_tags).where(id: current_user.memberships.pluck(:member_id).compact)
members_id = Member.find_by_full_name(id_tags, current_user)
users + members_email + members_id
end
end
然后,在我的控制器中,我可以做这样简单的事情:
# NodesController (well, my guess at it :)).
def show
@node = Node.find(params[:id])
@tagged_users = TaggedUsers.call(@node, current_user)
# blah blah blah ... other code
end
在视图中,它将像“简单”一样:
= render partial: 'nodes/user_tag_list', locals: ( node: @node, tagged_users: @tagged_users }
或类似的东西......希望这会有所帮助!
答案 1 :(得分:2)
这很简单。传递current_user
作为参数。
def tagged_users(current_user)
# ...
end
并在视图中使用它。
<% node.tagged_users(current_user)...
或者,您可以在attr_accessor
中设置Node
。但我会传递用户。
class Node
attr_accessor :current_user
end
然后,只要你立刻就是一个节点:
@node.current_user = current_user
答案 2 :(得分:0)
理想情况下,您将行为移动到另一个对象,例如服务或命令对象。我认为craig.kaminsky的解决方案是一个非常好的开始。
但是,如果你真的想要在Node模型上保持这种行为,你也可以重新定义Node#tagged_users
以接受current_user
参数:Node#tagged_users(current_user)
。然后在您看来,您可以:
<% node.tagged_users(current_user).each do |tag| %>
这样就可以了。