Search code examples
ruby-on-railsruby-on-rails-4strong-parameters

How to use strong parameters with foreign keys


I am having an issue with foreign keys being permitted in my new Rails 4 application.

Lets say you have a user create form, where you can create a user and assign a user type though a dropdown.

The user model will then have a foreign key: user_type_id.

I have a RSpec test which uses FactoryGirl, and if I debug and look at params the user_type has the value 2, but if my permit params look like this:

private 

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

I won't get any user_type out. I have also tried with:

private 

def user_params
  params.require(:user).permit(:name, :password, user_type_attributes: [:user_type_id]) 
end

but without any luck.

What is the way to permit it in my post action in my User controller?

Update:

I don't have a UI yet, I try to do this the TDD way, so basically it is my RSpec-tests which fails.

The create user action looks like this:

 def create
    @user = User.new(user_params)
    authorize @user

    respond_to do |format|
        if @user.save
            format.html { render json: @user, status: :created, location: @user }
            format.json { render json: @user, status: :created, location: @user }
        else
            format.html { render json: @user, status: :unprocessable_entity, location: @user }
            format.json { render json: @user.errors, status: :unprocessable_entity }
        end
    end
end

and the RSpec test looks like this:

it 'should create a user' do
                expect {
                    post :create, { :user => FactoryGirl.attributes_for(:User) }
                }.to change(User, :count).by(1)
            end

The FactoryGirl for my user looks like this:

FactoryGirl.define do
    factory :User do |f|
        f.email { Faker::Internet.email }
        f.password { '12345678' }
        f.password_confirmation { '12345678' }
        f.user_type { FactoryGirl.create(:UserType) }
    end
end

If I debug my @user object it doesn't have a user_type added, but if I debug the params object, it does, contain a user_type: 2

Any ideas?


Solution

  • You are not creating an Id in the Factory. You are creating the new associated object. You will have to retrieve the ID in the params passed to the controller.

    I suggest:

    FactoryGirl.define do
        factory :User do |f|
            f.email { Faker::Internet.email }
            f.password { '12345678' }
            f.password_confirmation { '12345678' }
            f.user_type 999
        end
    end
    

    In your spec:

    before(:each) do
      type = FactoryGirl.create(:UserType, id: 999)
    end
    

    And then:

    it 'should create a user' do
      expect { :create, { :user => FactoryGirl.attributes_for(:User)}
                         }.to change(User, :count).by(1)
    end
    

    And remove the association from the FactoryGirl action.

    EDIT: If the user type is mandatory, and assuming that you have them in the database, you just need to insert in the factory the user_id you want for that user type. And you won't need to merge the params after.