Tbpgr Blog

元エンジニア 人事 tbpgr(てぃーびー) のブログ

Ruby on Rails | Validation | conditional

概要

conditional

詳細

ActiveRecord で、validation時に if や unless を利用することで、
特定の条件下での validation を行うことができます。

サンプル

テーブル定義
CREATE TABLE "articles" (
  "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
  "title" varchar(255), 
  "text" text, 
  "created_at" datetime, 
  "updated_at" datetime
);
Validation その1

titleが5文字より大きい場合のみ、数値を強要する

class Article < ActiveRecord::Base
  has_many :comments, dependent: :destroy
  validates :title, numericality: { only_integer: true }, :if => :over_five?

  def over_five?
    return false if title.nil?
    title.size > 5
  end
end
試行 その1

rails console(pry)で試行します。

[1] pry(main)> a = Article.new
=> #<Article id: nil, title: nil, text: nil, created_at: nil, updated_at: nil>
[2] pry(main)> a.title = 'abcde'
=> "abcde"
[3] pry(main)> a.valid?
=> true
[4] pry(main)> a.title = 'abcdef'
=> "abcdef"
[5] pry(main)> a.valid?
=> false
[6] pry(main)> a.errors.messages
=> {:title=>["is not a number"]}
[7] pry(main)> a.title = 123456
=> 123456
[8] pry(main)> a.valid?
=> true
Validation その2

titleが5文字以下の場合のみ、数値を強要する

class Article < ActiveRecord::Base
  has_many :comments, dependent: :destroy
  validates :title, numericality: { only_integer: true }, :unless => :over_five?

  def over_five?
    return false if title.nil?
    title.size > 5
  end
end
試行 その2

rails console(pry)で試行します。

[1] pry(main)> a = Article.new
=> #<Article id: nil, title: nil, text: nil, created_at: nil, updated_at: nil>
[2] pry(main)> a.title = 'abcdef'
=> "abcdef"
[3] pry(main)> a.valid?
=> true
[4] pry(main)> a.title = 'abcde'
=> "abcde"
[5] pry(main)> a.valid?
=> false
[6] pry(main)> a.errors.messages
=> {:title=>["is not a number"]}
[7] pry(main)> a.title = 12345
=> 12345
[8] pry(main)> a.valid?
=> true
Validation その3

titleが5文字より大きい場合のみ、数値を強要する
(if: evalの文法を利用)

class Article < ActiveRecord::Base
  has_many :comments, dependent: :destroy
  validates :title, numericality: { only_integer: true }, :if => "title.nil? ? false : (title.size > 5)"
end
試行 その3

rails console(pry)で試行します。

[1] pry(main)> a = Article.new
=> #<Article id: nil, title: nil, text: nil, created_at: nil, updated_at: nil>
[2] pry(main)> a.title = 'abcde'
=> "abcde"
[3] pry(main)> a.valid?
=> true
[4] pry(main)> a.title = 'abcdef'
=> "abcdef"
[5] pry(main)> a.valid?
=> false
[6] pry(main)> a.errors.messages
=> {:title=>["is not a number"]}
[7] pry(main)> a.title = 123456
=> 123456
[8] pry(main)> a.valid?
=> true
Validation その4

titleが5文字より大きい場合のみ、数値を強要する
(if: Procの文法を利用)

class Article < ActiveRecord::Base
  has_many :comments, dependent: :destroy
  validates :title, numericality: { only_integer: true }, :if => Proc.new { |a|a.title.nil? ? false : (a.title.size > 5) }
end
試行 その4

rails console(pry)で試行します。

[1] pry(main)> a = Article.new
=> #<Article id: nil, title: nil, text: nil, created_at: nil, updated_at: nil>
[2] pry(main)> a.title = 'abcde'
=> "abcde"
[3] pry(main)> a.valid?
=> true
[4] pry(main)> a.title = 'abcdef'
=> "abcdef"
[5] pry(main)> a.valid?
=> false
[6] pry(main)> a.errors.messages
=> {:title=>["is not a number"]}
[7] pry(main)> a.title = 123456
=> 123456
[8] pry(main)> a.valid?
=> true
Validation その5

titleが5文字より大きい場合のみ、title/textに数値を強要する

class Article < ActiveRecord::Base
  has_many :comments, dependent: :destroy
  with_options :if => :over_five? do |a|
    a.validates :title, numericality: { only_integer: true }
    a.validates :text, numericality: { only_integer: true }
  end

  def over_five?
    return false if title.nil?
    title.size > 5
  end
end
試行 その5

rails console(pry)で試行します。

[1] pry(main)> a = Article.new
=> #<Article id: nil, title: nil, text: nil, created_at: nil, updated_at: nil>
[2] pry(main)> a.title = 'abcde'
=> "abcde"
[3] pry(main)> a.text = 'abcde'
=> "abcde"
[4] pry(main)> a.valid?
=> true
[5] pry(main)> a.title = 'abcdef'
=> "abcdef"
[6] pry(main)> a.text = 'abcdef'
=> "abcdef"
[7] pry(main)> a.valid?
=> false
[8] pry(main)> a.errors.messages
=> {:title=>["is not a number"], :text=>["is not a number"]}
[9] pry(main)> a.title = 123456
=> 123456
[10] pry(main)> a.text = 123456
=> 123456
[11] pry(main)> a.valid?
=> true
Validation その6

titleが5文字より大きい場合のみ、titleに数値を強要する
(if, unlessを同時に使用してみる)

class Article < ActiveRecord::Base
  has_many :comments, dependent: :destroy
  validates :title, numericality: { only_integer: true },
    :if => Proc.new { |a|a.title.present? },
    :unless => Proc.new { |a|a.title.size <= 5 }
end
試行 その6

rails console(pry)で試行します。

[1] pry(main)> a = Article.new
=> #<Article id: nil, title: nil, text: nil, created_at: nil, updated_at: nil>
[2] pry(main)> a.title = 'abcde'
=> "abcde"
[3] pry(main)> a.valid?
=> true
[4] pry(main)> a.title = 'abcdef'
=> "abcdef"
[5] pry(main)> a.valid?
=> false
[6] pry(main)> a.errors.messages
=> {:title=>["is not a number"]}
[7] pry(main)> a.title = 123456
=> 123456
[8] pry(main)> a.valid?
=> true