LoginSignup
3
2

More than 5 years have passed since last update.

インスタンス変数のスコープ~undefined method `method' for nil:NilClass~

Posted at

※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

ちゃんと動作しました。めでたしめでたし。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2