Ruby on Railsのお話です。has_many で through な多対多のデータを扱うときの関連付けを行う方法。
たとえば、以下のようなActiveRecordで
class Book has_many :book_genres has_many :genres, :through => :book_genres end class BookGenre belongs_to :book belongs_to :genre end class Genre has_many :book_genres has_many :books, :through => :book_genres end
Bookの編集画面からGenreの関連付けをしたいならば、app/views/books/_form.html.erb に以下のように書いてやります。
<%= form_for(@book) do |f| %> ... <% Genres.all.each do |genre| %> <%= check_box_tag("book[genre_ids][]", genre.id, @book.genre_ids.include?(genre.id)) %><%= genre.name %> <% end %> ... <% end %>
book[genre_ids] という名前のパラメータに genre の id をセットして送信してやれば @book.update_attributes(param[:book]) で中間テーブルも一緒に更新されるようになるのです。とても簡単ですね。
ところが…
チェックボックスを全て外したときは関連を全部削除してほしいのですが、削除されません。チェックボックスを全部外すと book[genre_ids] というパラメータ自体が送られず、ActiveRecord さんは genre_ids を変更しなくていいんだね?と判断します。
対処法。hiddenでダミーのパラメータを作るだけ。
<%= form_for(@book) do |f| %> ... <% Genre.all.each do |genre| %> <%= check_box_tag("book[genre_ids][]", genre.id, @book.genre_ids.include?(genre.id)) %><%= genre.name %> <% end %> <input type="hidden" name="book[genre_ids][]"> ... <% end %>
params[:book][:genre_ids]の値に ["1", "2", ""] のような空文字が入りますが、更新時に無視されるの問題ないようです。
こういうコードはviewに書かずにヘルパにまとめた方がいい、というわけでGemにしておきました。10行ぐらいのコードですけど…、テストも書いてないのでrubygems.orgにはアップしてません。bundlerのgit経由で使ってください。
gem "checkboxes_helper", ">=0.1.0", :git => "git://github.com/paulownia/checkboxes_helper.git"
で
<%= form_for(@book) do |f| %> ... <%= f.collection_check_boxes(":genres", Genre.all, :id, :name %><%= genre.name %> ... <%= f.check_boxes(":genres", Genre.all.map { |g| [g.id, g.name] } %><%= genre.name %> ... <% end %>
みたいな感じに使います。