0

I'm running into an error when nesting parameters in Rails 5: Unpermitted parameter: specialties

I have an Expertise model:

class Expertise < ApplicationRecord
    has_many :buckets, through: :specialties
    has_many :specialties   
end

A Bucket model:

class Bucket < ApplicationRecord
    has_many :expertises, through: :specialties
    has_many :specialties
end

And a Specialty model:

class Specialty < ApplicationRecord
    belongs_to :expertise
    belongs_to :bucket
end

I'm trying to allow the User to edit his or her Expertises and adjust the Specialties associated with them. The @buckets are passed in from the controller, and the form currently looks like this:

<%= form_for(expertise) do |f| %>
    <%= f.fields_for :specialties do |s| %>
        <%= s.collection_select :bucket_ids, @buckets, :id, :name, {}, { multiple: true, class: "input" } %>
    <% end %>
<% end %>

I based the form on this answer.

Here's the relevant snippet from the ExpertisesController:

def expertise_params
    params.require(:expertise).permit(:user_id, :name, :rating, :description, specialties_attributes: [:id, :expertise_id, :bucket_id, :_destroy, bucket_ids: []])
end

And here are the parameters that are being passed in:

Parameters: {"expertise"=>{"specialties"=>{"bucket_ids"=>["", "1"]}, "description"=>""}, "id"=>"97"}

Specialties should be an array, right? I'm not sure how to do that.

The aim is to easily enable the User to select from the available Buckets (@buckets) to toggle his or her Expertise Specialties on or off. So let's say there are 5 Buckets available, the User would only be able to toggle on/off 5 possible Specialties for that Expertise.

Andrew
  • 472
  • 2
  • 24
  • Do you already tried to switch `specialties_attributes` to `specialties`? – Thiago Ururay Jun 20 '17 at 01:08
  • Can you paste the log output? – JCorcuera Jun 20 '17 at 01:17
  • @ThiagoUruray, I tried that, but it threw an error: "Specialty expected, got Array" – Andrew Jun 20 '17 at 01:22
  • @JCorcuera, Added the parameters from the log, is that what you're referring to? – Andrew Jun 20 '17 at 01:22
  • @Andrew I guess you could try `accepts_nested_attributes_for :specialties` on expertise model – Thiago Ururay Jun 20 '17 at 01:31
  • @ThiagoUruray, Thank you for your help. When I try that, the nested `fields_for` form doesn't return any `specialties` and so the HTML element is empty. Then, when I try to use `@expertise.specialties.build`, I get `undefined method bucket_ids` for Specialty because `bucket_ids` isn't actually an attribute, but `bucket_id` is. Worth keeping in mind that the User needs to be able to toggle multiple Specialties, each of which is tied to a Bucket (via a `bucket_id`), and from what I've ready I'm supposed to use `bucket_ids` (the plural) there. – Andrew Jun 20 '17 at 01:36
  • Oh, I see! When you try to build with `expertise_params` rails tries to build a new Expertise Object assigning the params as attributes of expertise. You can remove bucket_ids from expertise_params and process it after the build – Thiago Ururay Jun 20 '17 at 01:39
  • @ThiagoUruray, What exactly would that look like? Would you mind expanding on that in an answer? I'm having a hard time putting that together. – Andrew Jun 20 '17 at 01:44
  • @Andrew check if my answer matches your question, please – Thiago Ururay Jun 20 '17 at 02:05
  • 1
    Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/147118/discussion-between-andrew-and-thiago-ururay). – Andrew Jun 20 '17 at 02:10

2 Answers2

1

Unpermitted parameter: specialties

You didn't set up accept_nested_attributes_for which spits out with that error

class Expertise < ApplicationRecord
  has_many :specialties
  has_many :buckets, through: :specialties
  accepts_nested_attributes_for :specialties
end

When I try that, the nested fields_for form doesn't return any specialties and so the HTML element is empty. Then, when I try to use @expertise.specialties.build, I get undefined method bucket_ids for Specialty because bucket_ids isn't actually an attribute, but bucket_id is. Worth keeping in mind that the User needs to be able to toggle multiple Specialties, each of which is tied to a Bucket (via a bucket_id), and from what I've ready I'm supposed to use bucket_ids (the plural) there

You don't need to have plural form(_ids) just because to accept multiple values. Just keep bucket_id to accept multiple values. And don't forget to build the associated model in the controller

def new @expertise = Expertise.new @expertise.specialties.build end Change bucket_ids to bucket_id in the form

<%= s.collection_select :bucket_id, @buckets, :id, :name, {}, { multiple: true, class: "input" } %>

And finally, expertise_params should be

def expertise_params
  params.require(:expertise).permit(:user_id, :name, :rating, :description, specialties_attributes: [:id, :expertise_id, :_destroy, bucket_id: []])
end

Update:

Ok after some research, it looks like it should be bucket_ids, but the bucket_ids should be allowed as attribute for expertise. Check this post and tweak your form and expertise_params accordingly. You won't be needing accept_nested_attributes_for too!

Pavan
  • 33,316
  • 7
  • 50
  • 76
  • Thank you for your help. This got me closer, but still not quite there. I can now save the Specialty, but it doesn't have a Bucket associated with it. Here are the params, if they're helpful: `"expertise"=>{"specialties_attributes"=>{"0"=>{"bucket_id"=>["", "1"]}}}` – Andrew Jun 20 '17 at 15:56
  • @Andrew Can you post that `INSERT` call that you got in the server log? – Pavan Jun 20 '17 at 16:01
  • Here you go: `INSERT INTO "specialties" ("expertise_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["expertise_id", 97], ["created_at", 2017-06-20 16:04:12 UTC], ["updated_at", 2017-06-20 16:04:12 UTC]]` – Andrew Jun 20 '17 at 16:04
  • 1
    @Andrew Ok after some research, it looks like it should be `bucket_ids`, but the `bucket_ids` should be allowed as attribute for `expertise`. Check this post https://stackoverflow.com/questions/8826407/rails-3-multiple-select-with-has-many-through-associations and tweak your `form` and `expertise_params`. You won't be needing `accept_nested_attributes_for` too – Pavan Jun 20 '17 at 16:49
  • @Andrew Glad it worked :) I included an update in answer stating the same, so you can mark it as accepted :) – Pavan Jun 21 '17 at 04:48
0

The situation: Expertise has_many Buckets through Specialties and you want to update some bucket status of a specific expertise. So you can do this:

class ExpertisesController < ApplicationController
  def your_action
    @expertise = Expertise.find params[:id]
    bucket_ids = params[:expertise][:specialties][:bucket_ids]
    @expertise.specialties.where(id: bucket_ids).update(status: :on)
  end
end
Thiago Ururay
  • 482
  • 3
  • 15
  • I'd like to create and delete Specialty objects depending on which corresponding Buckets are selected, not update a property on a Specialty object. – Andrew Jun 20 '17 at 02:23