Reputation: 1168
I'm following Michael Hartl tutorial about Rails 5 ActionCable, to build a simple chat, and a problem is occurring inside my create
action in MessageController
:
def create
message = current_user.messages.build(message_params)
if message.save
ActionCable.server.broadcast 'room_channel',
content: message.content,
username: message.user.username
head :ok
end
end
It goes until head :ok
, and after that, display an empty HTML page. The log is:
Processing by MessagesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"h9UsB78aX8mO8Nyn8eZEUuDzAOxL4V7UCMwNuTfwALliMv7OCkcUIeR4/xXIcvPjwq9H1bphjn6G96G+0VYisw==", "message"=>{"content"=>"oi"}, "commit"=>"Send"}
User Load (1.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Message Load (2.1ms) SELECT "messages".* FROM "messages" ORDER BY "messages"."created_at" DESC LIMIT ? [["LIMIT", 50]]
(0.3ms) begin transaction
SQL (9.3ms) INSERT INTO "messages" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["content", "oi"], ["user_id", 1], ["created_at", 2016-09-19 02:12:58 UTC], ["updated_at", 2016-09-19 02:12:58 UTC]]
(9.1ms) commit transaction
[ActionCable] Broadcasting to room_channel: {:content=>"oi", :username=>"alice"}
Completed 200 OK in 69ms (ActiveRecord: 22.0ms)
RoomChannel transmitting {"content"=>"oi", "username"=>"alice"} (via streamed from room_channel)
Finished "/cable/" [WebSocket] for 10.0.2.2 at 2016-09-19 02:12:58 +0000
RoomChannel stopped streaming from room_channel
(After that, I can refresh the page and the message is displayed properly)
Why that is happening?
My RoomChanel class:
class RoomChannel < ApplicationCable::Channel
def subscribed
stream_from "room_channel"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
end
My room.coffee
App.room = App.cable.subscriptions.create "RoomChannel",
connected: ->
# Called when the subscription is ready for use on the server
disconnected: ->
# Called when the subscription has been terminated by the server
received: (data) ->
alert data.content
Upvotes: 5
Views: 857
Reputation: 13
I'm following Michael's tutorial for ActionCable and had the same problem.
I think this was due to the format of the form partial _anything.html.erb
.
app/views/messages/_message_form.html
As you go through the tutorial, you're upgrading to Action Cable features. But in the _message_form
partial, it is still with the usual HTTP request
. So after you broadcast a message using the messages_controller.rb
, the browser render an empty page because the form was already rendered.
app/views/messages/_message_form.html
, Originally:
<div class="message-input">
<%= form_for(@message) do |f| %>
<%= f.text_area :content %>
<%= f.submit "Send" %>
<% end %>
</div>
So, you have to add the remote: true
to the form, like this:
<div class="message-input">
<%= form_for(@message, remote: true) do |f| %>
<%= f.text_area :content %>
<%= f.submit "Send" %>
<% end %>
</div>
Adding the remote: true
makes an JS request (Ajax, in this case)
Quoting Michael:
You can verify by submitting a message that it appears as desired, but in fact this is a cheat because the form from Listing 6 is currently submitting an ordinary
HTTP POST
request, which causes the page to refresh. In order to use Action Cable, we need to change the form to submit a remote request that submits an Ajax request without refreshing the page. We can do this by including theremote: true
option in the call toform_for
.
Note that I'm doing everything in localhost:3000
Upvotes: 0
Reputation: 978
I know the answer is accepted already, but this solution worked for me without having to remove head :ok
, maybe it helps somebody out.
Normally in the development environment people are running localhost:3000
but i was running on a different port, localhost:3030
.
And this case i had to add an allowed request origin for that port, like so:
config.action_cable.allowed_request_origins = [
'http://localhost:3030'
]
to my /config/environments/development.rb
Upvotes: 1
Reputation: 1168
Following a sugestion, I'm adding as answer what I did to get around this problem. It doesn't answer why that happens, but solve the problem.
The solution is: remove head :ok
.
Aparently it's unecessary, because if I add a test whit assert_response :success
to the action, it'll pass.
Upvotes: 0