Rails Model Validation

Validation

ActiveModel::Validations::XxxxxValidator class.
Check model attributes.

  • acceptance
  • confirmation
  • exclusion
  • inclusion
  • format
  • length
  • numericality
  • presence
  • absence
  • uniqueness

Example and Basics

Data

title 		presence, length 1 - 100
price		integer < 10000
category    candidate  A/B/C/D/E

Model

class Item < ActiveRecord::Base
  validates :title,
    presence: true,
	length: { minimum: 1, maximum: 100 }
  validates :price,
    numericality: { only_integer: true, less_than: 10000 }
  validates :category,
    includesion: { in:&#91;'A','B','C','D', 'E'&#93; }
end
&#91;/ruby&#93;

Model create
&#91;ruby&#93;
def create
  @item = Item.new(item_params)
  respond_to do |format|
    if @item.save
	  # success
	else
	  # fail
	end
  end
end
&#91;/ruby&#93;

validation is executed when save is called.

<h4>Apply validation</h4>
create, create!, save, save!, update, update!

<h3>Show error in view</h3>
create, create!, save, save!, update, update!
[ruby]
<% if @item.errors.any? %>
  <div id="error_explanation">
    <h2><%= pluralize(@item.errors.count, "error") %> prohibited this
	item from being saved</h2>
	<ul>
	  <% @item.errors.full_message.each do |msg| %>
	    <li><%= msg %></li>
	  <% end %>
	</ul>
  </div>
<% end %>

acceptance

Allow user regulation : No need to add database attr
Example) User Info(users_controller.rb)

def user_params
  params.require(:user).permit(:username, :password, :email, :agreement)
end

Model

class User < ActiveRecord::Base
  validates :agreement, acceptance: true
end
&#91;/ruby&#93;
users/_form.html.erb
&#91;ruby&#93;
<%= f.text_field :roles %>
<div class="field">
  <%= f.label :agreement %><br>
  <%= f.check_box :agreement %>
</div>
<div class="actions">
  <%= f.submit %>
</div>

confirmation

password, email double input check

users_controller.rb

def user_params
  params.require(:user).permit(:username, :password, :email, :email_confirmation, :agreement)
end

user.rb

class User < ActiveRecord::Base
  validates :email, confirmation: true
end
&#91;/ruby&#93;
users/_form.html.erb
&#91;ruby&#93;
<div class="field">
  <%= f.label :email %><br>
  <%= f.text_field :email %>
</div>
<div class="field">
  <%= f.label :email_confirmation %><br>
  <%= f.text_field :email_confirmation %>
</div>

Use field with _confirmation as confirmation
xxxxxx
xxxxxx_confirmation

uniqueness

validate :name, uniqueness: { scope: :team }

We can add scope
name is unique within team, team is other column

Validation parameters

Examples

parameter description
allow_nil if nil, skip validation
allow_blank if blank, skip validation
message error message
on validation timing(create, update, save)
if if true, do validation
unless if true, do validation

How to use

validates :uid,    # column
  presence: true,
  uniqueness: { allow_blank: true },
  length: { is: 20, allow_blank: true }

acceptance should be applied only create

class User < ActiveRecord::Base
  validates :agreement, acceptance: { on: :create }
end
&#91;/ruby&#93;

<h4>message</h4>
[ruby]
class Item < ActiveRecord::Base
  validates: :name,
    presence: { message: 'is required'},
	uniqueness: { allow_blank: true, message '%{value} is unique' }
end
&#91;/ruby&#93;

<h4>if/unless</h4>
[ruby]
class User < ActiveRecord::Base
  validates :email, presence: { unless: 'letter.blank?' }
end

&#91;/ruby&#93;
If the letter isn't blank, check email presence

<hr>
<h3>My Validation class</h3>
The class should be extended <strong>ActiveModel::EachValidator</strong>
[ruby]
class TitleValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    record.errors.add(attribute, ' is not correct') unless value.length < 0
  end
end
&#91;/ruby&#93;
record : target object
attribute : field name
value : value

<h4>How to use</h4>
validation name is class name from Validator
In case of above, <strong>title</strong> is validation name
[ruby]
validates :title,
  presence: true,
  title: true

How to get parameter from validation

option[:parametername: true}

title: { parametername: true }