Rails 4: Strong Params

One of the biggest mental shifts for me while upgrading to Rails 4 was how model attributes are handled. Attributes are now whitelisted in the controller before being passed to the model for persistence, as opposed to being declared in the model via the attr_accessible method. This makes perfect sense from an application architecture and security standpoint — it addresses one of the biggest security flaws in previous versions of Rails — but I found myself having to constantly refer back to the docs to understand the syntax of strong parameters. These are my notes from researching strong parameters, which I will continue to update. Perhaps someone else will find them useful.

Simple Example

Let’s take a look at a simple model first.

class ContactsController < ActionController::Base  
    def create
        Contact.create(contact_params)
    end

    private

    def contact_params
        params.require(:contact).permit(:name, :email, :phone)
    end
end  

Referencing params directly in any of the public methods will raise a mass-assignment exception. Instead, we encapsulate the required and optional parameters in a private method with the new require and permit methods.
Conditional Params

One of the advantages to this new method of whitelisting attributes is that conditional logic based on user authentication and permissions can be applied directly to the params. This is especially useful if our application makes use of roles and permissions. For example, say we want to control how users of our application are allowed to be updated.

class UsersController < ActionController::Base  
    def update
        User.save(user_params)
    end

    private

    def user_params
        if current_user.is_admin?
            params.require(:user).permit(:name, :email, :role)
        elsif current_user.id == params[:user][:id]
            params.require(:user).permit(:name, :email)
        end
    end
end  

Naturally, we will allow an admin to update anything about any user. However, if the current user is not an admin, but is trying to edit their own user record, we allow them to edit some, but not all attributes (in this case, updating the role attribute is restricted to admins).
Nested Params

Strong parameters also are capable of handling nested parameters, which may be present if one model’s controller accepts parameters for a related model. In our Contact example above, say we wanted a contact to have many contact methods, rather than a single email and phone attribute. We can achieve this with acceptsnestedattributes_for in the model, but how do we represent this with strong parameters?

class ContactsController < ActionController::Base  
    def create
        Contact.create(contact_params)
    end

    private

    def contact_params
        params.require(:contact).permit(:name, :contact_methods => [:type, :value])
    end
end  

In this example, :contact_methods => [...] signifies that it permits an array of contact method objects to be present in the params. The keys within the array represent the attributes that a contact method may contain.

To be continued…

References

Andrew Allen

Author of EfficientRails.com, Software Engineer @Munchery, Former startup founder.

comments powered by Disqus