Rails: Unpermitted parameter in Rails 5
Asked Answered
M

2

39

First of all I want simply get an object inside the current object that I'm sending to my backend.

I have this simple JSON (generated from a form):

{
  "name": "Project 1",
  "project_criteria": [
    {
      "name": "Criterium 1",
      "type": "Type 1",
      "benefit": "1"
    },
    {
      "name": "Criterium 2",
      "type": "Type 2",
      "benefit": "3"
    }
  ]
}

My classes:

class Project < ApplicationRecord
  has_many :project_criteria
  accepts_nested_attributes_for :project_criteria
end

class ProjectCriterium < ApplicationRecord
  belongs_to :project
end

ProjectsController:

def project_params
  params.require(:project).permit(:name,  project_criteria: [] )
end

But I still can't access project_criteria parameter as you can see below:

Started POST "/projects" for 127.0.0.1 at 2016-08-19 16:24:03 -0300
Processing by ProjectsController#create as HTML
  Parameters: {"project"=>{"name"=>"Project 1", "project_criteria"=>{"0"=>{"benefit"=>"1", "name"=>"Criterium 1", "type"=>"Type 1"}, "1"=>{"benefit"=>"3", "name"=>"Criterium 2", "type"=>"Type 2"}}}}
Unpermitted parameter: project_criteria # <-----------

Note:

By the way, I already tried to use criterium instead of criteria(which - in my opinion - is the correct since it should be pluralized) in has_many and accepts_nested_attributes_for, but it also doesn't work.

Does someone have a solution for this?

Mcculley answered 19/8, 2016 at 19:37 Comment(2)
Minor note: the singular of criteria is criterionNiggerhead
Perhaps it's an app about bike races ¯_(ツ)_/¯Ammeter
B
56

It's not the inflection of the word "criteria" that's giving you problems (although you can add a custom inflector to get the singular and plural versions you prefer if you really want).

The issue is that you have to explicitly permit the fields of nested objects.

Change your current params:

params.require(:project).permit(:name,  project_criteria: [] )

To this (for a single nested object):

params.require(:project).permit(:name,  project_criteria: [:name, :type, :benefit] )

Your case is somewhat compounded by the fact that you're dealing with multiple nested objects, so you'll have to pass a hash instead:

params.require(:project).permit(:name,  { project_criteria: [:name, :type, :benefit]} )
Beowulf answered 19/8, 2016 at 19:49 Comment(9)
Thanks for the response, but using both ways that you suggested gives: ActiveRecord::AssociationTypeMismatch (ProjectCriterium(#39449900) expected, got Array(#17940440)):Mcculley
I guess you're passing JSON as a hash? This may sound dumb, but... if you want an array at the end, pass a hash (my example). If you want a hash at the end, pass an array (which seems to be what you want), so just replace the curlies with square braces and give it a shot.Beowulf
Well, I was passing that way that I posted in the initial part of my question, but it's coming as hash ("project_criteria"=>{"0"=>{"benefit"=>"1", "name"=>"Criterium 1", "type"=>"Type 1"}, "1"=>{"benefit"=>"3", "name"=>"Criterium 2", "type"=>"Type 2"}}}}). By the way, I want an array at the end.. but unfortunately both of your suggestions give me that error.Mcculley
Did you try combining our answers? Rename to attributes as well as explicitly listing nested attributes? The error is basically saying that Rails expected an instance of ProjectCriterium, but it got an array instead, so I'm guessing that error is coming after the data is passed. I'd modify the create method by swapping save! for save to see if more detailed exceptions are generated while attempting to save nested objects.Beowulf
@Mcculley The abve comment is very true. You have too keep the attribute name inside [], with :id key. You can't keep that blank.Imperialism
@Mcculley You also should go and read the link I gave. That will help you to understand how this method works. U need to follow some conventions, that Rails uses to do some behind the scene magics.Imperialism
@MarsAtomic, well, I'm still working in another part.. I need to get the parameter first, then I can work on create or another method.. #Arup Rakshit, I tried to put all the attributes as you mentioned (combining with your answer, so I have this: params.require(:project).permit(:name, project_criteria_attributes: [:name, :type, :benefit] ), but I get this error: ActiveRecord::DangerousAttributeError (attribute is defined by Active Record. Check to make sure that you don't have an attribute or method with the same name.):Mcculley
@ArupRakshit, well I read that link, but still can't make work following all conventions..Mcculley
@ArupRakshit, I just forgot to check it as answer. Your answer totally works. The problem was on my side, I had an attribute called attribute (funny).. I had to change it to make it work again.Mcculley
T
6

I had this issue when working on a Rails 6 application.

My application consists of a User model that has a one-to-one relationship a Personal_Info model

My original code was this:

User Model

class User < ApplicationRecord 
  has_one :personal_info, class_name: 'PersonalInfo', dependent: :destroy
  accepts_nested_attributes_for :personal_info, allow_destroy: true
end

Personal Info Model

class PersonalInfo < ApplicationRecord
  belongs_to :user
end

User Controller

class UsersController < ApplicationController

  def index
    @users = User.all
  end
  .
  .

  def user_params
    params.require(:user).permit(:email, :password, :password_confirmation,
                                 personal_info_attributes: [:first_name,  
                                 :last_name, :phone, :gender, :dob, 
                                 :address, :city, :state, :country])
  end
end

The issue was that I did not add the Personal_Info id to the accepted user params (parameters).

Here's how I fixed it:

I simply had to add the Personal_Info id to the UsersController params this way:

User Controller

class UsersController < ApplicationController

  def index
    @users = User.all
  end
  .
  .

  def user_params
    params.require(:user).permit(:email, :password, :password_confirmation,
                                 personal_info_attributes: [:id, :first_name,  
                                 :last_name, :phone, :gender, :dob, 
                                 :address, :city, :state, :country])
  end
end

Another way is to add the update_only option to the Users Model this way:

class User < ApplicationRecord 
  has_one :personal_info, class_name: 'PersonalInfo', dependent: :destroy
  accepts_nested_attributes_for :personal_info, update_only: true, allow_destroy: true
end

That's all.

I hope this helps

Taste answered 27/7, 2020 at 17:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.