0

I'm trying to permit an array with an arbitrary number of values, but Rails throws Unpermitted parameter: service_rates every time. I tried a lot of things (Rails 4 Unpermitted Parameters for Array, Unpermitted parameters for Dynamic Forms in Rails 4, ...) but nothing works.

The field's name is service_rates and it's column type is jsonb.

I want to create a JSON object from an arbitrary number of input fields:

<%= f.hidden_field :service_ids, value: @services.map(&:id) %>
<% @services.each do |service| %>
  <tr>
    <td>
      <% value = @project.service_rates ? @project.service_rates["#{service.id}"]['value'] : '' %>
      <%= text_field_tag "project[service_rates][#{service.id}]", value, class: 'uk-width-1-1', placeholder: 'Stundensatz' %>
    </td>
  </tr>
<% end %>

So my POST data looks like this:

 project[service_rates][1] = 100
 project[service_rates][2] = 95
 project[service_rates][3] = 75

Currently service_rates is permitted via whitelisting with tap:

def project_params
  params.require(:project).permit(:field1, :field2, […], :service_ids).tap do |whitelisted|
    whitelisted[:service_rates] = params[:project][:service_rates]
  end
end

At least, I'm building a JSON object in a private model function (which throws this error):

class Project < ActiveRecord::Base
  before_save :assign_accounting_content

  attr_accessor :service_ids

  private

  def assign_accounting_content

    if self.rate_type == 'per_service'
      service_rates = {}
      self.service_ids.split(' ').each do |id|
        service_rates["#{id}"] = {
          'value': self.service_rates["#{id}"]
        }
      end

      self.service_rates = service_rates
    end

  end

end

I've also tried to permit the field like that …

params.require(:project).permit(:field1, :field2, […], :service_rates => [])

… and that …

params.require(:project).permit(:field1, :field2, […], { :service_rates => [] })

… but this doesn't work either.

When I try this …

params.require(:project).permit(:field1, :field2, […], { :service_rates => [:id] })

… I get this: Unpermitted parameters: 1, 3, 2

Community
  • 1
  • 1
Slevin
  • 4,268
  • 12
  • 40
  • 90

1 Answers1

2

It's not really clear what service_rates is for you. Is it the name of an association ? Or just an array of strings ?

To allow array of strings : :array => [], To allow nested params for association : association_attributes: [:id, :_destroy, ...]

params.require(:object).permit(
  :something,
  :something_else,
  ....
  # For an array (of strings) : like this (AFTER every other "normal" fields)
  :service_rates => [],
  # For nested params : After standard fields + array fields
  service_rates_attributes: [
    :id,
    ...
  ]
)

As I explained in the comments, the order matters. Your whitelisted array must appear AFTER every classic fields

EDIT

Your form should use f.fields_for for nested attributes

<%= form_for @project do |f| %>
    <%= f.fields_for :service_rates do |sr| %>
      <tr>
        <td>
          <%= sr.text_field(:value, class: 'uk-width-1-1', placeholder: 'Stundensatz' %>
        </td>
      </tr>
    <% end %>
<% end %>
Cyril Duchon-Doris
  • 12,964
  • 9
  • 77
  • 164
  • Thanks, you pointed me to the right direction. `service_rates` is an object (of objects), not an array. Is it possible to permit a hash with arbitrary (nested) keys and values? – Slevin Jul 21 '15 at 12:19
  • Well, accepting an arbitrary number of keys and values is the opposite of Rails 4 strong params. It is not safe to do that. But you can still access the parameters with `params[service_rates]` – Cyril Duchon-Doris Jul 21 '15 at 12:22
  • Would it be possible to permit keys dynamically? The content of `service_rates` looks like `'1': {'value': 10, 'active': true }, '2': {'value': 20, 'active': false }`. The keys (`1`, `2`, …) are IDs of the records from my `Service` model. Would this work: `permit({:service_rates => { HOW_TO_ADD_ALL_SERVICE_IDS_HERE? }})`? – Slevin Jul 21 '15 at 12:34
  • Oh you meant that. This is done automatically, you don't have to worry about it. When you write `service_rates_attributes: ` it will automatically permit the array of `service_rates`, so you just have to specify `service_rates_attributes: [:id, :value, :active]` – Cyril Duchon-Doris Jul 21 '15 at 12:42
  • When I do this, I get `Unpermitted parameter: service_rates` :( (I'm using Rails 4.2.3) – Slevin Jul 21 '15 at 13:16
  • I think the problem is in your form/model. You should edit your question to add them. I also added an edit to my answer. – Cyril Duchon-Doris Jul 21 '15 at 13:27
  • OK, I figured it out. I've used a weird mix of same-named input fields and params. I refactored parts of my code and now it works. Thank you very much! – Slevin Jul 21 '15 at 13:28