Conditional Validations in Rails ActiveRecord

Conditional validations can be used when a validation needs to be run only if a condition is satisfied. This can be implemented in many ways, a few of which we will discuss in this article.

Let’s assume we have a post model in our Rails application, and a post can be published by registered users and guests.

1
2
3
4
rails new conditional_validation
rails generate model User name user_type
rails generate model Post title body:text user:belongs_to
rails db:create db:migrate

Now add validations.

Using a symbol with :if and :unless

Make sure your post.rb looks like this:

1
2
3
4
5
6
7
8
class Post < ApplicationRecord
 validates :body, length: { maximum: 100 }, if: :guest_user?
 belongs_to :user

 def guest_user?
   user.user_type == "guest"
 end
end

Test your implementation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
rails console

User.create(name: "John", user_type: "guest")
User.create(name: "Michael", user_type: "member")
user = User.first
post = Post.create(title: "A post with characters less than 100", body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do.", user_id: user.id)

# This example will not pass validation as the number of characters is above 100 and user_type is guest.

post2 = Post.create(title: "A post with characters greater than 100", body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt 
t labore et dolore magna aliqua.", user_id: user.id)

post2.valid?
=> false 

post2.errors

=> #<ActiveModel::Errors:0x00007fd68821d908 @base=#<Post id: nil, title: "A post with characters greater than 100", body: "Lorem ipsum dolor sit amet, consectetur adipiscing...", user_id: 1, created_at: nil, updated_at: nil>, @messages={:body=>["is too long (maximum is 100 characters)"]}, @details={:body=>[{:error=>:too_long, :count=>100}]}> 


# This example will create the post above 100 characters, as the user_type is a member.

user = User.last
post2 = Post.create(title: "A post with characters greater than 100", body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt 
t labore et dolore magna aliqua.", user_id: user.id)

Using a Proc with :if and :unless

Make sure your post.rb looks like this:

1
2
3
4
5
class Post < ApplicationRecord
 validates :body, length: { maximum: 100 }, if: Proc.new { |p| p.user.user_type == "guest" }
 belongs_to :user
end

Now test your implementation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
rails console

user = User.first

post = Post.create(title: "A post with characters greater than 100", body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt u
 labore et dolore magna aliqua.", user_id: user.id)
post.errors

 => #<ActiveModel::Errors:0x00007fd684e84e98 @base=#<Post id: nil, title: "A post with characters greater than 100", body: "Lorem ipsum dolor sit amet, consectetur adipiscing...", user_id: 1, created_at: nil, updated_at: nil>, @messages={:body=>["is too long (maximum is 100 characters)"]}, @details={:body=>[{:error=>:too_long, :count=>100}]}> 


user = User.last

# This example will create the post above 100 characters, as the user_type is a member.

post = Post.create(title: "A post with characters greater than 100", body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt u
 labore et dolore magna aliqua.", user_id: user.id)

Now you can validate conditionally in your Rails applications. Happy validating!