Brendan Jones
Brendan Jones

Reputation: 3

Why does my controller require the params hash to be repetitively nested?

I currently have the following situation:

ChallengeRequestsController #new - creates a ChallengeRequest along with another model needing a recpient_id.

def create
  @challenge_request = ChallengeRequest.new(challenge_params)

  recipient = User.find(params.require(:recipient_id))

  # Rest of method redacted.
end

def challenge_params
  params.require(:challenge_request).permit(:action)
end

With this controller, I have an RSpec test as follows:

RSpec.describe ChallengeRequestsController, type: :controller do
  describe "POST #create" do

    context "with valid challenge request" do
      let(:valid_challenge_request) { build(:challenge_request) }

      context "with non-exisistent recpient id" do
        it "throws an error" do
          expect{
            post :create, :params => {
              :challenge_request => {
                :challenge_request => valid_challenge_request
              },
              :recipient_id => 10000
            }
          }.to raise_error ActiveRecord::RecordNotFound
        end
      end

    end
  end
end

Just for reference, here's the Factory:

FactoryGirl.define do
  factory :challenge_request do
    action { Faker::LeagueOfLegends.champion }
  end
end

All of this code works and the test passes, my question is how can I refactor this in a way that I don't need to use the ugly nesting in the request?

:challenge_request => {
  :challenge_request => valid_challenge_request
}

When posting the request without this nesting:

post :create, :params => {
  :challenge_request => valid_challenge_request,
  :recipient_id => 10000
}

The challenge_request is empty when the ChallengeRequestController receives the request.

Upvotes: 0

Views: 57

Answers (1)

Simple Lime
Simple Lime

Reputation: 11035

It would probably work if you change your valid_challenge_request to be a hash of attributes instead of the model itself.

let(:valid_challenge_request) { FactoryBot.attributes_for(:challenge_request) }

You're trying to send along an instance of a model as a parameter to a controller, and something is doing something (I can't find what's doing what to the model) to try and coerce it into something that a browser might send the controller. That conversion is turning the model into an empty string, which is not present or the value false and thus causes the require to throw the ParameterMissing

Upvotes: 1

Related Questions