diff options
Diffstat (limited to 'activemodel/lib')
-rw-r--r-- | activemodel/lib/active_model/conversion.rb | 4 | ||||
-rw-r--r-- | activemodel/lib/active_model/dirty.rb | 3 | ||||
-rw-r--r-- | activemodel/lib/active_model/lint.rb | 8 | ||||
-rw-r--r-- | activemodel/lib/active_model/mass_assignment_security.rb | 18 | ||||
-rw-r--r-- | activemodel/lib/active_model/mass_assignment_security/sanitizer.rb | 12 | ||||
-rw-r--r-- | activemodel/lib/active_model/naming.rb | 40 | ||||
-rw-r--r-- | activemodel/lib/active_model/serialization.rb | 16 | ||||
-rw-r--r-- | activemodel/lib/active_model/validations/clusivity.rb | 31 | ||||
-rw-r--r-- | activemodel/lib/active_model/validations/exclusion.rb | 26 | ||||
-rw-r--r-- | activemodel/lib/active_model/validations/inclusion.rb | 26 |
10 files changed, 88 insertions, 96 deletions
diff --git a/activemodel/lib/active_model/conversion.rb b/activemodel/lib/active_model/conversion.rb index c7c805f1a2..d7f30f0920 100644 --- a/activemodel/lib/active_model/conversion.rb +++ b/activemodel/lib/active_model/conversion.rb @@ -21,7 +21,7 @@ module ActiveModel # cm.to_model == self # => true # cm.to_key # => nil # cm.to_param # => nil - # cm.to_path # => "contact_messages/contact_message" + # cm.to_partial_path # => "contact_messages/contact_message" # module Conversion extend ActiveSupport::Concern @@ -57,7 +57,7 @@ module ActiveModel end module ClassMethods #:nodoc: - # Provide a class level cache for the to_path. This is an + # Provide a class level cache for #to_partial_path. This is an # internal method and should not be accessed directly. def _to_partial_path #:nodoc: @_to_partial_path ||= begin diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb index 026f077ee7..d327913824 100644 --- a/activemodel/lib/active_model/dirty.rb +++ b/activemodel/lib/active_model/dirty.rb @@ -1,6 +1,7 @@ require 'active_model/attribute_methods' require 'active_support/hash_with_indifferent_access' require 'active_support/core_ext/object/duplicable' +require 'active_support/core_ext/object/blank' module ActiveModel # == Active Model Dirty @@ -98,7 +99,7 @@ module ActiveModel # person.name = 'bob' # person.changed? # => true def changed? - changed_attributes.any? + changed_attributes.present? end # List of attributes with unsaved changes. diff --git a/activemodel/lib/active_model/lint.rb b/activemodel/lib/active_model/lint.rb index a10fdefd1a..88b730626c 100644 --- a/activemodel/lib/active_model/lint.rb +++ b/activemodel/lib/active_model/lint.rb @@ -78,10 +78,10 @@ module ActiveModel def test_model_naming assert model.class.respond_to?(:model_name), "The model should respond to model_name" model_name = model.class.model_name - assert_kind_of String, model_name - assert_kind_of String, model_name.human - assert_kind_of String, model_name.singular - assert_kind_of String, model_name.plural + assert model_name.respond_to?(:to_str) + assert model_name.human.respond_to?(:to_str) + assert model_name.singular.respond_to?(:to_str) + assert model_name.plural.respond_to?(:to_str) end # == Errors Testing diff --git a/activemodel/lib/active_model/mass_assignment_security.rb b/activemodel/lib/active_model/mass_assignment_security.rb index 95de039676..5e5405fe27 100644 --- a/activemodel/lib/active_model/mass_assignment_security.rb +++ b/activemodel/lib/active_model/mass_assignment_security.rb @@ -85,7 +85,7 @@ module ActiveModel # end # end # - # When using the :default role : + # When using the :default role: # # customer = Customer.new # customer.assign_attributes({ "name" => "David", "email" => "a@b.com", :logins_count => 5 }, :as => :default) @@ -93,7 +93,7 @@ module ActiveModel # customer.email # => "a@b.com" # customer.logins_count # => nil # - # And using the :admin role : + # And using the :admin role: # # customer = Customer.new # customer.assign_attributes({ "name" => "David", "email" => "a@b.com", :logins_count => 5}, :as => :admin) @@ -107,8 +107,9 @@ module ActiveModel # To start from an all-closed default and enable attributes as needed, # have a look at +attr_accessible+. # - # Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of +attr_protected+ - # to sanitize attributes won't provide sufficient protection. + # Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of + # +attr_protected+ to sanitize attributes provides basically the same + # functionality, but it makes a bit tricky to deal with nested attributes. def attr_protected(*args) options = args.extract_options! role = options[:as] || :default @@ -152,7 +153,7 @@ module ActiveModel # end # end # - # When using the :default role : + # When using the :default role: # # customer = Customer.new # customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :default) @@ -162,15 +163,16 @@ module ActiveModel # customer.credit_rating = "Average" # customer.credit_rating # => "Average" # - # And using the :admin role : + # And using the :admin role: # # customer = Customer.new # customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :admin) # customer.name # => "David" # customer.credit_rating # => "Excellent" # - # Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of +attr_accessible+ - # to sanitize attributes won't provide sufficient protection. + # Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of + # +attr_accessible+ to sanitize attributes provides basically the same + # functionality, but it makes a bit tricky to deal with nested attributes. def attr_accessible(*args) options = args.extract_options! role = options[:as] || :default diff --git a/activemodel/lib/active_model/mass_assignment_security/sanitizer.rb b/activemodel/lib/active_model/mass_assignment_security/sanitizer.rb index cfeb4aa7cd..4491e07a72 100644 --- a/activemodel/lib/active_model/mass_assignment_security/sanitizer.rb +++ b/activemodel/lib/active_model/mass_assignment_security/sanitizer.rb @@ -3,18 +3,16 @@ module ActiveModel class Sanitizer # Returns all attributes not denied by the authorizer. def sanitize(attributes, authorizer) - sanitized_attributes = attributes.reject { |key, value| authorizer.deny?(key) } - debug_protected_attribute_removal(attributes, sanitized_attributes) + rejected = [] + sanitized_attributes = attributes.reject do |key, value| + rejected << key if authorizer.deny?(key) + end + process_removed_attributes(rejected) unless rejected.empty? sanitized_attributes end protected - def debug_protected_attribute_removal(attributes, sanitized_attributes) - removed_keys = attributes.keys - sanitized_attributes.keys - process_removed_attributes(removed_keys) if removed_keys.any? - end - def process_removed_attributes(attrs) raise NotImplementedError, "#process_removed_attributes(attrs) suppose to be overwritten" end diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb index 755e54efcd..adf000e53c 100644 --- a/activemodel/lib/active_model/naming.rb +++ b/activemodel/lib/active_model/naming.rb @@ -2,38 +2,40 @@ require 'active_support/inflector' require 'active_support/core_ext/hash/except' require 'active_support/core_ext/module/introspection' require 'active_support/core_ext/module/deprecation' +require 'active_support/core_ext/module/delegation' +require 'active_support/core_ext/object/blank' module ActiveModel - class Name < String - attr_reader :singular, :plural, :element, :collection, :partial_path, - :singular_route_key, :route_key, :param_key, :i18n_key + class Name + include Comparable + + attr_reader :singular, :plural, :element, :collection, + :singular_route_key, :route_key, :param_key, :i18n_key, + :name alias_method :cache_key, :collection - deprecate :partial_path => "ActiveModel::Name#partial_path is deprecated. Call #to_partial_path on model instances directly instead." + delegate :==, :===, :<=>, :=~, :"!~", :eql?, :to_s, + :to_str, :to => :name def initialize(klass, namespace = nil, name = nil) - name ||= klass.name - - raise ArgumentError, "Class name cannot be blank. You need to supply a name argument when anonymous class given" if name.blank? + @name = name || klass.name - super(name) + raise ArgumentError, "Class name cannot be blank. You need to supply a name argument when anonymous class given" if @name.blank? - @unnamespaced = self.sub(/^#{namespace.name}::/, '') if namespace + @unnamespaced = @name.sub(/^#{namespace.name}::/, '') if namespace @klass = klass - @singular = _singularize(self).freeze - @plural = ActiveSupport::Inflector.pluralize(@singular).freeze - @element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self)).freeze - @human = ActiveSupport::Inflector.humanize(@element).freeze - @collection = ActiveSupport::Inflector.tableize(self).freeze - @partial_path = "#{@collection}/#{@element}".freeze - @param_key = (namespace ? _singularize(@unnamespaced) : @singular).freeze - @i18n_key = self.underscore.to_sym + @singular = _singularize(@name) + @plural = ActiveSupport::Inflector.pluralize(@singular) + @element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(@name)) + @human = ActiveSupport::Inflector.humanize(@element) + @collection = ActiveSupport::Inflector.tableize(@name) + @param_key = (namespace ? _singularize(@unnamespaced) : @singular) + @i18n_key = @name.underscore.to_sym @route_key = (namespace ? ActiveSupport::Inflector.pluralize(@param_key) : @plural.dup) - @singular_route_key = ActiveSupport::Inflector.singularize(@route_key).freeze + @singular_route_key = ActiveSupport::Inflector.singularize(@route_key) @route_key << "_index" if @plural == @singular - @route_key.freeze end # Transform the model name into a more humane format, using I18n. By default, diff --git a/activemodel/lib/active_model/serialization.rb b/activemodel/lib/active_model/serialization.rb index 51f078e662..4323ee1e09 100644 --- a/activemodel/lib/active_model/serialization.rb +++ b/activemodel/lib/active_model/serialization.rb @@ -1,7 +1,5 @@ require 'active_support/core_ext/hash/except' require 'active_support/core_ext/hash/slice' -require 'active_support/core_ext/array/wrap' - module ActiveModel # == Active Model Serialization @@ -11,7 +9,6 @@ module ActiveModel # A minimal implementation could be: # # class Person - # # include ActiveModel::Serialization # # attr_accessor :name @@ -19,7 +16,6 @@ module ActiveModel # def attributes # {'name' => nil} # end - # # end # # Which would provide you with: @@ -43,7 +39,6 @@ module ActiveModel # So a minimal implementation including XML and JSON would be: # # class Person - # # include ActiveModel::Serializers::JSON # include ActiveModel::Serializers::Xml # @@ -52,7 +47,6 @@ module ActiveModel # def attributes # {'name' => nil} # end - # # end # # Which would provide you with: @@ -88,7 +82,7 @@ module ActiveModel method_names.each { |n| hash[n.to_s] = send(n) } serializable_add_includes(options) do |association, records, opts| - hash[association] = if records.is_a?(Enumerable) + hash[association.to_s] = if records.is_a?(Enumerable) records.map { |a| a.serializable_hash(opts) } else records.serializable_hash(opts) @@ -126,13 +120,13 @@ module ActiveModel # +records+ - the association record(s) to be serialized # +opts+ - options for the association records def serializable_add_includes(options = {}) #:nodoc: - return unless include = options[:include] + return unless includes = options[:include] - unless include.is_a?(Hash) - include = Hash[Array.wrap(include).map { |n| n.is_a?(Hash) ? n.to_a.first : [n, {}] }] + unless includes.is_a?(Hash) + includes = Hash[Array(includes).map { |n| n.is_a?(Hash) ? n.to_a.first : [n, {}] }] end - include.each do |association, opts| + includes.each do |association, opts| if records = send(association) yield association, records, opts end diff --git a/activemodel/lib/active_model/validations/clusivity.rb b/activemodel/lib/active_model/validations/clusivity.rb new file mode 100644 index 0000000000..b632a2bd6b --- /dev/null +++ b/activemodel/lib/active_model/validations/clusivity.rb @@ -0,0 +1,31 @@ +require 'active_support/core_ext/range.rb' + +module ActiveModel + module Validations + module Clusivity + ERROR_MESSAGE = "An object with the method #include? or a proc or lambda is required, " << + "and must be supplied as the :in option of the configuration hash" + + def check_validity! + unless [:include?, :call].any?{ |method| options[:in].respond_to?(method) } + raise ArgumentError, ERROR_MESSAGE + end + end + + private + + def include?(record, value) + delimiter = options[:in] + exclusions = delimiter.respond_to?(:call) ? delimiter.call(record) : delimiter + exclusions.send(inclusion_method(exclusions), value) + end + + # In Ruby 1.9 <tt>Range#include?</tt> on non-numeric ranges checks all possible values in the + # range for equality, so it may be slow for large ranges. The new <tt>Range#cover?</tt> + # uses the previous logic of comparing a value with the range endpoints. + def inclusion_method(enumerable) + enumerable.is_a?(Range) ? :cover? : :include? + end + end + end +end diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb index 644cc814a7..5fedb1978b 100644 --- a/activemodel/lib/active_model/validations/exclusion.rb +++ b/activemodel/lib/active_model/validations/exclusion.rb @@ -1,35 +1,17 @@ -require 'active_support/core_ext/range' +require "active_model/validations/clusivity" module ActiveModel # == Active Model Exclusion Validator module Validations class ExclusionValidator < EachValidator - ERROR_MESSAGE = "An object with the method #include? or a proc or lambda is required, " << - "and must be supplied as the :in option of the configuration hash" - - def check_validity! - unless [:include?, :call].any? { |method| options[:in].respond_to?(method) } - raise ArgumentError, ERROR_MESSAGE - end - end + include Clusivity def validate_each(record, attribute, value) - delimiter = options[:in] - exclusions = delimiter.respond_to?(:call) ? delimiter.call(record) : delimiter - if exclusions.send(inclusion_method(exclusions), value) + if include?(record, value) record.errors.add(attribute, :exclusion, options.except(:in).merge!(:value => value)) end end - - private - - # In Ruby 1.9 <tt>Range#include?</tt> on non-numeric ranges checks all possible values in the - # range for equality, so it may be slow for large ranges. The new <tt>Range#cover?</tt> - # uses the previous logic of comparing a value with the range endpoints. - def inclusion_method(enumerable) - enumerable.is_a?(Range) ? :cover? : :include? - end end module HelperMethods @@ -59,7 +41,7 @@ module ActiveModel # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. - # * <tt>:strict</tt> - Specifies whether validation should be strict. + # * <tt>:strict</tt> - Specifies whether validation should be strict. # See <tt>ActiveModel::Validation#validates!</tt> for more information def validates_exclusion_of(*attr_names) validates_with ExclusionValidator, _merge_attributes(attr_names) diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb index 147e2ecb69..15ae7b1959 100644 --- a/activemodel/lib/active_model/validations/inclusion.rb +++ b/activemodel/lib/active_model/validations/inclusion.rb @@ -1,35 +1,17 @@ -require 'active_support/core_ext/range' +require "active_model/validations/clusivity" module ActiveModel # == Active Model Inclusion Validator module Validations class InclusionValidator < EachValidator - ERROR_MESSAGE = "An object with the method #include? or a proc or lambda is required, " << - "and must be supplied as the :in option of the configuration hash" - - def check_validity! - unless [:include?, :call].any?{ |method| options[:in].respond_to?(method) } - raise ArgumentError, ERROR_MESSAGE - end - end + include Clusivity def validate_each(record, attribute, value) - delimiter = options[:in] - exclusions = delimiter.respond_to?(:call) ? delimiter.call(record) : delimiter - unless exclusions.send(inclusion_method(exclusions), value) + unless include?(record, value) record.errors.add(attribute, :inclusion, options.except(:in).merge!(:value => value)) end end - - private - - # In Ruby 1.9 <tt>Range#include?</tt> on non-numeric ranges checks all possible values in the - # range for equality, so it may be slow for large ranges. The new <tt>Range#cover?</tt> - # uses the previous logic of comparing a value with the range endpoints. - def inclusion_method(enumerable) - enumerable.is_a?(Range) ? :cover? : :include? - end end module HelperMethods @@ -59,7 +41,7 @@ module ActiveModel # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. - # * <tt>:strict</tt> - Specifies whether validation should be strict. + # * <tt>:strict</tt> - Specifies whether validation should be strict. # See <tt>ActiveModel::Validation#validates!</tt> for more information def validates_inclusion_of(*attr_names) validates_with InclusionValidator, _merge_attributes(attr_names) |