Rails 7.1 Allows Validators To Accept Lambdas Without Record Argument

Rails validations are a key feature for ensuring the integrity of the data being saved to the database. They allow us to define rules for model attributes, such as requiring a value, ensuring uniqueness, or excluding specific values. Rails also allows us to use custom logic for validations by using blocks or callable objects like lambdas.

What Is a Lambda in Ruby?

A lambda is a type of Proc object in Ruby with stricter rules.

  • Argument checking: A lambda ensures the number of arguments passed matches the number expected. If not, it raises an error.
  • Return behavior: A lambda returns control back to where it was called, instead of exiting the enclosing method like a regular proc.
print_value = ->(x) { "Value: #{x}" }
print_value.call(10)       # Works fine
print_value.call(10, 20)   # Raises an ArgumentError

Before Rails 7.1

In earlier versions of Rails, lambdas used in validations required an argument, even if the argument was not needed. Without this, Rails would raise an ArgumentError.

class User < ApplicationRecord
  validates :name, exclusion: { in: -> { ["Admin"] } }
end
user = User.create!(name: "Admin")

#=> `block in <class:User>': wrong number of arguments (given 1, expected 0) (ArgumentError)

To make the above validation work, we need to pass an argument to the lambda, even though it won’t be used.

class User < ApplicationRecord
  validates :name, exclusion: { in: (_record) -> { ["Admin"] } }
end
user = User.create!(name: "Admin")

`raise_validation_error': Validation failed: Name is reserved (ActiveRecord::RecordInvalid)

This worked, but it added unnecessary complexity when the record argument wasn’t actually used.

After Rails 7.1

Rails 7.1 removed the requirement to include argument. Lambdas now work without explicitly passing arguments, simplifying validations.

class User < ApplicationRecord
  validates :name, exclusion: { in: -> { ["Admin"] } }
end
user = User.create!(name: "Admin")

`raise_validation_error': Validation failed: is reserved (ActiveRecord::RecordInvalid)(ActiveRecord::RecordInvalid)

This change eliminates the need for extra arguments in lambdas, making the code easier to read and maintain.

Need help on your Ruby on Rails or React project?

Join Our Newsletter