SakuraWi - BLog

WEBエンジニア。聴いたお話をまとめておく倉庫的な。スタックストックスタック!

検索フォームにvalidationを追加する方法【Ruby on Rails】


Ruby on Railsにて、検索フォームを使用した際に、受け渡す値にvalidationを加えたい時、ありますよね。
form_forやform_tagを使用した際のクエリ,パラメータにvalidationを加える方法を書きます。

Formオブジェクトというデザインパターンのひとつです。

RailsTutorialを絶賛挑戦中や、終わってから少し応用的なことをしている人は同じようなことで困っているかと思います。
参考にになれば幸いです!

おおまかな流れ

  1. modelによるvalidationを利用するため、フォーム用のクラスを作成する。
  2. クラスにvalidationを記述しておく
  3. コントローラ内で作ったクラスをインスタンス化させる時に引数として渡してvalidationを適用させる

といった流れですね。

内容

主に検索フォームを使用した例はこちら

RailsTutorial7章より

<%= form_for(@user) do |f| %>
      <%= f.label :name %>
      <%= f.text_field :name %>

      <%= f.label :email %>
      <%= f.email_field :email %>

      <%= f.label :password %>
      <%= f.password_field :password %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation %>

      <%= f.submit "Create my account", class: "btn btn-primary" %>
    <% end %>

このコードでは、以下のコントローラで定めたUserのモデルオブジェクトを使用したformを作成しています。
つまり、@userに対して働きかけが行うようにしているといったものです。
@userはmodelであるUserからインスタンス化したものです。

class UsersController < ApplicationController

  def show
    @user = User.find(params[:id])
  end

  def new
    @user = User.new
  end
end

ここで、validationがかかるタイミングはmodelを作成しようとした時です。
上記のmodelのUserをみてみましょう。

class User < ActiveRecord::Base
  validates :name, presence: true
end

こちらのUserは ActiveRecordを継承して作成しています。
ここがポイントです。
ActiveRecordを継承して作成したmodelオブジェクトは、簡単に言えばDBとやりとりを行うmodelとなります。

modelでは、createやnewを行うタイミングでvalidationが適用されます。
ここでは,validates :name, presence: trueの部分ですね。
name属性(変数)は、空はだめですよ、といっています。

さて、modelオブジェクトを使えばvalidationをさせる仕組みは揃っているということです。
こちらを利用します。

ただし、今回のparams[:keyword]のような一時的な値の受け渡しにおいていちいちDBに保存していると時間がかかってダメです。
そこで、一時的に格納するオブジェクトを作成することで解決させます。

以下のようなclassを新たに
app/models/の中に作成します。
クラスの名前、attr_accessorの変数名は各自で設定してください。
クラスにおける変数としてattr_accessorで定義します。

class SearchForm 
  include ActiveModel::Model

  attr_accessor :keyword
  validates :keyword, presence: true
end

validates :keyword, presence: trueの部分はvalidates :keyword, presence: true, length: { maximum: 10 }のようにvalidationを追加してもよいでしょう。

ここでポイントは2点です。

  • class に < ActiveRecordがないこと
  • include ActiveModel::Model

ActiveRecordを継承しないのは、DBとやりとりをしないclassであるととらえておいて問題なさそうです。
include ActiveModel::Modelについても、このように記述すると思っておきましょう。
詳しくは追加でググりましょう。

さて、これでmodelを用意することができました。
あとはこちらのクラスを使ってインスタンス化を行えば自動的にvalidationがされるはずです。

コントローラ内にてこんな感じになると思います。
SearchFormのクラスは作ってあるため、コントローラで使えます。

word = SearchForm.new(keyword: params[:search_keyword])

newしてあげる時にparamsで値をkeywordに入れてあげましょう。
この時にvalidationが行われます。

ここで一度、rails consoleを用いてvalidationに応じていろいろと値を入れてみて試すとvalidationが行われているか確かめることができます。

>word = SerchForm.new ( keyword: "aaaaaaa")
>word.valid?

長さのvalidationをかけているならこんな感じですね。

>word = SerchForm.new ( keyword: "")

空白をチェックするならこんな感じ。

と、これでvalidationが適用されることになったので、あとはインスタンス変数の(この場合は)wordを使いましょう。
params[:keyword]としていたところをwordを使ってあげるとOKです。

参考記事

form objectを使ってみよう - メドピア開発者ブログ