Strong Parameters The Right Way
StrongParameters is a great gem and it comes with Rails 4 by default. Currently, there are two patterns to work with your attributes.
1. Creating a private method on your controller which returns the whitelisted attributes. #
# app/controllers/people_controller.rb
class PeopleController < ActionController::Base
  def update
    person = current_account.people.find(params[:id])
    person.update_attributes!(person_params)
    redirect_to person
  end
  private
    def person_params
      params.require(:person).permit(:name, :age)
    end
end
Pros #
- If your person_params logic is simple as the example shows. That’s pretty much, just call the method and it will do the job.
 
Cons #
If your person_params logic grows because, let say you want to permit certain params attributes if your user is an admin and another params attributes if it’s just a regular user:
- You’ll be adding more complexity to your controller.
 - You wont be able to reuse these logic.
 - Your controller will be harder to test.
 
2. Extracting your params logic into a class. #
# app/models/permitted_params.rb
class PermittedParams < Struct.new(:params)
  def person
    valid_keys = [:name, :email, :message]
    params.slice(*valid_keys).require(:person).permit(*valid_keys)
  end
end
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery
  private
    def permitted_params
      @permitted_params ||= PermittedParams.new(params)
    end
end
# app/controllers/people_controller.rb
class PeopleController < ActionController::Base
  def update
    person = current_account.people.find(params[:id])
    person.update_attributes!(permitted_params.person)
    redirect_to person
  end
end
These approach, in my opinion is better than the first one. You should checkout the StrongParameters’ Railscasts for more deatils if you liked these approach.
Pros #
- You’ll decouple your controller’s logic from your params logic, in which case, you’ll keep your controllers dry.
 - Your controllers will be easier to test.
 - You’ll avoid code duplication.
 
Cons #
If you have a lot a resources, because applications usually grows and not the other way:
- Your PermittedParams class will end up being a huge and will be hard to maintain.
 - You’ll be breaking the Single Responsability Principle.
 
So, which is exactly the best way to handle my parameters? #
The best way to handle your resource params would be to have a PermittedParams class type for each resource. Wouldn’t be better to have your resources params’ logic in separate classes like this?:
# app/parameters/user_parameters.rb
class UserParameters < Struct.new(:params)
  def permit
    params.require(:user).permit(:name, :age)
  end
end
class ApplicationController < ActionController::Base
  protect_from_forgery
  # Returns an instance of the params class related to the Controller from which was called
  def permitted_params
    @permitted_params ||= permitted_params_class.new(params)
  end
  # Returns the params class related to the Controller from which was called
  def permitted_params_class
    class_name                = params[:controller].to_s.singularize
    formatted_class_name      = class_name.camelcase
    @permitted_params_class ||= "#{formatted_class_name}Parameters".constantize
  end
end
# app/controllers/users_controller.rb
class UsersController < ApplicationController
  def create
    User.create(permitted_params.permit)
  end
end
Pros #
- You’ll decouple your controller’s logic from your params logic, in which case, you’ll keep your controllers dry.
 - Your controllers will be easier to test.
 - You’ll avoid code duplication.
 - Your params classes will be smaller, easier to test and maintain.
 - Your params classes will not violate the Single Responsability Principle.
 
Cons #
Some people might think that this is an over-engineering work if your controllers are simple and you have to deal with params like the first approach I described.
ActionParameter #
It’s a gem I created to implement this last pattern with some other features. I encourage you to take a look at it and try it, I’m pretty sure it would be helpful.
Conclusion #
All three patterns are good, you should choose the one that fits your needs. But bear in mind that applications and their logic always tends to grow and to get more complex.