Add `ActionController::ParamsWrapper` to wrap JSON parameters into a nest #359

Merged
merged 1 commit into from May 2, 2011

5 participants

@sikachu
Ruby on Rails member

Add ActionController::ParamsWrapper to wrap JSON parameters into a nested hash

So now, instead of having to send JSON parameter with a parent such as:

{"user": {"name": "Prem"}}

you can now send it like this:

{"name": "Prem"}

and it will be wrapped in params[#{controller_name}] automatically. So for example if you're posting data to UsersController it will be wrapped in params[:user].

You could also specify the key which the parameters should be wrapped to by using wrap_parameters like this:

class UsersController < ApplicationController
  wrap_parameters :person
end

And you can also pass in a model class, which Rails will automatically detect proper parameter key and attribute names.

@josevalim josevalim and 1 other commented on an outdated diff May 2, 2011
...p/templates/config/initializers/wrap_parameters.rb.tt
@@ -0,0 +1,11 @@
+# Be sure to restart your server when you modify this file.
+
+# Enable parameter wrapping for JSON by default
+# TODO: Need to explain and add links to it on how it works
+# You can disable this by set it to false
+<%= app_const %>.config.action_controller.wrap_parameters = [:json]
@josevalim
Ruby on Rails member

Have you added tests for this line? Usually it is too late to change config here, you should do instead:

ActionController::Base.wrap_parameters :format => [:json]

@sikachu
Ruby on Rails member
sikachu added a note May 2, 2011

I'm adding test now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@vijaydev vijaydev and 1 other commented on an outdated diff May 2, 2011
actionpack/lib/action_controller/metal/params_wrapper.rb
@@ -0,0 +1,131 @@
+require 'active_support/core_ext/class/attribute'
+require 'action_dispatch/http/mime_types'
+
+module ActionController
+ # This module wraps a request parameters into a nested hash automatically. So instead of sending a JSON request for:
+ #
+ # {"user": {"name": "Konta"}}
+ #
+ # you can now send it like this:
+ #
+ # {"name": "Konata"}
@vijaydev
Ruby on Rails member
vijaydev added a note May 2, 2011

You might want to fix Konta/Konata inconsistency :-)

@sikachu
Ruby on Rails member
sikachu added a note May 2, 2011

Yes! :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@sikachu sikachu Add `ActionController::ParamsWrapper` to wrap parameters into a neste…
…d hash

This will allow us to do a rootless JSON/XML request to server.
8c9e4d5
@dhh dhh merged commit 79a9beb into rails:master May 2, 2011
@josevalim

The order of the hash is not preserved on Ruby 1.8.7. This means those tests frequently fail on Ruby 1.8.7.

Ruby on Rails member

Indeed. It would be better to parse the response JSON and check ruby object equality. :-(

Ruby on Rails member

Oops .. yeah, I overlooked that one. I've been using 1.9.2 for too long 💣

@josevalim
Ruby on Rails member

There are also no tests for the following scenarios:

1) wrap_parameters false
2) No tests for filtered logger
3) No tests that only post/put/delete parameters are wrapped, get aren't

In this case, features 1) and 2) were broken. I have fixed both and pushed tests. 3) works but needs to be properly tested.

Ruby on Rails member

Thank you for do the housekeeping for me, José. I'll add the test case for 3)

@agrobbin

This is my first post for the Rails core, so please tell me if I'm posting this in the wrong spot or should be doing something differently..

After working with Rails 3.1.0beta, I found there be a problem with the ActionController::ParamsWrapper when dealing with a abstract class and a similarly named controller. My scenario is as follows:

  • User is an abstract model with two subclasses, Student and Professor
  • UsersController is a resourceful controller used to edit either a Student or Professor (depending on who is logged in)
# app/models/user.rb
class User < ActiveRecord::Base
  self.abstract_class = true
end

# app/controllers/users_controller.rb
class UsersController < ApplicationController
end

# config/initializers/wrap_parameters.rb
ActionController::Base.wrap_parameters :format => [:json]

Let me know if there is anything I should do on top of this comment.

@josevalim
Ruby on Rails member

@agrobbin, what is the issue? Is it an exception? If so, what is the error message and backtrace? However, if you are just unsure on how to make it work, I recommend you to try the rubyonrails-talk mailing list and many people there can help you. If you then decide it is a rails issue or it is a needed, please report back here!

@agrobbin

My apologies @josevalim, having the base configurations, with no additional definitions in UsersController, when you try and go to /user/edit (it is a resource not resources, so no ID is passed), the following error appears:

ActiveRecord::StatementInvalid

Mysql2::Error: Table 'uclass.users' doesn't exist: SHOW FIELDS FROM `users`

Here is the backtrace:

/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb:279:in `query'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb:279:in `block in execute'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb:222:in `block in log'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/notifications/instrumenter.rb:21:in `instrument'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb:217:in `log'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb:279:in `execute'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb:469:in `columns'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:93:in `block (2 levels) in initialize'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:174:in `with_connection'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:90:in `block in initialize'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activerecord/lib/active_record/base.rb:694:in `yield'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activerecord/lib/active_record/base.rb:694:in `default'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activerecord/lib/active_record/base.rb:694:in `columns'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activerecord/lib/active_record/base.rb:704:in `column_names'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_controller/metal/params_wrapper.rb:167:in `_set_wrapper_defaults'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_controller/metal/params_wrapper.rb:128:in `inherited'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/abstract_controller/railties/routes_helpers.rb:7:in `block (2 levels) in with'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_controller/railties/paths.rb:7:in `block (2 levels) in with'
app/controllers/users_controller.rb:1:in `<top (required)>'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/dependencies.rb:452:in `load'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/dependencies.rb:452:in `block in load_file'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/dependencies.rb:639:in `new_constants_in'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/dependencies.rb:451:in `load_file'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/dependencies.rb:338:in `require_or_load'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/dependencies.rb:489:in `load_missing_constant'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/dependencies.rb:181:in `block in const_missing'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/dependencies.rb:179:in `each'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/dependencies.rb:179:in `const_missing'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/inflector/methods.rb:124:in `block in constantize'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/inflector/methods.rb:123:in `each'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/inflector/methods.rb:123:in `constantize'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/dependencies.rb:527:in `block in initialize'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/dependencies.rb:549:in `yield'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/dependencies.rb:549:in `default'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/dependencies.rb:549:in `[]'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_dispatch/routing/route_set.rb:61:in `controller_reference'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_dispatch/routing/route_set.rb:46:in `controller'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_dispatch/routing/route_set.rb:25:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_dispatch/routing/mapper.rb:41:in `call'
rack-mount (0.8.0) lib/rack/mount/route_set.rb:153:in `block in call'
rack-mount (0.8.0) lib/rack/mount/code_generation.rb:93:in `block in recognize'
rack-mount (0.8.0) lib/rack/mount/code_generation.rb:75:in `optimized_each'
rack-mount (0.8.0) lib/rack/mount/code_generation.rb:92:in `recognize'
rack-mount (0.8.0) lib/rack/mount/route_set.rb:141:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_dispatch/routing/route_set.rb:531:in `call'
oa-core (0.2.5) lib/omniauth/strategy.rb:44:in `call!'
oa-core (0.2.5) lib/omniauth/strategy.rb:30:in `call'
oa-core (0.2.5) lib/omniauth/strategy.rb:44:in `call!'
oa-core (0.2.5) lib/omniauth/strategy.rb:30:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_dispatch/middleware/best_standards_support.rb:17:in `call'
rack (1.3.0.beta) lib/rack/etag.rb:23:in `call'
rack (1.3.0.beta) lib/rack/conditionalget.rb:25:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_dispatch/middleware/head.rb:14:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_dispatch/middleware/params_parser.rb:21:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_dispatch/middleware/flash.rb:243:in `call'
rack (1.3.0.beta) lib/rack/session/abstract/id.rb:195:in `context'
rack (1.3.0.beta) lib/rack/session/abstract/id.rb:190:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_dispatch/middleware/cookies.rb:321:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activerecord/lib/active_record/query_cache.rb:54:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb:448:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activerecord/lib/active_record/identity_map.rb:152:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/callbacks.rb:392:in `_run_call_callbacks'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/callbacks.rb:81:in `run_callbacks'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_dispatch/middleware/callbacks.rb:28:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_dispatch/middleware/reloader.rb:68:in `call'
rack (1.3.0.beta) lib/rack/sendfile.rb:102:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_dispatch/middleware/remote_ip.rb:48:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_dispatch/middleware/show_exceptions.rb:47:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/railties/lib/rails/rack/logger.rb:13:in `call'
rack (1.3.0.beta) lib/rack/methodoverride.rb:24:in `call'
rack (1.3.0.beta) lib/rack/runtime.rb:17:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/activesupport/lib/active_support/cache/strategy/local_cache.rb:72:in `call'
rack (1.3.0.beta) lib/rack/lock.rb:34:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/actionpack/lib/action_dispatch/middleware/static.rb:53:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/railties/lib/rails/engine.rb:438:in `call'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/railties/lib/rails/rack/log_tailer.rb:14:in `call'
thin (1.2.11) lib/thin/connection.rb:84:in `block in pre_process'
thin (1.2.11) lib/thin/connection.rb:82:in `catch'
thin (1.2.11) lib/thin/connection.rb:82:in `pre_process'
thin (1.2.11) lib/thin/connection.rb:57:in `process'
thin (1.2.11) lib/thin/connection.rb:42:in `receive_data'
eventmachine (0.12.10) lib/eventmachine.rb:256:in `run_machine'
eventmachine (0.12.10) lib/eventmachine.rb:256:in `run'
thin (1.2.11) lib/thin/backends/base.rb:61:in `start'
thin (1.2.11) lib/thin/server.rb:159:in `start'
rack (1.3.0.beta) lib/rack/handler/thin.rb:13:in `run'
rack (1.3.0.beta) lib/rack/server.rb:265:in `start'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/railties/lib/rails/commands/server.rb:70:in `start'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/railties/lib/rails/commands.rb:54:in `block in <top (required)>'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/railties/lib/rails/commands.rb:49:in `tap'
/Users/alex/.rvm/gems/ruby-1.9.2-p180@uclass/bundler/gems/rails-cbe6e09f6a02/railties/lib/rails/commands.rb:49:in `<top (required)>'
script/rails:6:in `require'
script/rails:6:in `<main>'
@josevalim
Ruby on Rails member

@agrobbin, thank you very much for the backtrace! Could you please open up a new issue? We are going to assign a responsible to it and mark it as a blocker to Rails 3 release!

@agrobbin

Done! #558

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment