Rails:绕过控制器中的双重渲染限制

问题描述 投票:0回答:1

我正在 Rails 中构建聊天。我有一个用于发送消息的 MessagesController 和一个用于通过 websocket 接收消息的通道(操作电缆)。

这是我的 MessagesController#create:

def create
  message = Message.create!(message_params)

  ActionCable.server.broadcast(
    "some_channel",
    render(message) # app/views/messages/_message.html.erb
  )
end

接收客户端然后获取渲染的 HTML 并将其附加到页面:

<div class="border-bottom p-3">
  <h6><strong><%= message.from %></strong></h6>
  <div class="message-body">
    <%= markdown message.body %>
  </div>
</div>

使用

render @messages
加载页面时,使用相同的模板呈现所有消息。

在发送者端,我打算在消息表单上使用

remote: true
,然后在 MessagesController#create 底部渲染 JS 来运行 JS 回调。我觉得这是 Rails 的做事方式。但是,正如你所看到的,我已经在控制器中调用了
render
,并且 Rails 不允许我调用 render 两次。

我想我可以自己评估消息模板,以避免第一次使用 ERB 调用

render

def create
  message = Message.create!(message_params)

  message_template = File.read('app/views/messages/_message.html.erb')

  ActionCable.server.broadcast(
    "conversations:#{params[:conversation_id]}",
    ERB.new(message_template).result(binding)
  )

  render 'create', handlers: ['js.erb']
end

但是使用 ERB 构建模板失败,因为控制器无法识别我在消息模板中调用的辅助方法 (

markdown
)。我尝试将方法从视图上下文导入到控制器上下文中,但它不起作用。也许我可以将不同的绑定传递给 ERB,但我不知道哪个(它不接受
view_context
,即使接受,变量
message
在其中也不可用)。

所以现在,我只能手动编写 ajax 请求,而不是在表单上使用

remote: true
。我怀疑我可以使用涡轮流来完成这类事情(我以前从未使用过),但仅仅为此安装涡轮似乎有点矫枉过正。我无法摆脱这样的感觉:必须有一种简单的 Rails 方式来完成我想做的事情。

如何绕过 Rails 不允许双重渲染的限制?或者,我愿意接受另一种方法。

编辑:我想到我可以通过套接字发送新消息,而不是使用 MessagesController#create。由于我是从 JS 执行此操作,因此我可以在那里运行我的“回调”。但我使用套接字这一事实是偶然的;我可以看到其他场景,其中需要绕过不涉及套接字的双重渲染。

编辑 2:另一个想法:我可以仅使用控制器来保存和渲染消息,然后从客户端广播渲染的消息。但随后我需要一个系统来识别和忽略往返(自己发送的传入消息)——对于如此简单的事情来说,这似乎也有些过分了。再说一遍,套接字是一个偶然的实现细节。

ruby-on-rails templates rendering
1个回答
© www.soinside.com 2019 - 2024. All rights reserved.