Using ShouldaMatchers#permit To Ensure Your Controller Parameters Get Passed
Background
I was working on a Rails 4.2.x application that had a controller with nested parameters. The whitelisted parameter list was so long, and I was making changes fairly fast without having a good way to ensure that I was passing all the data (via the parameter attributes) that I wanted to save.
For example, when adding a new piece of data (such as a person's school), I found myself forgetting to allow the application to save a person's school simply because I forgot to include it in the whitelisted parameter list.
This could easily have resulted in some data loss. I wanted a "Test Driven Development" (TDD) approach to ensure I wouldn't forget those parameters.
TDD via ShouldaMatchers#permit
Fortunately, there's a gem shoulda-matchers that is tailor made for this use case.
Here is the test setup. I actually have many more nested parameters besides user_demographic_attributes, but for readability's sake I omitted them.
The test setup assumes you are using RSpec with factory_girl.
Now you don't have to worry about whether or not you forgot to
Controller Setup: people_controller.rb
class PeopleController < ApplicationController
# Only allow a trusted parameter "white list" through.
def person_params
params.require(:person).permit(:id, :commit, :outcome_status_description, :additional_feedback, user_demographic_attributes: [:first_name, :last_name, :email, :school, :title, :department, :affiliation, :secondary_department, :secondary_school, :_destroy])
end
end
RSpec Controller Test Setup: peoplecontrollerspec.rb
RSpec.describe PeopleController, :type => :controller do
before do
@person = create(:person)
@survey = create(:survey, year: "2015", person_id: @person.id, status: "Saved")
@user_demographic = create(:user_demographic, person_id: @person.id)
end
it do
params = {
id: @person.id,
survey_id: @survey.id,
person: {
user_demographic_attributes: {
first_name: "MyString",
last_name: "MyString",
email: "MyString",
school: "MyString",
department: "MyText"
}
}
}
should permit(:id, :commit, :outcome_status_description, :additional_feedback, user_demographic_attributes: [:first_name, :last_name, :email, :school, :department, :affiliation, :_destroy]).for(:update_survey, params: params, verb: :patch).on(:person)
end
In spec_helper.rb add the following:
RSpec.configure do |config|
#your usual rspec configuration stuff
end
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end