病みつきエンジニアブログ

機械学習、Python、Scala、JavaScript、などなど

simple_form をTable 要素で使う

simple_form は、Rails 用のform_for の拡張みたいなものです。
普通、form_for を使うと、タグ等について自分で書いていかないといけませんが、simple_form を上手く運用すると、view内にはform に関連するタグを書く必要はありません(的な感じ)
逆にいうと、タグを勝手に書いていくので、デザイナーへの殺傷能力は高い気がします。上手くコントロールするのが大変です(CoCの弊害だと思う)。

simple_form は、div要素での運用がデフォになってます。
で、表題のようなチャレンジです。あえてtableで果敢に挑戦します。

まず、viewの方には、以下のように書きます。

    <%= simple_form_for @user do |f| %>
      <table>
        <%= f.input :name %>
        <%= f.input :email %>
      </table>
    <% end %>

はい、シンプルです。しかし、このままだとdivります。

次に、生成するform用のhtmlを変更するために、wrapper というものを変更します。wrapperはconfig/initializers/simple_form.rb で定義します。
今回は、デフォルトのwrapperを変更します。
結論ですが、以下のように編集してください。

  config.wrappers :default, :tag => :tr, :class => :input,
    :hint_class => :field_with_hint, :error_class => :field_with_errors do |b|

    #デフォルトのコードが書いてあります。

    ## Inputs
    b.use :label, :wrap_with => {:tag => :th} # or :td, you prefer
    b.use :input, :wrap_with => {:tag => :td}
    b.use :hint,  :wrap_with => { :tag => :span, :class => :hint }
    b.use :error, :wrap_with => { :tag => :span, :class => :error }
  end

wrapper が何をwrapするかというと、f.input が意味するものです。
下から4,5行目で、「f.inputはlabelとinputを描画します」という宣言をしています。
そのf.inputをwrapするための設定が、config.wrappersの引数で、tr要素(表の行)によって囲っています。
行の中に、labelとinputが出来るわけですが、それぞれをtd要素で囲うことによって、label用の列とinput用の列ができます。

最終的に、こんな構造のhtmlができます(かなり省いてますが)

<form>
  <table>
    <tr>
      <th>名前</th>
      <td><input name="name"></td>
    </tr>
    <tr>
      <th>メールアドレス</th>
      <td><input name="email"></td>
    </tr>
  </table>
</form>

感想

これの何がよくないかというと、view内において、生成されるhtmlの特性を知らないと、table式のformを作ってくれない、ということです。
もう少し具体的に言うと、erb内では、simple_form_forとf.inputだけでなく、table要素について書かなければなりません。
こんなの糞です。