Rails の select() 系ヘルパーはイケてないと声を大にして言いたい

背景

いつも思うが、Rails の select() 系ヘルパーメソッドってわかりにくい。
初心者泣かせ。

具体例(1)

参考文献: マニュアル

select() の例:

### eRuby
<%= select("post", "person_id",
           Person.all.collect {|p| [ p.name, p.id ] },
           { :include_blank => true }) %>

### HTML
<select name="post[person_id]">
  <option value=""></option>
  <option value="1" selected="selected">David</option>
  <option value="2">Sam</option>
  <option value="3">Tobias</option>
</select>

( select() では [p.name, p.id] の順番なのに )

具体例(2)

collection_select() の例:

### eRuby
<%= collection_select("post", "person_id",
                      Person.all, :id, :name,
                      {:prompt => true}) %>

### HTML
<select name="post[person_id]">
  <option value="">Please select</option>
  <option value="1" selected="selected">David</option>
  <option value="2">Sam</option>
  <option value="3">Tobias</option>
</select>

( collection_select() では :id, :name の順番になってる! 紛らわしい! )

問題点

  • 使い方がわかりにくい
    • 引数の数が多いため
  • よく似たメソッドが複数存在
    • ちょっとずつ異なる用途ごとに別々のメソッドが用意されているため

改善案

  • select() がブロックをとるようにする。
<%= select(....) do |t|
      @items.each {|x| t.option(....) }
    end %>

改善例(1)

### 改善前
<%= select("post", "person_id",
           Person.all.collect {|p| [ p.name, p.id ] },
           { :include_blank => true }) %>

### 改善後
<%= select("post", "person_id") do |t|
      t.option(nil, '-')
      Person.all.each {|p| t.option(p.id, p.name) }
    end %>

(:include_blank とか覚える必要なし)

改善例(2)

### 改善前
<%= collection_select("post", "person_id",
                      Person.all, :id, :name,
                      {:prompt => true}) %>

### 改善後
<%= select("post", "person_id") do |t|
      t.option(nil, 'Please select')
      Person.all.each {|p| t.option(p.id, p.name) }
    end %>

(:prompt とか覚える必要なし)

効果

  • 使い方がわかりやすい
    • select() の引数とブロックとで役割を分担するため
    • select() の引数の数が減るため
  • 1 つのメソッドに統一できる
    • 用途が少しずつ異なっても、ブロックの記述で吸収できる
    • 少しだけ異なる用途ごとにメソッドを用意する必要がない

今後の課題

  • optgroupタグのサポート Done
  • HTMLエスケープ
    • Rails3の仕様にあわせるべき?
  • Rails plugin 化
    • めんどいなー
    • 正直、Rails には疲れた

まとめ

  • Rails の select() 系ヘルパーはイケてない
    • 使い方がわかりにくい
    • よく似たメソッドが複数存在する
  • select() がブロックを取るように改善
    • 使い方がわかりやすくなる
    • 1 つのヘルパーメソッドだけで済む
    • ブロック万歳!