lib/action_controller/metal/params_wrapper.rb in actionpack-3.1.0.beta1 vs lib/action_controller/metal/params_wrapper.rb in actionpack-3.1.0.rc1

- old
+ new

@@ -1,9 +1,10 @@ require 'active_support/core_ext/class/attribute' require 'active_support/core_ext/hash/slice' require 'active_support/core_ext/hash/except' require 'active_support/core_ext/array/wrap' +require 'active_support/core_ext/module/anonymous' require 'action_dispatch/http/mime_types' module ActionController # Wraps parameters hash into nested hash. This will allow client to submit # POST request without having to specify a root element in it. @@ -34,15 +35,15 @@ # your new +params+ hash will look like this: # # {"name" => "Konata", "user" => {"name" => "Konata"}} # # You can also specify the key in which the parameters should be wrapped to, - # and also the list of attributes it should wrap by using either +:only+ or - # +:except+ options like this: + # and also the list of attributes it should wrap by using either +:include+ or + # +:exclude+ options like this: # # class UsersController < ApplicationController - # wrap_parameters :person, :only => [:username, :password] + # wrap_parameters :person, :include => [:username, :password] # end # # If you're going to pass the parameters to an +ActiveModel+ object (such as # +User.new(params[:user])+), you might consider passing the model class to # the method instead. The +ParamsWrapper+ will actually try to determine the @@ -50,11 +51,11 @@ # # class UsersController < ApplicationController # wrap_parameters Person # end # - # You still could pass +:only+ and +:except+ to set the list of attributes + # You still could pass +:include+ and +:exclude+ to set the list of attributes # you want to wrap. # # By default, if you don't specify the key in which the parameters would be # wrapped to, +ParamsWrapper+ will actually try to determine if there's # a model related to it or not. This controller, for example: @@ -70,11 +71,11 @@ EXCLUDE_PARAMETERS = %w(authenticity_token _method utf8) included do class_attribute :_wrapper_options - self._wrapper_options = {:format => []} + self._wrapper_options = { :format => [] } end module ClassMethods # Sets the name of the wrapper key, or the model which +ParamsWrapper+ # would use to determine the attribute names from. @@ -88,22 +89,22 @@ # # wrap_parameters Person # # wraps parameters by determine the wrapper key from Person class # (+person+, in this case) and the list of attribute names # - # wrap_parameters :only => [:username, :title] + # wrap_parameters :include => [:username, :title] # # wraps only +:username+ and +:title+ attributes from parameters. # # wrap_parameters false # # disable parameters wrapping for this controller altogether. # # ==== Options # * <tt>:format</tt> - The list of formats in which the parameters wrapper # will be enabled. - # * <tt>:only</tt> - The list of attribute names which parameters wrapper + # * <tt>:include</tt> - The list of attribute names which parameters wrapper # will wrap into a nested hash. - # * <tt>:except</tt> - The list of attribute names which parameters wrapper + # * <tt>:exclude</tt> - The list of attribute names which parameters wrapper # will exclude from a nested hash. def wrap_parameters(name_or_model_or_options, options = {}) model = nil case name_or_model_or_options @@ -123,54 +124,64 @@ # Sets the default wrapper key or model which will be used to determine # wrapper key and attribute names. Will be called automatically when the # module is inherited. def inherited(klass) if klass._wrapper_options[:format].present? - klass._set_wrapper_defaults(klass._wrapper_options) + klass._set_wrapper_defaults(klass._wrapper_options.slice(:format)) end super end protected # Determine the wrapper model from the controller's name. By convention, # this could be done by trying to find the defined model that has the # same singularize name as the controller. For example, +UsersController+ # will try to find if the +User+ model exists. - def _default_wrap_model + # + # This method also does namespace lookup. Foo::Bar::UsersController will + # try to find Foo::Bar::User, Foo::User and finally User. + def _default_wrap_model #:nodoc: + return nil if self.anonymous? + model_name = self.name.sub(/Controller$/, '').singularize begin model_klass = model_name.constantize - rescue NameError => e - unscoped_model_name = model_name.split("::", 2).last - break if unscoped_model_name == model_name - model_name = unscoped_model_name + rescue NameError, ArgumentError => e + if e.message =~ /is not missing constant|uninitialized constant #{model_name}/ + namespaces = model_name.split("::") + namespaces.delete_at(-2) + break if namespaces.last == model_name + model_name = namespaces.join("::") + else + raise + end end until model_klass model_klass end def _set_wrapper_defaults(options, model=nil) options = options.dup - unless options[:only] || options[:except] + unless options[:include] || options[:exclude] model ||= _default_wrap_model - if model.respond_to?(:column_names) - options[:only] = model.column_names + if model.respond_to?(:attribute_names) && model.attribute_names.present? + options[:include] = model.attribute_names end end - unless options[:name] + unless options[:name] || self.anonymous? model ||= _default_wrap_model options[:name] = model ? model.to_s.demodulize.underscore : controller_name.singularize end - options[:only] = Array.wrap(options[:only]).collect(&:to_s) if options[:only] - options[:except] = Array.wrap(options[:except]).collect(&:to_s) if options[:except] - options[:format] = Array.wrap(options[:format]) + options[:include] = Array.wrap(options[:include]).collect(&:to_s) if options[:include] + options[:exclude] = Array.wrap(options[:exclude]).collect(&:to_s) if options[:exclude] + options[:format] = Array.wrap(options[:format]) self._wrapper_options = options end end @@ -203,22 +214,22 @@ _wrapper_options[:format] end # Returns the list of parameters which will be selected for wrapped. def _wrap_parameters(parameters) - value = if only = _wrapper_options[:only] - parameters.slice(*only) + value = if include_only = _wrapper_options[:include] + parameters.slice(*include_only) else - except = _wrapper_options[:except] || [] - parameters.except(*(except + EXCLUDE_PARAMETERS)) + exclude = _wrapper_options[:exclude] || [] + parameters.except(*(exclude + EXCLUDE_PARAMETERS)) end { _wrapper_key => value } end # Checks if we should perform parameters wrapping. def _wrapper_enabled? ref = request.content_mime_type.try(:ref) - _wrapper_formats.include?(ref) && !request.request_parameters[_wrapper_key] + _wrapper_formats.include?(ref) && _wrapper_key && !request.request_parameters[_wrapper_key] end end end