【问题标题】:Ruby Action Cable for nested form用于嵌套形式的 Ruby 动作电缆
【发布时间】:2021-06-05 15:56:16
【问题描述】:

我有两个模型:post 和 comment,第二个嵌套在第一个中。我想为 cmets 创建一个动作电缆。这是我为帖子制作的方法:它工作得非常好——在控制台中显示帖子的标题和内容。路线:

   resources :posts do
    resources :comments 
  end
  root "posts#index"
  mount ActionCable.server => '/cable'

帖子控制器:

 class PostsController < ApplicationController
before_action :find_post, only: [:show, :update, :edit, :destroy]
after_action :publish_post, only: [:create]
  def publish_post
    ActionCable.server.broadcast "posts_channel", {title: @post.title, content: @post.content}
  end
private
  def find_post
    @post = Post.find(params[:id])
  end
end

posts_channel.rb 的代码:

class PostsChannel < ApplicationCable::Channel
  def subscribed
    stream_from "posts_channel"
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end
end

posts_channel.js 的代码:

import consumer from "./consumer"

consumer.subscriptions.create("PostsChannel", {
  connected() {
    console.log('i am post')
    // Called when the subscription is ready for use on the server
  },

  disconnected() {
    // Called when the subscription has been terminated by the server
  },
  received(data) {
    console.log(data)
    // Called when there's incoming data on the websocket for this channel
  }
});

我的 cmets 代码非常相似,这里是 cmets 控制器:

class CommentsController < ApplicationController
before_action :find_comment, only: [:destroy]
after_action :publish_comment, only: [:create]
  def create
    @post = Post.find(params[:post_id])
    @comment = @post.comments.create(params[:comment].permit(:name, :comment, :user_id, :best, :file))
    redirect_to post_path(@post)
  end
  def publish_comment
    ActionCable.server.broadcast "comments_channel", {title: @comment.name, content: @comment.comment}
  end

  private

  def find_comment
    @post = Post.find(params[:post_id])
    @comment = @post.comments.find(params[:id])
  end
end

cmets_channel.rb 和 cmets_channel.rb 一样,只是流到 cmets_channel.js,这里是 js 频道:

import consumer from "./consumer"

consumer.subscriptions.create("CommentsChannel", {
  connected() {
    console.log('I am comment')
    // Called when the subscription is ready for use on the server
  },

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

  received(data) {
    console.log(data)
    // Called when there's incoming data on the websocket for this channel
  }
});

我的代码可能有什么问题?我敢肯定,我在 JS 代码上做错了,它只是看不到我在帖子上创建的嵌套表单。正如我所说 - 帖子和 cmets 频道非常相同,但有关创建帖子的数据正在广播到我的控制台,但我的 cmets 不是,即使我在控制器中定义了应该看到哪个帖子和哪个评论系统。

【问题讨论】:

  • 我猜原因是在创建评论之后-> redirect_to 立即发布页面,因此加载发布页面意味着重新创建评论订阅,但在评论之前调用 after_action publish_comment频道被创建,评论频道不会收到数据。
  • 你是对的,当我创建评论时 - 帖子页面正在刷新。那么有什么办法可以使这项工作?还是我需要将 Ajax 添加到 cmets 以使页面不会刷新? (此外,def 'publish_post' 也有属性 'after_action' 但由于某种原因它正在工作)
  • 我认为您的代码没问题,因为我猜您的目的是广播新评论,对吧?现在假设你和我打开这篇文章(这个问题),我去创建评论页面创建评论,如果成功我将返回帖子页面(重新加载)显然我会看到评论,现在在你身边,您停留在帖子页面并且评论频道已经创建,因此显然您也会收到广播数据。您需要打开 2 个选项卡(或浏览器)来检查。
  • 我已经尝试过了。我有两个不同的浏览器并测试了帖子,它们工作得非常好 - ApplicationCable 向我的第二个浏览器广播了新帖子,但我不明白 - 为什么它对 cme​​ts 不起作用,如果它可以正确广播所有内容 - 它至少会发送评论数据到控制台,但我什么也没得到。如果你愿意 - 我可以给你发送 github 项目。
  • 是的,因为它是用代码编写的。此外,如果它对您有用 - 它是在我采取行动之前从控制台获取的:CommentsChannel 正在传输订阅确认 CommentsChannel 正在从 cmets:cmets_channel PostsChannel 正在传输订阅确认 PostsChannel 正在从 posts_channel 传输

标签: javascript ruby-on-rails ruby actioncable


【解决方案1】:

设法做到了。我决定为单个帖子创建新频道,这将由 id 确定。所以这是我的 post_channel.rb(!不是 postS_channel.rb):

 class PostChannel < ApplicationCable::Channel
  def subscribed
    stream_from "post_channel_#{params[:post_id]}"
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end
end

post_channel 的 Js 文件:

 import consumer from "./consumer"

document.addEventListener('turbolinks:load', () => {

  const element = document.getElementById('post-id');
  const post_id = element.getAttribute('data-post-id');

  consumer.subscriptions.create({channel: "PostChannel", post_id: post_id }, {
    connected() {
      console.log("connected to post №" + post_id)
    },

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

    received(data) {
      $('#comment_name').append('<div class="comment"> <strong>' + data.title + '</strong></div>')
      $('#comment_content').append('<div class="comment">' + data.content + '</div>')
      console.log(data)
    }
  });
})

我的 cmets_controller 部分:

 class CommentsController < ApplicationController
  before_action :find_comment, only: [:destroy]
  after_action :publish_comment, only: [:create]

  def create
    @post = Post.find(params[:post_id])
    @comment = @post.comments.create(params[:comment].permit(:name, :comment, :user_id, :best, :file))
    redirect_to post_path(@post)
  end

  def publish_comment
    ActionCable.server.broadcast("post_channel_#{@comment.post_id}", {title: @comment.name, content: @comment.comment})
  end
  private

  def find_comment
    @post = Post.find(params[:post_id])
    @post_id = @post[:post_id]
    @comment = @post.comments.find(params[:id])
  end
end

我也在我的路线中添加了这一行:

 get '/posts/:id' => 'posts#show'

所以我所要做的就是指定我的代码应该广播哪个帖子以查看 cmets。如果有人想使用我的代码 - 请注意,它会产生新的错误,您可以通过该错误获得 'no Post with id=['new']' 错误。

【讨论】:

    猜你喜欢
    • 2023-04-07
    • 2011-06-02
    • 2017-09-15
    • 2019-01-10
    • 2017-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-29
    相关资源
    最近更新 更多