Episode下の画面は、商品のリストを表示するRailsアプリケーションのページです。商品は複数のカテゴリーに属し、ProductモデルとCategoryモデルは多対多の関連を持っています。以下に示す商品はいずれのカテゴリーにも属しておらず、今のままでは画面から商品にカテゴリーを関連づける方法がありません。今回のエピソードでは、ユーザが商品情報を編集するときにチェックボックスのリストからカテゴリーを設定できる機能を付加します。:throughを使って関連づけられています。以下はProductのコードです。:categorizationsend商品は、Categorizationという結合用モデルを介して複数のカテゴリを持ちます。:throughの関係をProductに対して持っています。:throughの方がずっと柔軟性が高いので今回はそちらを利用することにしました。利点の一つは、商品のcategory_idsにアクセスするメソッドを提供してくれる点です。これをコンソールで実際に試すために、商品を取得してcategory_idsをリストアップしてみます。[]このmethodを介してcategory_idを設定することも可能です。それによって商品に対応するカテゴリーを取得できます。21:22:48">]ブラウザで商品を見てみると設定したカテゴリーが表示されています。商品情報編集フォームにカテゴリーを追加する商品情報の編集フォームを修正して、カテゴリーの追加や削除ができるようにします。フォームのテンプレートは以下の通りです。%>フォームには現状2つのフィールドがあります。それぞれ、商品の名称と価格です。一つのフィールドをカテゴリー用に追加します。その方法は以下のとおりです。%></div>上のコードでは、カテゴリー内をループしてそれぞれ用にチェックボックスを表示します。:category_idsを使うことができますが、ここではcategory_idsが配列であるために各属性用に複数の属性を設定する必要があり、うまく動作しません。その代わりに今回はマニュアルによる方法をとり、check_box_tagを使用しました。複数のチェックボックスを扱えるように、名前の末尾に空の角カッコを付けます。これがRailsに対して複数の値をまとめてparamsハッシュ内の配列に入れるように指示します。商品の編集用フォームにアクセスしてみると、チェックボックスが表示されます。いくつかを選択してフォームを送信すると、カテゴリーが追加されます。商品を再度編集するためにページに戻ると、選択したカテゴリーにチェックが入っていません。これを修正するためにcheck_box_tagに3つ目の引数を追加して、商品のcategory_idにそのカテゴリーが含まれている場合はチェックボックスがチェックされるようにします。%>商品を編集すると、正しくチェックボックスにチェックが入っています。このフォームにはまだバグが存在します。選択されているチェックボックのチェックをはずしてフォームを送信すると、以前選択されていたカテゴリーが削除されていません。これは、選択されていないチェックボックスがサーバに送信されるための値を持たないことが原因です。この問題に対処するために、フォームにチェックボックスと同じ名前の隠しフィールドを追加して値にnilを設定します。%></div>これでフォームが送信されるときにチェックボックスが一つもチェックされていない場合は、サーバにpostされるフィールドに隠しフィールドが追加されて、商品のカテゴリーが削除されます。クリック可能なチェックボックスのラベル編集フォームにはもう一つ解決しなくてはいけない問題があります。チェックボックスの隣のラベルをクリックしたときには、そのチェックボックスをクリックしたのと同じように振る舞うべきです。labelタグの中に名前をラップするのは簡単ですが、ラベルをidを介してチェックボックスに関連づける必要があるものの、現状では各チェックボックスが同じidを持っています。これはよくない設定なので、まずビューテンプレートを修正して各チェックボックスが個別のidを持つようにします。%>各チェックボックスのidをユニークにするために、Railsが提供するdom_idメソッドを使用してそれにカテゴリを渡します。これがcategory_nのidを生成します。ここでnはカテゴリーのidです。次にlabel_tagを使用してカテゴリー名を表示しますが、ここでdom_idも使用してラベルをチェックボックスと関連づけます。これでページをリロードすると、ラベルをクリックすることでチェックボックスのチェックを入れたり外したりできるようになりました。コードは正常に動作するようになりましたが、少し複雑になってしまいました。これをフォームビルダーに抽出することもできますが、それは今回のエピソードの範囲を超えています。代替案としてSimpleFormやFormtasticなどのgemを利用する方法があります。SimpleFormにはcollection_check_boxesメソッドがあり、今回おこなった処理をずっと簡潔に行う方法を提供します。Formtasticには似たようなcheck_boxesメソッドがあります。