简体   繁体   English

Rails 5,动作电缆和 current_user

[英]Rails 5, action cable and current_user

So I have this use case where I render a message in a controller (with ApplicationController.renderer) that is then broadcasted to a couple of users.所以我有这个用例,我在控制器(使用 ApplicationController.renderer)中呈现一条消息,然后将其广播给几个用户。 The broadcast also is performed in inside the same controller.广播也在同一个控制器内部执行。 Both these actions are triggered when an update to certain object is performed.当对某个对象执行更新时,这两个操作都会被触发。

The problem is, I need to access the current_user object inside that rendered view, and of course, I can not render it with the current user as a local variable because then the message will be sent with the user that broadcasted the message and not the end user that will see that view.问题是,我需要访问渲染视图中的 current_user 对象,当然,我不能将当前用户作为局部变量渲染它,因为这样消息将与广播消息的用户一起发送,而不是将看到该视图的最终用户。

So, after reading a couple of blog posts and the Rails docs I set the authentication with cookies to be supported by action cable.因此,在阅读了几篇博客文章和 Rails 文档后,我使用动作电缆支持的 cookie 设置了身份验证。

My question is: how can I access, inside the rendered view, the object (current_user) of the end user?我的问题是:如何在渲染视图中访问最终用户的对象 (current_user)?

Currently, my connection class looks like this.目前,我的连接类看起来像这样。 However, how can I render that view with this variable (logged_user)?但是,如何使用此变量 (logged_user) 呈现该视图?

module ApplicationCable
  class Connection < ActionCable::Connection::Base
   identified_by :logged_user

   def connect
     self.logged_user = User.find_by(id: cookies.signed[:user_id])
   end
 end
end

My controller looks like this:我的控制器看起来像这样:

(...)

 def update 
   if @poll.update(poll_params)
     broadcast_message(render_message(@poll), @poll.id, @poll.room.id)
     (...)
   end
 end

 def broadcast_message(poll = {}, poll_id, room_id)
   ActionCable.server.broadcast 'room_channel', body: poll, id: poll_id, room_id: room_id
 end

 def render_message(poll).
   if poll.show_at.to_time <= Time.now
     ApplicationController.renderer.render(
       partial: 'rooms/individual_student_view_poll',
       locals: {
         poll: poll,
         room: @room
       })
   end
 end

(....)

So basically, my ultimate goal is to access the logged_user object after the message is broadcasted to it.所以基本上,我的最终目标是在向其广播消息后访问 logging_user 对象。

Thanks谢谢

Something like this: 像这样:

ApplicationController.renderer.render(
  partial: 'rooms/individual_student_view_poll',
  locals: {
    poll: poll,
    room: @room
  },
  assigns: {
    logged_user: logged_user
  }
)

Will be available in your template like this: 将在您的模板中可用,如下所示:

<% if defined? @logged_user %>
...
<% end %>

I've had to solve the same problem.我不得不解决同样的问题。 What I wound up doing was creating a template renderer that inherits from ApplicationController that I could configure just for rendering templates with a current_user assigned before the render.我最后做的是创建一个模板渲染器,它继承自ApplicationController ,我可以配置它只用于渲染模板,在渲染之前分配一个current_user Here is what that looks like:这是它的样子:

class TemplateRenderer < ApplicationController
  def self.with_current_user(user)
    @current_user = user
    self
  end

  def self.current_user
    @current_user
  end

  def current_user
    self.class.current_user
  end
  helper_method :current_user
end

With this in place, you can simply call:有了这个,你可以简单地调用:

TemplateRenderer.with_current_user(logged_user).render(...)

Now calling current_user in your partial will access the helper method defined on TemplateRenderer , which in turn will refer to the class instance variable set by with_current_user .现在在你的局部调用current_user将访问在TemplateRenderer定义的辅助方法,它反过来将引用由with_current_user设置的类实例变量。

As you may have noticed, if you use the assigns option in the render call instead, you could access that variable by referring directly to the assigned instance var ( @current_user ), but not by calling the current_user helper, even if that helper was set to return the @current_user instance variable.正如你可能已经注意到,如果你使用的assigns在渲染电话方式,你可以通过直接引用该分配的实例VAR(访问变量@current_user ),而不是通过调用current_user帮手,即使该助手是集返回@current_user实例变量。 Having a special controller/renderer to override the current_user at the class level before calling render gets around this issue.在调用 render 解决这个问题之前,有一个特殊的控制器/渲染器来覆盖类级别的current_user

To make things easier, I had with_current_user return the class instance itself so that it could be easily chained with render .为了使事情更容易,我让with_current_user返回类实例本身,以便它可以轻松地与render链接。

I did wrestle with the naming and location of this class.我确实在考虑这个类的命名和位置。 TemplateRenderer describes its intended purpose, but it inherits from ApplicationController , which would suggest a name with a Controller suffix. TemplateRenderer描述了它的预期用途,但它继承自ApplicationController ,它会建议一个带有Controller后缀的名称。 I chose to locate this in my channels directory for now and leave off the suffix, since its only purpose (in my case) is to render templates for channels.我现在选择在我的channels目录中找到它并去掉后缀,因为它的唯一目的(在我的例子中)是为频道渲染模板。 But I can easily see arguments for putting it in the controllers directory with a Controller suffix.但是我可以很容易地看到将它放在带有Controller后缀的控制器目录中的参数。

EDIT: While the above answer will work, there is a subtle danger with it.编辑:虽然上述答案有效,但它有一个微妙的危险。 If you call were to call TemplateRenderer.render again after the first call, the current user would still be set, which could result in users seeing private content for another user.如果您在第一次调用后再次调用TemplateRenderer.render ,则仍会设置当前用户,这可能导致用户看到另一个用户的私有内容。 To solve this, you can do the following:要解决此问题,您可以执行以下操作:

class TemplateRenderer < ApplicationController
  def self.render_for_user(user, *args)
    @current_user = user
    res = render(*args)
    @current_user = nil
    res
  end

  def self.current_user
    @current_user
  end

  def current_user
    self.class.current_user
  end
  helper_method :current_user
end

Now, calling:现在,调用:

TemplateRenderer.render_for_user(logged_user, partial: "my_partial", **other_opts)

...will render with the specified user as current_user , but then set current_user to nil after the render. ...将使用指定的用户作为current_user渲染,但在渲染后将current_user设置为 nil。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM