简体   繁体   中英

Rails Active Record Callbacks error in nested association

I'm having trouble with Active Record callbacks in a model which contains accepts_nested_attributes

I call build_associated_parties using an after_create callback, but these values are not being saved and I get <nil> errors. I've also tried using before_create & after_initialize callbacks without success.

What is causing the callbacks to fail?

connection.rb

class Connection < ActiveRecord::Base 
  attr_accessible :reason, :established, :connector, :connectee1,
                  :connectee2, :connectee1_attributes,
                  :connectee2_attributes, :connector_attributes 

  belongs_to :connector, class_name: "User" 
  belongs_to :connectee1, class_name: "User"
  belongs_to :connectee2, class_name: "User"

  accepts_nested_attributes_for :connector, :connectee1, :connectee2 

  belongs_to :permission 

  after_create :build_associated_parties    

  # builds connectee's, connector, permission objects
  def build_associated_parties   
    build_connector
    build_connectee1
    build_connectee2
    build_permission
  end

connection_controller.rb

class ConnectionsController < ApplicationController
  def new
    @connection = Connection.new
  end

  def create        
    @connection = Connection.new params[:connection]
    if @connection.save     
      flash[:notice] = "Connection created successfully!"
      redirect_to @connection
    else
      render :new
    end
  end
end

However, if I instead build these attributes inside the controller as shown below, I don't get the error. This is nice, but it seems to go against keeping business logic code out of the controller.

class ConnectionsController < ApplicationController
  def new
    @connection = Connection.new
    @connection.build_connectee1
    @connection.build_connectee2
    @connection.build_connector
  end
end

How can I accomplish the same functionality with code in the model? Are there advantages to keeping it in the model?

You called your method build_associated_parties after connection is created, so how these methods:

 build_connector
 build_connectee1
 build_connectee2
 build_permission

know what params it will use? So they don't know what values are passed into method then they will get error. In controller, they didn't have error because they used values of params[:connection] .

On your form, if you already have fields for connector, connectee1, connectee2 , you should put code which initialize object in your new controller. When you save @connection , it's saved those object too. I think these codes aren't need to put into model. Your model only should put other logic code, like search or calculation...

after_create is a big no. Use after_initialize in your model and use self inside your build_associated_parties method. See if that works.

Moved logic out of controller and back into model. However, the build_* code was overwriting the values I was passing into the nested attributes.

By adding unless {attribute} to these build_ methods, I was able to properly pass in the values.

class Connection < ActiveRecord::Base attr_accessible :reason, :established, :connector, :connectee1, :connectee2, :connectee1_attributes, :connectee2_attributes, :connector_attributes

  belongs_to :connector, class_name: "User"
  belongs_to :connectee1, class_name: "User"
  belongs_to :connectee2, class_name: "User"

  accepts_nested_attributes_for :connector, :connectee1, :connectee2

  belongs_to :permission

  after_initialize :build_associated_parties

  validates :reason, :presence => true
  validates_length_of :reason, :maximum => 160

  #builds connectee's, connector, permission objects
  def build_associated_parties
    build_connector unless connector
    build_connectee1 unless connectee1
    build_connectee2 unless connectee2
  end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM