ruby-on-railsruby-on-rails-4nested-formsfields-fornested-form-for

Rails fields_for and not creating relationship with nested object


The model "Formula" has many "Operands" created using a simple_nested_form, using fields for. It seems the process is correct, and no errors launched, but operands are not saved.

Formula model:

class Formula < ActiveRecord::Base
  attr_accessible :name, :client_id
  validates_presence_of :name, :client_id
  belongs_to :client
  has_many :operands, as: :operation, dependent: :destroy
  accepts_nested_attributes_for :operands, allow_destroy: true
  attr_accessor :operator, :numeric_operand, :operation_id, :operation_type
end

Operand model:

class Operand < ActiveRecord::Base
  attr_accessible :operator, :numeric_operand, :operation_id, :operation_type
  validates_presence_of :operator
  belongs_to :operation, polymorphic: true
  OPERATOR_TYPES = ["+", "-", "*", "/"]
end

Formulas controller:

class FormulasController < ApplicationController
  load_and_authorize_resource
  def new 
    @formula.operands.build 
  end

  def create
    @formula = Formula.new(params[:formula])      
    @formula.client_id = @current_client.id unless @formula.client_id.present?
      if @formula.save
        redirect_to @formula, notice: t('controllers.notice.successfully_created') }
      else
        render action: "new" 
      end
    end

  def edit
  end

  def update
      if @formula.update_attributes(params[:formula])
       redirect_to @formula, notice: t('controllers.notice.successfully_updated')
      else 
        render action: "edit"
      end
  end

Formula _form:

= simple_nested_form_for @formula, :html => { :class => 'form-vertical' } do |f|    
  = f.error_notification
 .form-inputs
    .row   
      .span3= f.input :name  
    .well      
      = f.fields_for :operands   
      = f.link_to_add t('helpers.links.add'), :operands  
  .form-actions
    = f.button :submit, :class => 'btn-primary', disable_with: "#{t('helpers.links.submitting')}"

_operands_fields:

.well
  .row
    .span2= f.input :operator, collection: Operand::OPERATOR_TYPES
    .span3= f.input :numeric_operand

This all seem to work fine, but when the proccess ends, no operands are created. When inspecting returned params in update or create methods using better errors, operands attributes are retrieved successfully from the form, but the relationship between formula and them is not created:

>> @formula.operands.all
=> #<ActiveRecord::AssociationRelation []>
>> @formula.operands.first
=> nil
>> params
=> {"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"--TOKEN--", "formula"=>{"name"=>"Sdfg", "operands_attributes"=>{"1457352032591"=>{"operator"=>"+", "numeric_operand"=>"3"}}}, "commit"=>"Update Formula", "action"=>"update", "controller"=>"formulas", "locale"=>"en", "id"=>"3"}
>>

Solution

  • Update (Using Strong Params)

    Continuing from our discussion that protected_attributes doesn't work with nested attributes for a polymorphic association in Rails 4 (unverified), I then suggested to use strong params:

    class FormulasController < ApplicationController
      # ..
      def formula_params
        params.require(:formula).permit(:name, :client_id, operands_attributes: [ :id, :operator, :numeric_operand, :formula_id, :_destroy ])
      end
      # ..
    end