ActionParameter helps you move all your parameter's logic into it's own class. This way you'll keep your controllers dry and they would be easier to test.
# app/controllers/users_controllers.rb
class UsersController < ActionController::Base
def create
User.create(user_params)
end
private
def user_params
params.require(:user).permit(:name, :age)
end
end
# app/controllers/users_controllers.rb
class UsersController < ActionController::Base
def create
# It automatically deduces which Parameters class from Controller's name
User.create(permitted_params.permit)
end
end
# app/parameters/user_parameters.rb
class UserParameters < ActionParameter::Base
def permit
params.require(:user).permit(:name, :age)
end
end
ActionParameter works with Rails 3.0 onwards and Ruby 1.9.3 onwards. You can add it to your Gemfile with:
gem 'action_parameter'
Run the bundle command to install it.
####Generator
rails generate parameters [MODEL_NAME]
Will create app/parameters/[model_name]_parameters.rb.
####Controller Helpers
- permitted_params: Returns an ActionParameter instance.
permitted_params(options={})
#####Options Hash
- options - Hash with one valid key: :class.
- options[:class] - Symbol value with the name of the Parameters class you want to use.
#####Example 1
# app/controllers/people_controllers.rb
class PeopleController < ActionController::Base
def create
Person.create(permitted_params.permit) # This will call to PersonParameters' permit method
end
end
# app/parameters/person_parameters.rb
class PersonParameters < ActionParameter::Base
def permit
params.require(:person).permit(:name, :age)
end
end
#####Example 2
# app/controllers/people_controllers.rb
class PeopleController < ActionController::Base
def create
Person.create(permitted_params(class: :user).sign_up) # This will call to UserParameters' sign_up method
end
end
# app/parameters/user_parameters.rb
class UserParameters < ActionParameter::Base
def sign_up
params.require(:person).permit(:name, :age)
end
end
####Parameter Class Helpers
#####Default Helpers
- params: Returns params from the current controller request which instantiated the Parameter class.
- controller_name: Returns the controller's name from which the Parameter class was instantiated.
- action_name: Returns the action's name from the controller from which the Parameter class was instantiated.
#####Creating New Helpers
If you want to create new helper methods for your parameters class, just call locals method over permitted_params. Let say you want to make @current_user available for the UserParameter's class under the user method, then you'll need to use the locals method to tell the UserParameters class to create a new helper that returns @current_user.
permitted_params(class: :user).locals( user: @current_user,
another_helper: @value )
This will create user and another_helper methods and they will be available in UserParameters class.
#####Example
# app/controllers/users_controllers.rb
class UsersController < ActionController::Base
def create
User.create(permitted_params.locals(user: @current_user).permit) # This will call to UserParameters' permit method
end
end
# app/parameters/user_parameters.rb
class UserParameters < ActionParameter::Base
def permit
if user.admin?
params.require(:person).permit(:name, :age, :admin)
else
params.require(:person).permit(:name, :age)
end
end
end
This example shows how to test using RSpec.
Theses tests require your test.rb configured to config.action_controller.action_on_unpermitted_parameters = :raise.
# spec/parameters/user_parameters_spec.rb
require "spec_helper"
describe UserParameters do
describe ".permit" do
describe "when permitted parameters" do
it "returns the cleaned parameters" do
user_params = { first_name: "John", last_name: "Doe" }
params = ActionController::Parameters.new(user: user_params)
permitted_params = UserParameters.new(params).permit
expect(permitted_params).to eq user_params.with_indifferent_access
end
end
describe "when unpermitted parameters" do
it "raises error" do
user_params = { foo: "bar" }
params = ActionController::Parameters.new(user: user_params)
expect{ UserParameters.new(params).permit }.
to raise_error(ActionController::UnpermittedParameters)
end
end
end
end