執筆時点のRubyとRailsのバージョンは以下の通りです。
shell
ruby -v
# 3.1.1
bundle exec rails -v
# 7.0.2.2
shell
bundle exec rails _7.0.2.2_ new .
bundle add devise
bin/rails g devise:install
bin/rails g devise user
bin/rails g model room name
bin/rails g model message content:text user:references room:references
bin/rails g controller rooms index show
toutch app/controllers/messages_controller.rb
toutch app/views/rooms/_room.html.erb
toutch app/views/messages/_message.html.erb
toutch app/javascript/controllers/form_controller.js
config/routes.rb
Rails.application.routes.draw do
devise_for :users
root to: 'rooms#index'
resources :rooms, only: :show do
resources :messages, only: :create
end
end
app/models/message.rb
class Message < ApplicationRecord
belongs_to :user
belongs_to :room
after_create_commit -> { broadcast_append_to room }
end
app/models/room.rb
class Room < ApplicationRecord
has_many :messages
end
app/controllers/rooms_controller.rb
class RoomsController < ApplicationController
before_action :authenticate_user!
def index
@rooms = Room.all
end
def show
@room = Room.find(params[:id])
end
end
app/controllers/messages_controller.rb
class MessagesController < ApplicationController
before_action :authenticate_user!
def create
room = Room.find(params[:room_id])
room.messages.create!(**message_params, user: current_user)
respond_to do |format|
format.turbo_stream
format.html { redirect_to room }
end
end
private
def message_params
params.require(:message).permit(:content)
end
end
app/views/rooms/index.html.erb
<h1>Room select</h1>
<%= render @rooms %>
app/views/rooms/_room.html.erb
<div><%= link_to room.name, room_path(room) %></div>
app/views/rooms/show.html.erb
<h1>Chat room</h1>
<%= turbo_stream_from @room %>
<%= render @room.messages %>
<%= form_with(model: [@room, @room.messages.new], data: { controller: "form", action: "turbo:submit-end->form#reset" }) do |f| %>
<%= f.label :content, 'Say something:' %>
<%= f.text_field :content %>
<%= f.submit %>
<% end %>
app/views/messages/_message.html.erb
<div><%= message.content %></div>
app/javascript/controllers/form_controller.js
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
reset() {
this.element.reset()
}
}