Search code examples
ruby-on-railsrspecrspec-rails

Provide strong parameters in controller spec


I'm looking to write a unit test for one of the methods of a controller which is as follows:

def update
  @key = current_user.keys.find_by_key(params[:id])
  @key.update_attributes(key_params)
  redirect_to :back
end

private

def key_params
  params.require(:key).permit(:note)
end

the route for this is:

PUT              /projects/:project_id/keys/:id           keys#update

So far I have the following:

describe '#update' do
  before :each do
    @user = FactoryGirl.create(:user)
    @project= FactoryGirl.create(:project, user: @user)
    @key = FactoryGirl.create(:key, id: 40, project: @project, user: @user)
    controller.stub(:current_user).and_return(@user)
  end

  it 'update key' do
    put :update, project_id:@project.id, id:@key.id
    expect(response.code).to eq "302"
  end
end

But this gives an error as follows:

KeysController#update update key
 Failure/Error: put :update, project_id:@project.id, id:@key.id
 ActionController::ParameterMissing:
   param is missing or the value is empty: key

Any leads would be very helpful. Thanks


Solution

  • You need to pass key params to the action. And it is good idea to check not only response status, but action result too

    it 'updates key' do
      # supposing that "note" is a string column
      expect do
        put :update, project_id: @project.id, id: @key.id, key: { note: 'New note' } 
      end.to change { @key.note }.from('Old note').to('New note')
      expect(response.code).to eq "302"
    end
    

    UPDATE:

    In the controller you're trying to find key instance by key attribute

    @key = current_user.keys.find_by_key(params[:id])
    

    but you're passing key.id in specs. How it works in the app? I suppose, you pass a key as :id parameter, so it should be

    put :update, project_id: @project.id, id: @key.key, key: { note: 'New note' } 
    

    in your specs. Also, find_by_key doesn't raise error if it can't find anything, it just returns nil. It means that you'll not get RecordNotFound. Moreover, it is a deprecated method, you should use find_by(key: params[:id]) To raise error use bang method find_by!(key: params[:id])

    If you're passing key.id in the app you need to make changes in the controller action

    @key = current_user.keys.find(params[:id])