group_collection_selectメソッドでのエラー[Ruby on Rails 5 アプリケーションプログラミング]
Table of Contents
grouped_collection_selectメソッドでのエラー
最近「Ruby on rails 5 アプリケーションプログラミング」の本を読みながらrailsの勉強をしているのだが、本の記述と配布されているサンプルコード(2017/10/29時点)に誤りがあり、割と長い時間嵌ってしまった。 同じ問題に突き当たる人がいないとも限らないので、解決方法を置いて置く。
問題は「4.1.9 選択ボックスの選択をグループ化するーgrouped_collection_selectメソッド」で解説されているサンプルコード
<%= form_for(@review) do |f| %> レビュー対象書籍: <%= f.grouped_collection_select :book_id, @authors, :books, :name, :id, :title %> <% end %>
についてのものだ。 本の手順通りに進めてこのテンプレートファイルを記述し(もちろん対応するルート定義と、コントローラーにメソッドが用意されている必要がある)、サーバーを立ち上げてアクセスすると、
undefined method 'books' for #<Author:~~~>
といったようなエラーに出くわし、ページへのアクセスができない。 これは、この時点でauthorモデルとbookモデルの間にアソシエーションを定義していないことに起因している。配布されているサンプルプログラムの方も同様の理由でエラーを吐く。
ここで問題になっているアソシエーションとはなんだろうか。少し調べた内容を置いておく。
アソシエーション
データベースのテーブル間の関係をrailsのモデル間の関係に落とし込んでrails側から操作できる用にするためのもの。データベースの基本的な用語についてはリンク参照。 テーブルの一つのレコードに対して別のテーブルの一つのレコードが結びついている場合を1:1の関係、別のテーブルのn個のレコードが結びついている場合を1:nの関係などと呼んだりする。
どうも、grouped_collection_selectメソッドはこのアソシエーションの情報を元に対応するbookモデルのパラメータを取得するはずだったのだが、記述がなかったので叶わなかった、ということみたいだ。
対処
そんなわけで、欠けているアソシエーションの情報を補ってやれば解決するということが分かった。今回実装したいauthorとbookの関係性は複数:複数の関係性で、このようなものは中間テーブルを介した表現が一般的らしい。 メソッドとしてはhas_and_belongs_to_manyを使い、下記の用になる。
.../railsbook/model/app/models/ 以下のbook.rbとauthor.rbにアソシエーションを記述する
class Book < ApplicationRecord has_and_belongs_to_many :authors #authorとのアソシエーションを追加 end
class Author < ApplicationRecord belongs_to :user has_and_belongs_to_many :books #booksとのアソシエーションを追加 end
has_and_belongs_to_manyメソッドは複数対複数のアソシエーションをモデルに追加するメソッド。対応するテーブルの関係に上下をつけない為、双方のモデルに記述する必要がある。
以上の変更を加えれば、/view/group_selectのページにアクセスできるようになる。