Rails 应用未通过 ActionCable 显示通知

Rails app not showing notifications through ActionCable

我有一个 todo-list rails 应用程序,允许一个用户将其他用户 public 列表标记为他们的最爱。这里的目标是:当列表的所有者创建一个新的 todo-item 时,将同一个列表标记为他们最喜欢的用户应该在不刷新页面的情况下实时收到通知。

app/assets/javascripts/channels/notification.js

App.notifications = App.cable.subscriptions.create("NotificationsChannel", {
      connected: function() {
        // Called when the subscription is ready for use on the server
      },

      disconnected: function() {
        // Called when the subscription has been terminated by the server
      },

      received: function(data) {
        // Called when there's incoming data on the websocket for this channel
        $("#notifications").prepend(data.html);
      }

});

我的 div 在 app/views/layouts/application.html.erb

      <body>
          <div class="container">
          <div id="notifications">

          </div>
          <header>
            <div class="header_inner">
              <nav style="text-align: right;">
                <% if user_signed_in? %>
                  <%= link_to 'New Todo List', new_todo_list_path %> |
                  <%= link_to "Sign out", destroy_user_session_path, method: :delete %>
                <% else %>
                  <%= link_to "Log in", new_user_session_path %>
                <% end %>
              </nav>
            </div>
          </header>
          <%= yield %>
        </div>
      </body>

app/models/notification.rb

class Notification < ApplicationRecord
  after_create_commit { NotificationRelayJob.perform_later(self) }

  belongs_to :user
  belongs_to :recipient, class_name: "User"
  belongs_to :notifiable, polymorphic: true
end

app/models/todo_list.rb

class TodoList < ApplicationRecord
  belongs_to :user
  has_many :todo_items, dependent: :destroy

  has_many :favorites
  has_many :users, through: :favorites

  validates :title, presence: true
  validates :description, length: { maximum: 50 }

  def public?
    self.public
  end
end

app/views/notifications/todo_lists/_created.html.erb

<div><%= notification.user.email %> <%= notification.action %> new item!</div>

app/channels/notifications_channel.rb

class NotificationsChannel < ApplicationCable::Channel
  def subscribed
    stream_from "notifications:#{current_user.id}"
  end

  def unsubscribed
    stop_all_streams
  end
end

app/jobs/notification_relay_job.rb

  class NotificationRelayJob < ApplicationJob
  queue_as :default

  def perform(notification)
    html = ApplicationController.render partial: "notifications/#{notification.notifiable_type.underscore.pluralize}/#{notification.action}", locals: {notification: notification}, formats: [:html]
    ActionCable.server.broadcast "notifications:#{notification.current_user}", html: html
  end

app/controllers/todo_items_controller.rb

class TodoItemsController < ApplicationController
  before_action :set_todo_list
  before_action :set_todo_item, except: [:create]

  def create
    @todo_item = @todo_list.todo_items.new(todo_item_params)
    if @todo_item.save
      @todo_list.users.each do |user|
        @noti = Notification.create(recipient: user, user: User.last, action: "create", notifiable: @todo_list)
      end
      redirect_to @todo_list, notice: 'Todo item added!'
    else
      redirect_to @todo_list, alert: 'Please some content in the new todo item'
    end
  end
  ...

development.log

web_1  | Finished "/cable/" [WebSocket] for 172.23.0.1 at 2018-04-17 00:58:28 +0000
web_1  | NotificationsChannel stopped streaming from notifications:2
web_1  | Started GET "/cable" for 172.23.0.1 at 2018-04-17 00:58:28 +0000
web_1  | Cannot render console from 172.23.0.1! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
web_1  | Started GET "/cable/" [WebSocket] for 172.23.0.1 at 2018-04-17 00:58:28 +0000
web_1  | Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
web_1  |   User Load (0.5ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ?  [["id", 2], ["LIMIT", 1]]
web_1  | Registered connection (Z2lkOi8vZmFudGFzdGljLXN5c3RlbS9Vc2VyLzI)
web_1  | NotificationsChannel is transmitting the subscription confirmation
web_1  | NotificationsChannel is streaming from notifications:2
web_1  | Started POST "/todo_lists/3/todo_items" for 172.23.0.1 at 2018-04-17 00:58:31 +0000
web_1  | Cannot render console from 172.23.0.1! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
web_1  | Processing by TodoItemsController#create as HTML
web_1  |   Parameters: {"utf8"=>"✓", "authenticity_token"=>"WfKWJNbd0HiPj64/51vXsj7O/mJ7nF/U6tvwP5OQMsTLE0cgUQHXYq7D08bB3RUxuxqVTvcD6uGzWcNJqkxGQA==", "todo_item"=>{"content"=>"asd"}, "commit"=>"Create Todo item", "todo_list_id"=>"3"}
web_1  |   TodoList Load (0.3ms)  SELECT  "todo_lists".* FROM "todo_lists" WHERE "todo_lists"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
web_1  |    (0.1ms)  begin transaction
web_1  |   SQL (2.2ms)  INSERT INTO "todo_items" ("content", "todo_list_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["content", "asd"], ["todo_list_id", 3], ["created_at", "2018-04-17 00:58:31.708390"], ["updated_at", "2018-04-17 00:58:31.708390"]]
web_1  |    (157.7ms)  commit transaction
web_1  |   User Load (0.4ms)  SELECT "users".* FROM "users" INNER JOIN "favorites" ON "users"."id" = "favorites"."user_id" WHERE "favorites"."todo_list_id" = ?  [["todo_list_id", 3]]
web_1  |   User Load (0.3ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT ?  [["LIMIT", 1]]
web_1  |    (0.1ms)  begin transaction
web_1  |   SQL (1.5ms)  INSERT INTO "notifications" ("user_id", "recipient_id", "action", "notifiable_type", "notifiable_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?)  [["user_id", 3], ["recipient_id", 1], ["action", "followed"], ["notifiable_type", "TodoList"], ["notifiable_id", 3], ["created_at", "2018-04-17 00:58:31.915523"], ["updated_at", "2018-04-17 00:58:31.915523"]]
web_1  |    (97.2ms)  commit transaction
web_1  | [ActiveJob] Enqueued NotificationRelayJob (Job ID: a32e8a9d-d9fd-4a1c-90c1-891c48709b4b) to Async(default) with arguments: #<GlobalID:0x00007f651054f610 @uri=#<URI::GID gid://fantastic-system/Notification/72>>
web_1  | Redirected to http://localhost:3000/todo_lists/3
web_1  |   Notification Load (0.6ms)  SELECT  "notifications".* FROM "notifications" WHERE "notifications"."id" = ? LIMIT ?  [["id", 72], ["LIMIT", 1]]
web_1  | Completed 302 Found in 359ms (ActiveRecord: 261.1ms)
web_1  | 
web_1  | 
web_1  | [ActiveJob] [NotificationRelayJob] [a32e8a9d-d9fd-4a1c-90c1-891c48709b4b] Performing NotificationRelayJob (Job ID: a32e8a9d-d9fd-4a1c-90c1-891c48709b4b) from Async(default) with arguments: #<GlobalID:0x00007f64cc04ab18 @uri=#<URI::GID gid://fantastic-system/Notification/72>>
web_1  | [ActiveJob] [NotificationRelayJob] [a32e8a9d-d9fd-4a1c-90c1-891c48709b4b]   User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
web_1  | [ActiveJob] [NotificationRelayJob] [a32e8a9d-d9fd-4a1c-90c1-891c48709b4b]   Rendered notifications/todo_lists/_followed.html.erb (4.9ms)
web_1  | [ActiveJob] [NotificationRelayJob] [a32e8a9d-d9fd-4a1c-90c1-891c48709b4b] [ActionCable] Broadcasting to notifications:3: {:html=>"<div>a@a.com.br followed you!</div>\n"}
web_1  | [ActiveJob] [NotificationRelayJob] [a32e8a9d-d9fd-4a1c-90c1-891c48709b4b] Performed NotificationRelayJob (Job ID: a32e8a9d-d9fd-4a1c-90c1-891c48709b4b) from Async(default) in 7.58ms
web_1  | Started GET "/todo_lists/3" for 172.23.0.1 at 2018-04-17 00:58:32 +0000
web_1  | Cannot render console from 172.23.0.1! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
web_1  | Processing by TodoListsController#show as HTML
web_1  |   Parameters: {"id"=>"3"}
web_1  |   TodoList Load (0.2ms)  SELECT  "todo_lists".* FROM "todo_lists" WHERE "todo_lists"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
web_1  |   Rendering todo_lists/show.html.erb within layouts/application
web_1  |   TodoItem Load (0.2ms)  SELECT "todo_items".* FROM "todo_items" WHERE "todo_items"."todo_list_id" = ?  [["todo_list_id", 3]]
web_1  |   User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
web_1  |   User Load (0.5ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ?  [["id", 2], ["LIMIT", 1]]
web_1  |   Rendered collection of todo_items/_todo_item.html.erb [4 times] (7.3ms)
web_1  |   Rendered todo_items/_form.html.erb (2.8ms)
web_1  |   Rendered todo_lists/show.html.erb within layouts/application (16.8ms)
web_1  | Completed 200 OK in 47ms (Views: 44.4ms | ActiveRecord: 1.1ms)
web_1  | 
web_1  | 
web_1  | Finished "/cable/" [WebSocket] for 172.23.0.1 at 2018-04-17 00:58:32 +0000
web_1  | NotificationsChannel stopped streaming from notifications:2
web_1  | Started GET "/cable" for 172.23.0.1 at 2018-04-17 00:58:32 +0000
web_1  | Cannot render console from 172.23.0.1! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
web_1  | Started GET "/cable/" [WebSocket] for 172.23.0.1 at 2018-04-17 00:58:32 +0000
web_1  | Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
web_1  |   User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ?  [["id", 2], ["LIMIT", 1]]
web_1  | Registered connection (Z2lkOi8vZmFudGFzdGljLXN5c3RlbS9Vc2VyLzI)
web_1  | NotificationsChannel is transmitting the subscription confirmation
web_1  | NotificationsChannel is streaming from notifications:2

我可以通过“@todo_list.users”看到所有收藏列表的用户(这将收到通知),控制台显示 NotificationChannel 正在传输和流式传输,但是当我创建时没有任何反应一个新的待办事项。我已经搜索了一段时间,但发现我不太了解 ActionCable :(.

非常感谢任何帮助。

最初,问题是您向谁发送通知。您指定了 notifications.current_user,它必须发送到 notification.recipient_id

app/jobs/notification_relay_job.rb

更改代码

ActionCable.server.broadcast "notifications:#{notification.current_user}", html: html

ActionCable.server.broadcast "notifications:#{notification.recipient_id}", html: html

执行此操作后,登录发件人和收件人用户,创建通知并再次测试。