-4

With a validation on a particular attribute using validates, one can, using the :message option, specify the key to the i18n message to be used when validation fails:

In model:

class Foo < ApplicationRecord
  validates :some_attribute, ...., message: :bar
end

In locales:

en:
  activerecord:
    errors:
      models:
        foo:
          attributes:
            some_attribute:
              bar: "Blah blah"

How can I do the corresponding thing with a validation that (is not specific to a single attribute and) uses the validate method instead of validates?

sawa
  • 165,429
  • 45
  • 277
  • 381
  • You can add an specific error if the rule isn't satisfied, like `errors.add(:attribute, message) unless foo.friend_of?(bar)`, like [in](https://github.com/rails/rails/blob/master/activemodel/lib/active_model/validations.rb#L93). Or am I misunderstanding the question? – Sebastián Palma Feb 01 '18 at 11:08
  • Your question is unclear — are you trying to "set the error message automatically", or are you trying to set the error message using "locales" and the `validate` method? The former is impossible, the latter is definitely possible. – Amin Shah Gilani Feb 05 '19 at 08:28

2 Answers2

2

Using validate with a block

class Foo < ApplicationRecord
  validate do
    if ERROR_CONDITION
      errors.add(:some_attribute, :bar)
    end
  end
end

OR using validate with a method

class Foo < ApplicationRecord
  validate :some_custom_validation_name

  private

  def some_custom_validation_name
    if ERROR_CONDITION
      errors.add(:some_attribute, :bar)
    end
  end
end

errors.add can be used like the following:

  • errors.add(ATTRIBUTE_NAME, SYMBOL)

    • SYMBOL corresponds to the message name. See the message column here in this table
    • i.e. this can be :blank, :taken, :invalid, or :bar (your custom message name)

      errors.add(:some_attribute, :taken)
      # => ["has already been taken"]
      
      errors.add(:some_attribute, :invalid)
      # => ["has already been taken", "is invalid"]
      
      errors.add(:some_attribute, :bar)
      # => ["has already been taken", "is invalid", "Blah blah"]
      
  • errors.add(ATTRIBUTE_NAME, SYMBOL, HASH)

    • same as above except that you can also pass in arguments to the message. See the interpolation column here in the same table that you'll need to use.

      errors.add(:some_attribute, :too_short, count: 3)
      # => ["is too short (minimum is 3 characters)"]
      errors.add(:some_attribute, :confirmation, attribute: self.class.human_attribute_name(:first_name))
      # => ["is too short (minimum is 3 characters)", "doesn't match First name"]
      
  • errors.add(ATTRIBUTE_NAME, STRING)

    • or pass a custom message string

      errors.add(:some_attribute, 'is a bad value')
      # => ["is a bad value"]
      

Also, assuming that you intend to pass in :bar as argument to your validation like in your example, then you can use a custom validator:

# app/validators/lorem_ipsum_validator.rb
class LoremIpsumValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    if ERROR_CONDITION
      record.errors.add(attribute, options[:message])
    end
  end
end

# app/models/foo.rb
class Foo < ApplicationRecord
  validates :some_attribute, lorem_impsum: { message: :bar }
  # or multiple attributes:
  validates [:first_name, :last_name], lorem_impsum: { message: :bar }

  # you can also combine the custom validator with any other regular Rails validator like the following
  # validates :some_attribute,
  #   lorem_impsum: { message: :bar },
  #   presence: true,
  #   length: { minimum: 6 }
end
Jay-Ar Polidario
  • 6,463
  • 14
  • 28
-1

It looks like it is impossible to do that way. I have to manually add the error message in the validation method.

sawa
  • 165,429
  • 45
  • 277
  • 381
  • If by "manually add" you mean "not use locales", then you're wrong. You can certainly use locales. Please see the alternate answer for an example. This should not be the accepted answer. Please write your questions correctly, otherwise, you're wasting the efforts of people trying to help. – Amin Shah Gilani Feb 05 '19 at 08:31