14

I am using the strong_parameters gem in my controllers, but I'm having a hard time understanding how I would test it.

Here's an example of my setup

class UserController < ActionController::Base
  include ActiveModel::ForbiddenAttributesProtection

  def create
    @user = User.new(user_params)
    if @user.save
      ...
    end
  end

  private
  def user_params
    params.require(:user).permit(:first_name, :last_name, :username, :email)
  end
end

I want to test the user_params method to make sure that it is correctly filtering out malicious key/value pairs, but can't figure out how to do it. Has anyone else been through this?

Bryce
  • 2,802
  • 1
  • 21
  • 46

3 Answers3

17

You can stub the params hash as

params = ActionController::Parameters.new(your_hash)

This is the class that your URL params are being converted to in your controller, and it gives you the require and permit methods.

I personally extract the functionally out into a new class to handle the authorization policy.

cpuguy83
  • 5,794
  • 4
  • 18
  • 24
6

Modify this according to your need,

describe "create action" do
    it 'creates a user' do
      User.should_receive(:create).
        with({name: 'Alan D'}.with_indifferent_access)
      post :create, user:
        { first_name: 'Alan', last_name: 'Donald', username: 'alan77', email: 'mymail@yopmail.com' }
    end
end

or other alternative solution to this problem is:

describe UsersController::UserParams do
  it 'cleans the params' do
    params = ActionController::Parameters.new(user: {foo: 'bar', name: 'baz'})
    user_params = UsersController::UserParams.build(params)
    expect(user_params).to eq({name: 'baz'}.with_indifferent_access)
  end
end
Rimian
  • 36,864
  • 16
  • 117
  • 117
Nimish
  • 1,053
  • 13
  • 29
0

I'm not sure I would test strong_parameters, which I am guessing you're using via the gem.

The gem has its own tests, so we can assume it works as expected.

This is an example of 'testing Rails', which I believe is unnecessary. I wouldn't test that attr_accessible works as advertised (Testing Rails), or attr_accessor (Testing Ruby).

IMHO, your integration tests should cover all desired instances of success/failure and implicitly cover your strong_parameter configuration.

adarsh
  • 396
  • 3
  • 12
  • 3
    Our test policy is to explicitly write tests for all functionality, to allow us to potentially switch gems/roll our own later on and still know that the system is working. – Bryce May 16 '13 at 14:54
  • 10
    You can also be testing that your code that integrates in with strong_parameters is working properly. I have fields which are writable/not writeable depending on user roles/permissions, so I need to test that these two pieces integrate properly. – cpuguy83 May 21 '13 at 13:33
  • 1
    Having taken an app from Rails 1.1 to 3.2 (and now preparing for 4.0), I can assure you that testing Rails is very necessary. Something that worked one way in one version of Rails may change behavior in another version. For instance, I used to clone activerecord records using the `clone` method, but somewhere between 3.0 and 3.2 they decided that `dup` would provide that functionality instead... and do it slightly differently. This was not well advertised, but it was quickly caught by my tests. – sockmonk Oct 10 '13 at 17:46
  • Yes @sockmonk - this is definitely one situation where you'd want to test Rails :) – adarsh Oct 11 '13 at 22:41