def generate_message(attribute, type = :invalid, options = {})
      type = options.delete(:message) if options[:message].is_a?(Symbol)
      value = (attribute != :base ? @base.send(:read_attribute_for_validation, attribute) : nil)

      options = {
        model: @base.model_name.human,
        attribute: @base.class.human_attribute_name(attribute),
        value: value,
        object: @base
      }.merge!(options)

      if @base.class.respond_to?(:i18n_scope)
        i18n_scope = @base.class.i18n_scope.to_s
        defaults = @base.class.lookup_ancestors.flat_map do |klass|
          [ :"#{i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{type}",
            :"#{i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ]
        end
        defaults << :"#{i18n_scope}.errors.messages.#{type}"

        catch(:exception) do
          translation = I18n.translate(defaults.first, options.merge(default: defaults.drop(1), throw: true))
          return translation unless translation.nil?
        end unless options[:message]
      else
        defaults = []
      end

      defaults << :"errors.attributes.#{attribute}.#{type}"
      defaults << :"errors.messages.#{type}"

      key = defaults.shift
      defaults = options.delete(:message) if options[:message]
      options[:default] = defaults

      I18n.translate(key, options)
    end
def generate_message(attribute, type = :invalid, options = {})
      type = options.delete(:message) if options[:message].is_a?(Symbol)
      value = (attribute != :base ? @base.send(:read_attribute_for_validation, attribute) : nil)

      options = {
        model: @base.model_name.human,
        attribute: @base.class.human_attribute_name(attribute),
        value: value,
        object: @base
      }.merge!(options)

      if @base.class.respond_to?(:i18n_scope)
        i18n_scope = @base.class.i18n_scope.to_s
        defaults = @base.class.lookup_ancestors.flat_map do |klass|
          [ :"#{i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{type}",
            :"#{i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ]
        end
        defaults << :"#{i18n_scope}.errors.messages.#{type}"

        catch(:exception) do
          translation = I18n.translate(defaults.first, options.merge(default: defaults.drop(1), throw: true))
          return translation unless translation.nil?
        end unless options[:message]
      else
        defaults = []
      end

      defaults << :"errors.attributes.#{attribute}.#{type}"
      defaults << :"errors.messages.#{type}"

      key = defaults.shift
      defaults = options.delete(:message) if options[:message]
      options[:default] = defaults

      I18n.translate(key, options)
    end
Translates an error message in its default scope
 (<tt>activemodel.errors.messages</tt>).

 Error messages are first looked up in <tt>activemodel.errors.models.MODEL.attributes.ATTRIBUTE.MESSAGE</tt>,
 if it's not there, it's looked up in <tt>activemodel.errors.models.MODEL.MESSAGE</tt> and if
 that is not there also, it returns the translation of the default message
 (e.g. <tt>activemodel.errors.messages.MESSAGE</tt>). The translated model
 name, translated attribute name and the value are available for
 interpolation.

 When using inheritance in your models, it will check all the inherited
 models too, but only if the model itself hasn't been found. Say you have
 <tt>class Admin < User; end</tt> and you wanted the translation for
 the <tt>:blank</tt> error message for the <tt>title</tt> attribute,
 it looks for these translations:

 * <tt>activemodel.errors.models.admin.attributes.title.blank</tt>
 * <tt>activemodel.errors.models.admin.blank</tt>
 * <tt>activemodel.errors.models.user.attributes.title.blank</tt>
 * <tt>activemodel.errors.models.user.blank</tt>
 * any default you provided through the +options+ hash (in the <tt>activemodel.errors</tt> scope)
 * <tt>activemodel.errors.messages.blank</tt>
 * <tt>errors.attributes.title.blank</tt>
 * <tt>errors.messages.blank</tt>