ruby on rails
例えば、クイズのテーブルがあって、クイズのカテゴリのテーブルもあり、クイズとクイズのカテゴリーは、多対多の関係になっていて、Categorizationという結合テーブルがある場合を考えます。
このような場合において、webサイトの表示にクイズのカテゴリを、チェックボックスで選択したいという課題について考えます。
参考)http://www.tom08.net/entry/2016/09/16/175801
のbefore_saveが大切でした。
自分の場合、before_save :category_ids_slim としました。
before_saveを使わないと、Quizテーブルのcategory_idsのカラムの中身が、
[¥"1¥"]のようになり、利用する際に困ってしまいます。そのため、before_saveが必要となります。
以下、参考ソースコードの紹介
class Quiz < ApplicationRecord
has_many :categorizations
has_many :quiz_categories, through: :categorizations
before_save :category_ids_slim
def category_ids_slim
self.category_ids.gsub!(/[\[\]\"]/, "").gsub!(" ","") if attribute_present?("category_ids")
end
end
(↑gsubが2つあるのは、苦肉の策です。)
<% if @quiz.category_ids.split(",").index("1") %>
<%= f.check_box :category_ids, {multiple: true, :checked => true}, "1", nil %>
<% else %>
<%= f.check_box :category_ids, {multiple: true}, "1", nil %>
<% end %>
<%= label_tag :category_ids, '日本史' %>
<% if @quiz.category_ids.split(",").index("11") %>
<%= f.check_box :category_ids, {multiple: true, :checked => true}, "11", nil %>
<% else %>
<%= f.check_box :category_ids, {multiple: true}, "11", nil %>
<% end %>
<%= label_tag :category_ids, '世界史' %>
もちろん、each do 〜 end で繰り返した方がいいのですが、頭の良くない自分は、1つ1つ階段を上がっていく感じでないとプログラムを組めないので、頭の良くない人向けに書いています。
railsでチェックボックスを複数使う場合は、multiple: trueと書きます。すると、@quiz.category_idsの変数が配列として認識されます。
上の内容だと、日本史のチェックボックスにチェックがついていると、1がcategory_idsの配列に追加され、チェックがついてないと何も追加されません。
日本史と、世界史にチェックがついていると、category_idsには、[¥"1¥", ¥"11¥"]のような文字列(配列?)が入ります。(この¥"が邪魔なので、beofre_saveで削除します)
なぜ1と11にしたかというと、@quiz.category_ids.include?("1")とすると、配列に11が入っている場合にも、trueとなってしまうので、それを確認するためです。なので、includeを使うと良くないので、今回は、split(",").index("1")というようにして、解決しています。
リテラルとかenumとかは後で実装します。
ということで、個人的にかなり時間がかかったので、メモついでに書きました。きれいなコードではないと思いますが、参考になるなら見て下さい。他のサイトの解説ではよくわからなかったのと、解説サイトが少なかったので、書きました。
追記
コードのリファクタリング その1
上のコードをeachで繰り返し処理に変更し、さらにリテラルを排除しました。
<% QuizCategory.all.each do |c| %>
<% if @quiz.category_ids.split(",").index(c.category_id.to_s) %>
<%= f.check_box :category_ids, {multiple: true, :checked => true}, c.category_id, nil %>
<% else %>
<%= f.check_box :category_ids, {multiple: true}, c.category_id, nil %>
<% end %>
<%= label_tag :category_ids, c.name %>
<% end %>