0

I have a model Declaration which has many Costs:

class Declaration < ActiveRecord::Base
  has_many :costs
  accepts_nested_attributes_for :costs
end

class Cost < ActiveRecord::Base
  belongs_to :declaration
end

I want a form where I have 10 cost lines for a declaration, so in the Declaration controller I have the follwing, with the permit params for strong parameters:

  def new
    @declaration = Declaration.new
    @costs = Array.new(10) { @declaration.costs.build }
  end

  def create
    @declaration = Declaration.new(declaration_params)
    if @declaration.save
      redirect_to user_declarations_path, notice: I18n.t('.declaration.message_create')
    else
      render action: "new"
    end
  end

  private

  def declaration_params
    params.require(:declaration).permit(:approval_date, :submit_date, :status, :user_id, :declaration_number,
      costs_attributes: [:id, :description, :amount_foreign, :rate, :amount, :cost_date, :projectuser_id])
  end

And there is the form of course, so when I submit the form I see this in the log:

Started POST "/users/3/declarations" for 127.0.0.1 at 2013-09-05 19:12:38 +0200
Processing by DeclarationsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"mhaznOuBy/zj7LA/nIpDTy7X2u5UrR+0jleJsFid/JU=", "declaration"=>{"user_id"=>"3", "cost"=>{"cost_date(3i)"=>"", "cost_date(2i)"=>"", "cost_date(1i)"=>"", "projectuser_id"=>"", "description"=>"", "amount_foreign"=>"", "rate"=>"", "amount"=>""}}, "commit"=>"Opslaan", "user_id"=>"3"}
  User Load (0.7ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 3 ORDER BY "users"."id" ASC LIMIT 1
Unpermitted parameters: cost

So why do I get an unpermitted parameter cost??

Update: declaration form added below:

- if can? :create, Declaration
  = form_for [current_user, @declaration] do |f|
    = f.hidden_field :user_id, value: current_user.id

    .row
      .page-header
        .span7
          %h1.title
            %i{ class: "icon-coffee icon-large" }
            = I18n.t('.declaration.add_title')
        .span5
          .action
            - if can? :create, Declaration
              = link_to I18n.t('.general.cancel'), user_declarations_path(current_user), class: 'btn'
              = f.submit(class: 'btn', value: I18n.t('.general.save'))
    .row
      .span12
        = render "layouts/error_messages", target: @declaration

    .row
      .span12
        = render "form", f: f

And the rendered form:

.row
  .span12
    %table.table.table-striped#declarations
      %thead
        %tr
          %th= I18n.t('.cost.cost_date')
          %th= I18n.t('.cost.project')
          %th= I18n.t('.cost.description')
          %th= I18n.t('.cost.amount_foreign')
          %th= I18n.t('.cost.rate')
          %th= I18n.t('.cost.amount')
      %tbody
        - @costs.each do |cost|
          = f.fields_for cost, html: { class: "form-inline"} do |c|
            %tr
              %td{ "data-title" => "#{I18n.t('.cost.cost_date')}" }= c.date_select :cost_date, { include_blank: true, default: nil }
              %td{ "data-title" => "#{I18n.t('.cost.project')}" }= c.collection_select :projectuser_id, @projectusers, :id, :full_name, include_blank: true
              %td{ "data-title" => "#{I18n.t('.cost.description')}" }= c.text_field :description, class: "input-large"
              %td{ "data-title" => "#{I18n.t('.cost.amount_foreign')}" }= c.text_field :amount_foreign, class: "input-small", type: :number, step: "any"
              %td{ "data-title" => "#{I18n.t('.cost.rate')}" }= c.text_field :rate, class: "input-small", type: :number, step: "any"
              %td{ "data-title" => "#{I18n.t('.cost.amount')}" }= c.text_field :amount, class: "input-small", type: :number, step: "any"

With permit! I get this error message:

Started POST "/users/3/declarations" for 127.0.0.1 at 2013-09-09 09:29:44 +0200
Processing by DeclarationsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"jQwy7psQwixneWF8DezrR/Wo5VKU/dpfz+sosiatm9c=", "declaration"=>{"user_id"=>"3", "cost"=>{"cost_date(3i)"=>"", "cost_date(2i)"=>"", "cost_date(1i)"=>"", "projectuser_id"=>"", "description"=>"", "amount_foreign"=>"", "rate"=>"", "amount"=>""}}, "commit"=>"Opslaan", "user_id"=>"3"}
  User Load (0.6ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 3 ORDER BY "users"."id" ASC LIMIT 1
Completed 500 Internal Server Error in 6ms

ArgumentError - wrong number of arguments (6 for 0):
  app/controllers/declarations_controller.rb:70:in `declaration_params'
  app/controllers/declarations_controller.rb:21:in `create'
7
  • Can you post your html.erb for the form? Commented Sep 8, 2013 at 18:25
  • Also, can you run a little troubleshooting by changing params.require(:declaration).permit... to params.require(:declaration).permit! to see what happens? I haven't researched the .permit! method to feel it is secure enough to use in production, but it will highlight if something is wonky in Rails singular/plural i.e. cost vs costs... Commented Sep 8, 2013 at 18:33
  • Could be it's rejecting the entire cost hash based on getting three parameters "cost"=>{"cost_date(3i)"=>"", "cost_date(2i)"=>"", "cost_date(1i)"=>"" from the form? It is recognizing cost_date(1i) as :cost_date parameter? Commented Sep 8, 2013 at 18:45
  • With permit! it returns: "wrong number of arguments (6 for 0)"? Commented Sep 9, 2013 at 7:31
  • possible duplicate of How is attr_accessible used in Rails 4? Commented Sep 9, 2013 at 7:36

2 Answers 2

1

First impression is you are returning three cost_date parameters. I think this needs to be returned as an array. Your params would then be:

 def declaration_params
 params.require(:declaration).permit(:approval_date, :submit_date, :status, :user_id, :declaration_number,
  costs_attributes: [:id, :description, :amount_foreign, :rate, :amount, :projectuser_id, :cost_date =>[]])
end

Then instead of your web server getting back:

... "cost"=>{"cost_date(3i)"=>"", "cost_date(2i)"=>"", "cost_date(1i)"=>"",... 

it should get:

"cost"=>{"cost_date"=>["","",""],...

though without seeing the form I don't know if this is what you are trying to achieve.

Sign up to request clarification or add additional context in comments.

3 Comments

I have added the views
Also, have you tried the code above? Are you supposed to get 3 different cost_date() params returned? that seems very odd for a table row.
The cost_date doesn't seem to be the problem here.
0

It seems that changing this:

  - @costs.each do |cost|
      = f.fields_for cost, html: { class: "form-inline"} do |c|

to this:

= f.fields_for(:costs) do |c|

Does the trick, because now all costs records are being saved. In the controller I have now this:

@declaration = Declaration.new
10.times do |n|
  @declaration.costs.build
end

The only issue I have now left is that it saves empty cost records.

1 Comment

Using 10.times do is going to give you ten new records no matter what. You should use a .each method. i.e. costs.each do... etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.