なまもの備忘録

気になったことをつらつらと書いていきます

group_collection_selectメソッドでのエラー[Ruby on Rails 5 アプリケーションプログラミング]

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のページにアクセスできるようになる。

その他参考

https://teratail.com/questions/80528