※rails初心者です。何か誤りや判りにくい点などがあればご指摘ください。
グループチャット機能のあるwebアプリケーションを開発しています。現在ビューの投稿フォームに入力された値をテーブルに保存する機能を実装しています。コントローラーは以下の通り。
app/controllers/message_controller.rb
class MessagesController < ApplicationController
before_action :authenticate_user!
def index
@messages = Message.find(params[:group_id])
@group = Group.find(params[:group_id])
@message = Message.new
end
def create
@message = @group.messages.new(message_params)
if @message.save
redirect_to group_messages_path(params[:group_id]), notice: "メッセージ送信成功"
else
flash.now[:alert] = "メッセェ〜ジを入力してください!"
render "index"
end
end
private
def message_params
params.require(:message).permit(:body, :image).merge(user_id: current_user.id)
end
end
createアクションで新規インスタンスを生成してそれを保存したいのですがエラーが出てしまいます。エラー文は以下の通り。
エラー文
NoMethodError in MessagesController#create undefined method `messages' for nil:NilClass
Extracted source (around line #12):
def create
@message = @group.message.new(message_params)
if @message.save
redirect_to group_messages_path(params[:group_id]), notice: "メッセージ送信成功"
else
おそらくcreateメソッド内で新規インスタンスを生成する際に問題があるんですが、何が悪いのやら。
app/models/group.rb
class Group < ApplicationRecord
has_many :messages
has_many :members
has_many :users, through: :members
validates :name, presence: :true
end
モデルでもちゃんとアソシエーションを定義しています。なのに何故っ!!と思っていましたが、実はこれインスタンス変数のスコープが問題なんです。僕はindexメソッド内で定義した@groupはcreateメソッド内でも有効だと思っていました。しかし実際はindexメソッド内で定義した3つのインスタンス変数のスコープはindexアクションが実行終了するまでなんです。なので別のアクションが動作するときに再びインスタンス変数を定義しないとダメだったんです。つまりcreateメソッド内で@groupの定義がなされていないためにmessagesがnillになっていいたんです。
そこで以下の点を修正しました。
@groupの定義はコントローラー内の2つのアクションで必要なのでbefore_actionを使って2つのアクションが動作する前に@groupを定義したメソッドを呼び出すようにしました。
app/controllers/message_controller.rb
class MessagesController < ApplicationController
before_action :authenticate_user!
before_action :set_group, only: [:index, :create]
def index
@messages = Message.find(params[:group_id])
@message = Message.new
end
def create
@message = @group.messages.new(message_params)
if @message.save
redirect_to group_messages_path(params[:group_id]), notice: "メッセージ送信成功"
else
flash.now[:alert] = "メッセェ〜ジを入力してください!"
render "index"
end
end
private
def message_params
params.require(:message).permit(:body, :image).merge(user_id: current_user.id)
end
def set_group
@group = Group.find(params[:group_id])
end
end
ちゃんと動作しました。めでたしめでたし。