プログラミング学習 備忘録

Railsを学習していく上での技術メモ。学んだことや解決したエラーなどを記録していきます。

掲示板実装③ 関連付けモデルのcreateアクション

実装時の最初のコード

def create
    @board = Board.new(board_params)
    @board.user_id = current_user.id
    debugger
    if @board.save
      flash[:success] = t('defaults.message.new_board_was_created')
      redirect_to boards_path
.
.
.
private

def board_params
    params.require(:board).permit(:title, :body)
end

これで実行したところエラーが発生

Started POST "/boards" for ::1 at 2020-10-22 11:58:26 +0900
Processing by BoardsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"i+2YvOizuA+ssszr3qeVbjJoR2GhLPRyiizTuclusxtL998Pvb5XoAlay4GxOL9QmSUIhqEZLZLUtcP2pwf0BQ==", "board"=>{"title"=>"いかが?", "body"=>"いい感じ"}, "commit"=>"登録する"}
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 21], ["LIMIT", 1]]
  ↳ vendor/bundle/ruby/2.6.0/gems/activerecord-5.2.3/lib/active_record/log_subscriber.rb:98
   (0.1ms)  begin transaction
  ↳ app/controllers/boards_controller.rb:12
   (0.1ms)  rollback transaction
  ↳ app/controllers/boards_controller.rb:12
  Rendering boards/new.html.erb within layouts/application
  Rendered boards/new.html.erb within layouts/application (3.9ms)
  Rendered shared/_header.html.erb (7.1ms)
  Rendered shared/_flash_message.html.erb (0.5ms)
  Rendered shared/_footer.html.erb (0.6ms)
Completed 200 OK in 186ms (Views: 177.9ms | ActiveRecord: 0.4ms)

サーバーログを見るとrollback transactionが発生していた。 バリデーションエラーが起こってる?

debuggerを挟んでparamsの中身をチェック

(byebug) params
<ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"0JLIVzGzOZq3K68t7TXgguDQg3Kzs5bAK29rmjVbrhwQiI/kZL7WNRLDqEeCqsq8S53MlbOGTyB19nvVWzLpAg==", "board"=><ActionController::Parameters {"title"=>"いかが?", "body"=>"いい感じ"} permitted: false>, "commit"=>"登録する", "controller"=>"boards", "action"=>"create"} permitted: false>
(byebug) @board
#<Board id: nil, title: "いかが?", body: "いい感じ", user_id: nil, created_at: nil, updated_at: nil>
(byebug) @board.user_id
nil
(byebug) @board.user
nil
(byebug) 

やっぱりuser_idがnilになっていて弾かれていた。 つまりuser_idを渡してあげればしっかりと動作するはず!

次のコード

def create
    @board = Board.new(board_params)
    @board.user_id = current_user.id
    if @board.save
      flash[:success] = t('defaults.message.new_board_was_created')
      redirect_to boards_path

If @board.saveの前に、@boardのuser_idを渡す一文を追加。 すると、今度は成功した!

しかし、モデル同士を紐付けしたのに、上記のコードではそのメリットを活かせていない。 紐付けをしていることにより、下のコードを使って一文で表すことができる

@board = current_user.boards.build(board_params)

ここでbuildを使っているのは、「モデルが関連付いているときは、buildを使う」というrailsの暗黙の了解のためであり、 newを使用してもしっかり動作する。