LoginSignup
1
1

More than 5 years have passed since last update.

ActiveModelを用いたフォームで配列やハッシュを扱う方法

Last updated at Posted at 2016-04-26

検索フォームなど、モデルに基づかないフォームを作る時に、ActiveModelを使ってフォームを作りたかったが、配列やハッシュをフォームで扱う時に若干詰まったのでメモ。

結論から言うと、スマートな方法ではないので、諦めた方が良さそう。
良さげな方法があったら教えてください。

例えば、レベルがmin〜maxの間のUserを検索するフォームを作りたいという場合で、levelをハッシュでやりとりしたい場合。
関係ない部分は諸々大分省略してるので脳内補完してください。

Form
class UserSearchForm
  include ActiveModel::Model
  attr_accessor :name, :level

  validates :name, length: { in: 6..20 }
end
View
<%= form_for(@user_search_form, url: search_user_url)
  <%= f.text_field :name %>
  <%= f.number_field :level, name: "user_search_form[level[min]]", value: @user_search_form.level.try(:fetch, :min, nil) %>
  <%= f.number_field :level, name: "user_search_form[level[max]]", value: @user_search_form.try(:fetch, :max, nil) %>
  <%= f.submit "検索" %>
<% end %>
Controller
class UsersController < ApplicationController
  def search
    @user_search_form = UserSearchForm.new(params[:user_search_form])
    @results = User.order(:id)

    @results = @results.where("name LIKE ?", @user_search_form.name) if @user_search_form.name.present?
    if @user_search_form.level.present?
      @results = @results.where("level >= #{@user_search_form.level[:min]}") if @user_search_form.level[:min].present?
      @results = @results.where("level <= #{@user_search_form.level[:max]}") if @user_search_form.level[:max].present?
    end
  end
end

Viewのフォームでname属性を指定しているところがミソ。
これでControllerに値が渡る時にparams[:user_search_form]内にlevelがハッシュとして入る。
でも、valueをよしなにしてくれなかったりで、そもそもActiveModelを使う利点が薄れてしまっているのでかなり微妙。
今回の例なら、わざわざハッシュにしなくてもattr_accessor:level_min:level_maxを定義して使えば良さそう。

参考リンク

ActiveModelを使ってDBと関係ないFormを作成する
stackoverflow - Rails: form_for with field for Hash
hashに対してtryする

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1