railsにおいて、予め選択肢をいくつか用意し、チェックボックスで複数回答してもらいたいときがある。ところが、Viewで現れるのは複数個のModelため、これをRailsで表現するのは、少し手間がいる。自分の場合、上手くいくまで試行錯誤したので、忘れないように記しておく。
言うまでもないが、accepts_nested_attributes_forを利用しているので、対応するrailsを使用すること。
できる限り誤記がないように注意したが、実際に動かしたコードとは違うので間違いが含まれているかも。
Model:
class User < ActiveRecord::Base has_many :user_kinds has_many :kinds, :through => :user_kinds accepts_nested_attributes_for :user_kinds end class Kind < ActiveRecord::Base has_many :user_kinds has_many :users, :through => :user_kinds end class UserKind < ActiveRecord::Base belongs_to :kinds belongs_to :users #validates_uniqueness_of :kind_id, :scope => :user_id end
Controller:
ほとんどScaffoldの吐くコードで大丈夫だが、一点だけ修正。
def update @user = User.find(params[:id]) UserKind.delete_all(['user_id = ?', @user.id]) # ここを追加, .clear の方が懸命かも??? 未検証 if @building.update_attributes(params[:user]) flash[:notice] = 'User was successfully updated.' redirect_to(@user) else render :action => 'edit' end end
このコードでは、updateを行う度にチェックボックスの最新の状態を追加する。例えば、ある選択肢をチェック入れたまま更新すると、同じ値のモデルをもう一つ作成してしまうことになる。これでは、チェックボックスがチェックされた状態から外れた状態にした場合、うまく動かない場合があるので、対象となるユーザーのUserKindを全部削除する必要がある。
View(/app/views/users/_form.html.erb):
<% for kind in Kind.find(:all) -%> <%= check_box_tag("user[user_kinds_attributes][][kind_id]", kind.id, @user.user_kinds.include?(kind)) -%> <%=h kind.name %> <% end -%>
例えば、こんな感じで表示される
□独身 □イケメン ■金持ち □非モテ
参考:
http://satishonrails.wordpress.com/2007/06/29/multiple-checkboxes-with-habtm/