How to test strong params with Rspec?

13,116

Solution 1

Create 2 hashes with expected and all (with unsatisfied) parameters. Then pass all params to action and check that you object model receiving only expected params. It will not if you are not using strong parameter filters. Than add permissions to params and check test again.

For example, this:

# action
def create
  User.create(params)
end

# spec
it 'creates a user' do
  expect_any_instance_of(User).to receive(:create).
    with({name: 'Sideshow Bob'}.with_indifferent_access)
  post :create, user: 
    { first_name: 'Sideshow', last_name: 'Bob', name: 'Sideshow Bob' }
end

will pass all params to User and test will fail. And when you filter them:

def user_params
  params.require(:user).permit(:name)
end

and change action with User.create(user_params), test will pass.

Solution 2

I personally use shoulda-matcher from thoughtbot.

With something like:

it do
  should permit(:first_name, :last_name, :email, :password).
    for(:update, params: params)
end

Solution 3

Here is how I did it:

  describe 'Safe Params' do

   let(:mixed_params) {
     {
       blueprint_application_environment: {
         id: 1000,
         blueprint_id:   1,
         application_id: 2,
         environment_id: 3
       },
       format: :json
     }
   }

context "when processing a Post request with a mix of permitted and unpermitted parameters" do
   before { post :create, mixed_params }

  it "a create will not set the value of the unpermitted parameter" do
     expect(JSON.parse(response.body)["id"]).not_to eq(1000)
   end

  it "a create will set the value of the permitted parameters" do
     expect(JSON.parse(response.body)["blueprint_id"]).to eq(1)
     expect(JSON.parse(response.body)["application_id"]).to eq(2)
     expect(JSON.parse(response.body)["environment_id"]).to eq(3)
   end
 end

end

Controller code:

  def create
    @blueprint_application_environment = BlueprintApplicationEnvironment.new(blueprint_application_environment_params)
    if @blueprint_application_environment.save
      render 'show.json.jbuilder'
    else
      render json: @blueprint_application_environment.errors, status: :unprocessable_entity
    end
  end

def blueprint_application_environment_params
    params.require(:blueprint_application_environment).permit(:blueprint_id, :application_id, :environment_id)
end

Solution 4

as like you create or update object using strong parameters,it is also similar except one thing that normal you do like this:

post :create, book_id: @book.id

But in strong parameter you have to do like this:

post :create, {book_id: @book.id, comment: {user_id: 101, book_id: @book.id, description: "worth to buy"}}

you have to pass in nested parameters.

Share:
13,116
Molfar
Author by

Molfar

Updated on June 16, 2022

Comments

  • Molfar
    Molfar almost 2 years

    What is the actual strategy to test strong params filtering in Rails controller with Rspec? (Except shoulda matchers) How to write failing test and then make it green?

  • dleve123
    dleve123 almost 9 years
    create is a class-level method defined on ActiveRecord::Base and inherited by User. So while expect_any_instance(User) (mock expectation on an instance of User) might work, expect(User) (mock expectation on the User class) will work as well and is more minimal.