醜悪な設計とコードを書いてみるー(多対多でなく多対配列)
はじめに
このところチカラワザに凝ってて、スマートでないことを知りつつも、なんとかしてみようというチャレンジの記録。できないとは言いたくなかっただけ。
多対多の関連におけるチェックボックスでの紐付けは簡単にできた(http://d.hatena.ne.jp/ikad/20110604/1307158317)ので、今回はこれをいじってみた。
テーマは多対多の片方をモデルでなくただの配列でやったらどうなるか・・・。
なんでこんなことをしたかというと、
・リストの数が少なく、変更もないためメンテしない(もしくは変更するならそれなりの覚悟)
・正規化によるテーブルの増加がやだ
・includeもjoinめんどい
なんて、後ろ向きで拡張性もへったくれもない理由でもなんとかしてみたかった。
背景と登場人物
ブログのタグ付けを想定。
モデル
Post ・・・ ブログ記事
Tag ・・・・ ブログ記事につけられたタグ
配列
tag_list ・・・ タグのリスト
準備作業
とりあえずscaffoldとmodelをば。
rails g scaffold Post title:string body:text rails g model Tag name:string post:references
app/helpers/application_helper.rbに配列をば。
def tag_list %w(dog cat bird fish) end
コード書いてみるー
app/modeld/post.rbが主戦場なのでまるごと
class Post < ActiveRecord::Base has_many :tags, :dependent => :destroy attr_accessor :tag_names #フォームからpostされる after_save :tags_update #いろいろ捗る def mytag_names arr = [] self.tags.all.map {|tag| arr << tag.name} return arr end def tags_update self.tags.destroy_all tag_names.each do |name| self.tags.create(:name => name) end if tag_names end end
app/views/posts/_form.html.erbにはチェックボックスのリストを追加
<div> <% tag_list.each_with_index do |name, idx| %> <%= check_box_tag 'post[tag_names][]', name, @post.mytag_names.include?(name), :id => "tag_#{idx}" %> <%= label_tag "tag_#{idx}", name %><br> <% end %> </div>
app/views/psots/index.html.erbにはタグのリストを追加
<td><%= post.mytag_names.map {|name| name + ","} %></td>