diff options
Diffstat (limited to 'activemodel/lib/active_model')
-rw-r--r-- | activemodel/lib/active_model/attribute_methods.rb | 6 | ||||
-rw-r--r-- | activemodel/lib/active_model/errors.rb | 47 | ||||
-rw-r--r-- | activemodel/lib/active_model/secure_password.rb | 4 | ||||
-rw-r--r-- | activemodel/lib/active_model/serialization.rb | 27 | ||||
-rw-r--r-- | activemodel/lib/active_model/serializers/json.rb | 4 | ||||
-rw-r--r-- | activemodel/lib/active_model/validations/validates.rb | 4 | ||||
-rw-r--r-- | activemodel/lib/active_model/validations/with.rb | 2 | ||||
-rw-r--r-- | activemodel/lib/active_model/validator.rb | 6 |
8 files changed, 70 insertions, 30 deletions
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb index a201e983cd..ef0b95424e 100644 --- a/activemodel/lib/active_model/attribute_methods.rb +++ b/activemodel/lib/active_model/attribute_methods.rb @@ -93,10 +93,10 @@ module ActiveModel # # Provides you with: # - # AttributePerson.primary_key + # Person.primary_key # # => "sysid" - # AttributePerson.inheritance_column = 'address' - # AttributePerson.inheritance_column + # Person.inheritance_column = 'address' + # Person.inheritance_column # # => 'address_id' def define_attr_method(name, value=nil, &block) sing = singleton_class diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index d91e4a2b6a..8337b04c0d 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -205,21 +205,14 @@ module ActiveModel messages.dup end - # Adds +message+ to the error messages on +attribute+, which will be returned on a call to - # <tt>on(attribute)</tt> for the same attribute. More than one error can be added to the same - # +attribute+ in which case an array will be returned on a call to <tt>on(attribute)</tt>. + # Adds +message+ to the error messages on +attribute+. More than one error can be added to the same + # +attribute+. # If no +message+ is supplied, <tt>:invalid</tt> is assumed. # # If +message+ is a symbol, it will be translated using the appropriate scope (see +translate_error+). # If +message+ is a proc, it will be called, allowing for things like <tt>Time.now</tt> to be used within an error. def add(attribute, message = nil, options = {}) - message ||= :invalid - - if message.is_a?(Symbol) - message = generate_message(attribute, message, options.except(*CALLBACKS_OPTIONS)) - elsif message.is_a?(Proc) - message = message.call - end + message = normalize_message(attribute, message, options) if options[:strict] raise ActiveModel::StrictValidationFailed, message end @@ -244,6 +237,15 @@ module ActiveModel end end + # Returns true if an error on the attribute with the given message is present, false otherwise. + # +message+ is treated the same as for +add+. + # p.errors.add :name, :blank + # p.errors.added? :name, :blank # => true + def added?(attribute, message = nil, options = {}) + message = normalize_message(attribute, message, options) + self[attribute].include? message + end + # Returns all the full error messages in an array. # # class Company @@ -300,13 +302,17 @@ module ActiveModel def generate_message(attribute, type = :invalid, options = {}) type = options.delete(:message) if options[:message].is_a?(Symbol) - defaults = @base.class.lookup_ancestors.map do |klass| - [ :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{type}", - :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ] + if @base.class.respond_to?(:i18n_scope) + defaults = @base.class.lookup_ancestors.map do |klass| + [ :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{type}", + :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ] + end + else + defaults = [] end defaults << options.delete(:message) - defaults << :"#{@base.class.i18n_scope}.errors.messages.#{type}" + defaults << :"#{@base.class.i18n_scope}.errors.messages.#{type}" if @base.class.respond_to?(:i18n_scope) defaults << :"errors.attributes.#{attribute}.#{type}" defaults << :"errors.messages.#{type}" @@ -325,6 +331,19 @@ module ActiveModel I18n.translate(key, options) end + + private + def normalize_message(attribute, message, options) + message ||= :invalid + + if message.is_a?(Symbol) + generate_message(attribute, message, options.except(*CALLBACKS_OPTIONS)) + elsif message.is_a?(Proc) + message.call + else + message + end + end end class StrictValidationFailed < StandardError diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb index 7a109d9a52..db78864c67 100644 --- a/activemodel/lib/active_model/secure_password.rb +++ b/activemodel/lib/active_model/secure_password.rb @@ -32,8 +32,8 @@ module ActiveModel # User.find_by_name("david").try(:authenticate, "notright") # => nil # User.find_by_name("david").try(:authenticate, "mUc3m00RsqyRe") # => user def has_secure_password - # Load bcrypt-ruby only when has_secured_password is used to avoid make ActiveModel - # (and by extension the entire framework) dependent on a binary library. + # Load bcrypt-ruby only when has_secure_password is used. + # This is to avoid ActiveModel (and by extension the entire framework) being dependent on a binary library. gem 'bcrypt-ruby', '~> 3.0.0' require 'bcrypt' diff --git a/activemodel/lib/active_model/serialization.rb b/activemodel/lib/active_model/serialization.rb index a756b9f205..a4b58ab456 100644 --- a/activemodel/lib/active_model/serialization.rb +++ b/activemodel/lib/active_model/serialization.rb @@ -78,7 +78,8 @@ module ActiveModel attribute_names -= Array.wrap(except).map(&:to_s) end - hash = attributes.slice(*attribute_names) + hash = {} + attribute_names.each { |n| hash[n] = read_attribute_for_serialization(n) } method_names = Array.wrap(options[:methods]).select { |n| respond_to?(n) } method_names.each { |n| hash[n] = send(n) } @@ -95,17 +96,37 @@ module ActiveModel end private + + # Hook method defining how an attribute value should be retrieved for + # serialization. By default this is assumed to be an instance named after + # the attribute. Override this method in subclasses should you need to + # retrieve the value for a given attribute differently: + # + # class MyClass + # include ActiveModel::Validations + # + # def initialize(data = {}) + # @data = data + # end + # + # def read_attribute_for_serialization(key) + # @data[key] + # end + # end + # + alias :read_attribute_for_serialization :send + # Add associations specified via the <tt>:include</tt> option. # # Expects a block that takes as arguments: # +association+ - name of the association # +records+ - the association record(s) to be serialized # +opts+ - options for the association records - def serializable_add_includes(options = {}) + def serializable_add_includes(options = {}) #:nodoc: return unless include = options[:include] unless include.is_a?(Hash) - include = Hash[Array.wrap(include).map { |n| [n, {}] }] + include = Hash[Array.wrap(include).map { |n| n.is_a?(Hash) ? n.to_a.first : [n, {}] }] end include.each do |association, opts| diff --git a/activemodel/lib/active_model/serializers/json.rb b/activemodel/lib/active_model/serializers/json.rb index 885964633f..c845440120 100644 --- a/activemodel/lib/active_model/serializers/json.rb +++ b/activemodel/lib/active_model/serializers/json.rb @@ -15,7 +15,7 @@ module ActiveModel self.include_root_in_json = true end - # Returns a JSON string representing the model. Some configuration can be + # Returns a hash representing the model. Some configuration can be # passed through +options+. # # The option <tt>include_root_in_json</tt> controls the top-level behavior @@ -42,7 +42,7 @@ module ActiveModel # The remainder of the examples in this section assume include_root_in_json is set to # <tt>false</tt>. # - # Without any +options+, the returned JSON string will include all the model's + # Without any +options+, the returned Hash will include all the model's # attributes. For example: # # user = User.find(1) diff --git a/activemodel/lib/active_model/validations/validates.rb b/activemodel/lib/active_model/validations/validates.rb index b85c2453fb..fbceb81e8f 100644 --- a/activemodel/lib/active_model/validations/validates.rb +++ b/activemodel/lib/active_model/validations/validates.rb @@ -27,7 +27,7 @@ module ActiveModel # # class EmailValidator < ActiveModel::EachValidator # def validate_each(record, attribute, value) - # record.errors[attribute] << (options[:message] || "is not an email") unless + # record.errors.add attribute, (options[:message] || "is not an email") unless # value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i # end # end @@ -48,7 +48,7 @@ module ActiveModel # # class TitleValidator < ActiveModel::EachValidator # def validate_each(record, attribute, value) - # record.errors[attribute] << "must start with 'the'" unless value =~ /\Athe/i + # record.errors.add attribute, "must start with 'the'" unless value =~ /\Athe/i # end # end # diff --git a/activemodel/lib/active_model/validations/with.rb b/activemodel/lib/active_model/validations/with.rb index 83aae206a6..93a340eb39 100644 --- a/activemodel/lib/active_model/validations/with.rb +++ b/activemodel/lib/active_model/validations/with.rb @@ -32,7 +32,7 @@ module ActiveModel # class MyValidator < ActiveModel::Validator # def validate(record) # if some_complex_logic - # record.errors[:base] << "This record is invalid" + # record.errors.add :base, "This record is invalid" # end # end # diff --git a/activemodel/lib/active_model/validator.rb b/activemodel/lib/active_model/validator.rb index 5304743389..0e444738ba 100644 --- a/activemodel/lib/active_model/validator.rb +++ b/activemodel/lib/active_model/validator.rb @@ -48,8 +48,8 @@ module ActiveModel #:nodoc: # # class MyValidator < ActiveModel::Validator # def validate(record) - # record.errors[:base] << "This is some custom error message" - # record.errors[:first_name] << "This is some complex validation" + # record.errors.add :base, "This is some custom error message" + # record.errors.add :first_name, "This is some complex validation" # # etc... # end # end @@ -68,7 +68,7 @@ module ActiveModel #:nodoc: # # class TitleValidator < ActiveModel::EachValidator # def validate_each(record, attribute, value) - # record.errors[attribute] << 'must be Mr. Mrs. or Dr.' unless value.in?(['Mr.', 'Mrs.', 'Dr.']) + # record.errors.add attribute, 'must be Mr. Mrs. or Dr.' unless value.in?(['Mr.', 'Mrs.', 'Dr.']) # end # end # |