フォーム - lanchester/rails_environment GitHub Wiki

strong parameters

https://github.com/rails/strong_parameters

mass assignment対策用の機能です。元々はgemでしたがrails 4以降ではコア機能として取り込まれました。

フォームからのパラメータをDBに登録するようなコントローラにおいて

User.new(params.require(:user).permit(:name, email))

のようにホワイトリスト形式で記述します。

配列の指定やネストしたパラメータも指定できます。

params.require(:user).permit(:name, emails: [], friend: [:name, :email])

permit!を使うことによってすべてのパラメータを許可することもできます。

params.require(:user).permit!

ただし、mass assignment脆弱性への危険はあります。

simple_form

https://github.com/plataformatec/simple_form

フォームの記述を少なくできるgemです。

gem 'simple_form'

bundle install

rails generate simple_form:installでプロジェクトにインストール。 以下のファイルが生成されます。

create  config/initializers/simple_form.rb
exist  config/locales
create  config/locales/simple_form.en.yml
create  lib/templates/erb/scaffold/_form.html.erb

twitter-bootstrapと連携する場合は以下のようにオプション付きでインストールします。

rails generate simple_form:install --bootstrap

基本的な使い方

viewform_forの代わりにsimple_form_forと記述します。

<%= simple_form_for @model, url: { controller: :[コントローラ名], action: :[アクション名] } do |f| %>
  <%= f.input :name %>
  <%= f.input :sex, collection: [["男", 1], ["女", 2]], as: :radio_buttons, checked: @model.sex %>
  <%= f.input :job, collection: Job.all.map { |j| [j.name, j.id]}, as: :select, selected: @model.job %>
<% end %>

これで<label>まで含めてタグが生成されます。ラジオボタンやセレクトボックスの場合collectionに配列を指定します。I18n等で日本語化する場合、modelでメソッドを定義しておくと良いです。

バリデート失敗時等に入力情報を保つ場合はcheckedselectedオプションを指定します。enumerizeを使っているカラムの場合は、@model.sexとすると文字列が返ってくるので@model.sex_valueなどで実際にDBに保存する値と比較します。

ブロックを取ることでrailsのヘルパーも使えます。

<%= f.input :role do %>
  <%= f.select :role, Role.all.map { |r| [r.name, r.id, { class: r.company.id }] }, include_blank: true %>
<% end %>

id属性等を変更する場合

<%= f.input :hoge, input_html: {value: "fuga", id: "piyo"} %>

非同期通信

remote: true

ただし、ファイルアップロード時には非同期宣言を無視して画面遷移しようとしてmissing templateエラーとなるため上記は使えない。

nested_form

viewでフォーム要素を動的に追加して子テーブルに持つことができるgemです。

# Gemfile
gem 'nested_form'

application.jsに以下を追加します。

//= require jquery_nested_form

対象となるモデルにはhas_manyaccepts_nested_attributes_forを指定しておきます。関連モデルの削除を許可するならallow_destroy: trueを指定します。

class Blog < ActiveRecord::Base
  has_many :articles
  accepts_nested_attributes_for :articles, allow_destroy: true
end

nested_form_forヘルパーが使えるようになります。

# view
<%= nested_form_for(@blog) do |f| %>

simple_formformtasticを使用している場合はそれぞれ

simple_nested_form_for
semantic_nested_form_for

で使用可能になります。

# view
<div class="field">
  <%= f.label :title %><br>
  <%= f.text_field :title %>
</div>
  <%= f.fields_for :blogs do |blog| %>
    <%= blog.text_field :name %>
    <%= blog.link_to_remove "Remove this" %>
  <% end %>
  <%= f.link_to_add "Add article", :articles %>
<div class="actions">
  <%= f.submit %>
</div>

コントローラではstrong_parameterを許可しておきます。

# controller
def blog_params
  params.require(:blog).permit(:title, :articles_attributes => [:id, :name, :blog_id,  :_destroy])
end

ネストした要素のバリデーション

以下のように通常のバリデーションと同じように指定できます。関連モデルにバリデーションを指定しておくことで、そのバリデートを実行できます。

class Blog < ActiveRecord::Base
  has_many :articles
  accepts_nested_attributes_for :articles, allow_destroy: true
  validates :blog_title, presence: true
  validates :articles, presence: true
end

class Article < ActiveRecord::Base
  belongs_to :blog
  validates :title, presence: true
end

エラーメッセージの日本語化

以下のFormtasticのヘルパーにより自動でバリデーションエラー時のメッセージを表示できます。

<%= f.semantic_errors *f.object.errors.keys %>

関連モデルのattributeの日本語化は以下のように/でモデル同士を繋げて指定します。

# config/locales/ja.yml
ja:
  activerecord:
    attributes:
      blog:
        blog_title: hoge
      blog/articles:
        title: fuga
requestについて

requestにはリクエストオブジェクトが色々入っています。これを使ってリクエストメソッドによって処理を分けることもできます。

# controller
def new
  if request.get? # 他にはpost?など
    @model = Model.new
  else
    @model = Model.new(params)
  end
end

ただしフォームでリクエストを分ける場合POSTPUTPATCHrailsがフォームによって自動で変えているためハマりポイントになりやすいです。get?で判定するのが無難そうです。

⚠️ **GitHub.com Fallback** ⚠️