snuf
@snuf (snuf snuf)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

関連付けたidの登録が全てid:1になるエラー

解決したいこと
railsで宿泊予約サイトの開発を進める過程で、部屋の予約機能にエラーが発生しました。
web上で部屋の予約を実行すると、関連づけた部屋が全てid=1で登録されてしまいます。
解決方法を教えて下さい。

rentコントローラー

スクリーンショット 2022-03-20 19.43.36.png

デバッグモードでparams、@hotelappで確認したところ、以下のようになりました。

スクリーンショット 2022-03-20 19.36.34.png
スクリーンショット 2022-03-20 19.39.15.png

Userからはidを受け取れているが、hotelappからはidを受け取れていない、もしくはidを探すように指令できていない?

それゆえ、自動的にidが1で代入されてる?という推測ですが、原因がわかりません。

@rent.hotelapp_id = @hotelapp.id

このコードでそのエラーが発生してるようですが、このコードがないとそもそも登録できず
hotelappコントローラーのparamsのpermit(:id)が余計だったかなと省いたり、rentコントローラーのparams.mergeにuser_idと同じようにhotelapp_id: hotelapp.idやhotelapp_id: @hotelapp.idを追加してみたものの、id=nilになりそもそも登録できなくなるなど、色々試したものの解決に至りません。

アドバイスお願いいたします。

def hotelapp_params
params.require(:hotelapp).permit(:id, :name, :intro, :price, :address,).merge(user_id: current_user.id)
end

念の為hotelappコントローラーのparamsも載せておきます。

初質問のため、わかりにくかったり不手際あるかもしれませんが、よろしくお願いいたします。

0

2Answer

1枚目27行目の

Hotelapp.find_by(params[:hotelapp_id])

# 見つからないとき nil を返す
Hotelapp.find_by(id: params[:rent][:hotelapp_id])

# または

# 見つからないとき例外を投げる
Hotelapp.find(params[:rent][:hotelapp_id])

のどちらかにすれば直ると思います。

エラーの原因は params に入っている :hotelapp_id の取り出し方が違うことに加えて、 find_by の使い方が間違っていることです。使い方は find_by(カラム名: カラムの値) または find_by(SQL の WHERE 句の条件文) です。

Hotelapp.find_by(params[:hotelapp_id]) と書くと後者に該当しますが、このとき params[:hotelapp_id] は取り出し方が間違っているので nil になります。条件文に nil を指定すると WHERE 句が付与されなくなります。結果、 SQL としては SELECT "hotelapps".* FROM "hotelapps" LIMIT 1; が発行されます。これは2枚目のスクリーンショットの [4] pry の次の行でも確認できます。

上記 SQL を実行するといずれかの hotelapps レコードが1つ返されることになります。この場合、 SQL の仕様的にはどのレコードを返すかは不定です。データベースエンジンにとっては挿入順が早いレコードが手頃なので毎回 id=1 のものを返しているだけです。


今回の問題とは関係ありませんが、9行目と10行目で @hotelapp に代入しているため9行目は無駄になっています。どちらか消してください。10行目を残す場合は Hotelapp.find_by(name: params[:room_name]) に直してください。

2Like

Comments

  1. @snuf

    Questioner

    ご回答頂いた通り、Hotelapp.find(params[:rent][:hotelapp_id])に修正したところ、正常に登録出来るようになりました。

    最初にfindメソッドを使ってエラーが起きたため、find_byを使用していたのですが、find_byはカラムから値を取得するくらいの理解だったので理解不足でした。

    findとfind_byの違いで結果どうなるか具体的に説明頂き、とても分かりやすく理解することが出来ました。

    メソッドやコマンドの結果、内部でどのような事が起きてその結果どうなるかなど、そのあたりが自分で調べてもあまり理解が進まなかったので、本でまとまった知識をインプットした方が良い気がしてきました。

    このエラーでずっと進めずにいたので、本当に助かりました。
    感謝いたします。

paramsの出力を見る限り、params[:hotelapp_id]ではなく、params[:rent][:hotelapp_id]のように見えますがいかがですか?

ちなみに、ソースコードはスクリーンショットではなくマークダウンで記述するようにしてほしいです。読みにくいし、回答者側がコピペできないのは不便です。

1Like

Comments

  1. @snuf

    Questioner

    ご回答ありがとうございます!

    rentコントローラーのコード記述に問題があるということでしょうか。
    createアクションを以下のように記載しても動作は変わらずでした、、
    未熟なもので詳しく内容をお教えいただけると幸いです。

    ```
    def create
    #binding.pry
    @rent = Rent.new(rent_params)
    @hotelapp = Hotelapp.find_by(params[:rent][:hotelapp_id])
    @rent.hotelapp_id = @hotelapp.id
    #binding.pry

    ```

    ソースコードはスクリーンショットではなくマークダウンで記述するように
    >>改めます!ご指摘ありがとうございます。
  2. binding.pryの出力を見る限り、paramsの中にhotelapp_idの値は含まれているので、これをController側で取り出せば現在の問題は解決するように思います。

    値の取り出し方はそれこそbinding.pryで色々試してみてください。rails触ってたのがもう4年も前(5.1.2)なのでちょっと定かじゃないですが、paramsのプロパティにpermitted: falseとあるのがちょっと気になりました。確かparams.permitとかしなきゃいけなかったような。。
  3. @snuf

    Questioner

    permitted: false についても調べてみました。
    やはりコントロール側の問題だったようです。paramsやアクションについても色々と参考になりました、ありがとうございます!

Your answer might help someone💌