88日目
今日の学習
Ruby on Rails
form_withでデータが送れない
以下のようなcreate
アクションを作成し、投稿ができるようにしたのだが投稿ができない。
Post
では、タイトル、ゲーム名、本文を入力してもらうフォームを用意する。
def create post = Post.create!( title: params[:title], game: params[:game], body: params[:body], user_id: current_user.id ) redirect_to post end def show @post = Post.find(params[:id]) end private def post_params params.require(:post).permit(:title, :game, :body) end
user_id
を投稿に紐づけたくてこのような形にしている。
入力した値が送信できなかった原因は、post_params
というメソッドを作成したにも関わらず、create
メソッド内でparams
と記述していたのが原因だった。
見本を写して作ったメソッドのため、そのままにしていたのが良くなかった。ビュー側のform_with
の書き方を見直しても問題なかったため、少々行き詰まってしまった。
正しくは、以下のような形にする。
post = Post.create!( title: post_params[:title], game: post_params[:game], body: post_params[:body], user_id: current_user.id )
エラー画面には文字を入力してくださいというバリデーションのメッセージが表示されていた。
表示されているエラー画面では以下のように表示されており、ちゃんと値が送れているのではないかと早とちりしてしまっていた。
{"authenticity_token"=>"[FILTERED]", "post"=>{"title"=>"タイトルです", "game"=>"ゲーム名", "body"=>"面白いです"}, "commit"=>"送信"}
しかし、ターミナル側には表示されていなかった。
post_params
で受け取ることにより、ちゃんと値が入力されている状態にすることができた。
これで良かったと思いきや、ゲーム名の部分でエラーが発生する。
AssociationTypeMismatch
本来、「ゲーム名」としているところには、楽天APIで検索したゲームの情報を選択して投稿...という形にしようと思っているのだが、暫定的にゲーム名を入力するだけにしてある。
ゲームの情報を保存するGame
モデルを別で作成してあり、Post
モデルと紐づけてある状態だ。
暫定で用意したゲーム名の入力部分に適当な文字を入力して投稿しようとすると、以下のようなエラーが発生した。
ActiveRecord::AssociationTypeMismatch in PostsController#create Game(#69160) expected, got "ゲーム名" which is an instance of String(#5620)
Ruby - RailsでAssociationTypeMismatchエラー|teratail
こちらを参考にすると、「入力された値("ゲーム名")はString
なので、Game
の外部キーではないためエラーが発生しているということになる。
とりあえず投稿だけできるかを確認したかったため、ゲーム情報を楽天APIから検索してDBに登録する機能は後回しにしようと考えていたが、同時に実装することにした。
一つのフォームから複数のモデルに保存
Post
とGame
モデル両方に登録を行いたい。
Ruby on Rails における build メソッドと new メソッドの違い - Qiita
【Rails】モデルの関連付けで用いられるbuildメソッドまとめ|TechTechMedia
今回はモデルの関連付けを行うため、new
ではなくbuild
メソッドを利用。
build
を使うとfield_for
が使えるため、複数モデルにデータを保存できるようになる。
また、belongs_to
やhas_one
では親モデル.build_子モデル
という形にする必要がある。
今回であればpost.build_game
のようにする。
アバター機能
ポートフォリオに、ユーザーがアバターを設定できる機能をつけたい。
しかし、デプロイする際にデータをどこに保存する設定であれば大丈夫なのかどうかが良く分からない。
【Rails忘備録】carrierwave使ってS3に画像をアップロードするの巻 - 君が代
こちらの方は、冒頭でHerokuへデプロイする場合はS3が必要だと仰っている。
【Rails5】AWS S3+CarrierWave+Fog::AWSを利用して画像アップロード機能を作成する | WEB-LOG
そこで、以下の記事をもとにgem CarrierWave
を画像アップロード機能として使用しながら、本番環境ではS3に画像がアップロードできるように設定した。
【Rails】 CarrierWaveチュートリアル | Pikawaka - ピカ1わかりやすいプログラミング用語サイト
アバターを設定していない場合表示されるデフォルト画像を用意したが、サムネイル用のデフォルト画像は別途で用意しなければならないようだった。
外部キーの追加と削除
追加
開発中に、自分のデータベースの組み立て方がおかしいことに気づいた。具体的にはbelongs_to
の矢印方向を間違っていた。
そのため、誤った外部キーを削除し、新たに外部キーを追加なければならない。
追加する際は、マイグレーションファイルを作成し、add_reference
を利用する。
【Rails】後からカラムを追加して外部キーを張る際に、add_referenceを使う場合の注意点。 - Qiita
def change add_reference :子モデル複数形, :親モデル, foreign_key: true end
このとき、foreign_key
がデフォルトではfalse
になってしまうため、オプションでtrue
とする必要がある。
削除
外部キーを削除する際は、マイグレーションファイルを作成し、remove_foreign_key
を利用する。
Rails の migration で外部キー制約の設定をする (add_foreign_key, remove_foreign_key) - Qiita
def change remove_foreign_key :親モデル名複数形, :子モデル名複数形 end
これでマイグレーションした後にテーブルを確認してみると、まだgame_id
というカラムが残ったままだった。
remove_index :posts, :game_id remove_column :posts, :game_id, :bigint
以下を新たに実行すると、削除することができた。