Kevin Whitaker
Kevin Whitaker

Reputation: 13435

Rails: has_one belongs_to not building relationships properly

I've got two models, one belonging to another, and can't seem to get them to save properly. The problem stems from the fact that when I use the build method on the models, it isn't assigning them to each other in memory, so that when I try to call .save on the parent, the children don't have the parent's ID set, and fail.

Here is the parent model:

#  id             int(11)
#  execution_id   int(11)
#  macro_type_id  int(11)
#  macro_key_id   int(11)
#  created_at     datetime
#  updated_at     datetime

class ExecutionMacro < ActiveRecord::Base
  belongs_to :execution
  belongs_to :macro_type
  belongs_to :macro_key
  has_one :advertisement_execution, :dependent => :destroy
  accepts_nested_attributes_for :advertisement_execution

  attr_accessible :macro_key_id, :macro_type_id, :advertisement_execution_attributes

  validates :execution, :presence => true
  validates :macro_type, :presence => true
  validates :macro_key, :presence => true
end

Here is the child:

#  id                        int(11)
#  advertisement_id          int(11)
#  execution_macro_id        int(11)
#  advertisement_version_id  int(11)
#  created_at                datetime
#  updated_at                datetime
#  deleted_at                datetime

class AdvertisementExecution < ActiveRecord::Base
  belongs_to :advertisement
  belongs_to :advertisement_version
  belongs_to :execution_macro

  attr_accessible :advertisement_id, :advertisement_version_id, :execution_macro_id

  validates :execution_macro, :presence => true
  validates :advertisement, :presence => true
  validates :advertisement_version, :presence => true
end

So, if I try the following code:

@execution = Execution.find(1)
@em = @execution.execution_macros.build(:macro_type_id => 1, :macro_key_id => 1)
@ae = @em.build_advertisement_execution(:advertisement_id => 1, :advertisement_version_id => 1)
if @em.save
  "do something"
else
  "throw an error"
end

The save will fail, citing "Advertisement Execution: Execution Macro can't be blank."

It doesn't feel like this should be that hard. What am I missing?

Upvotes: 1

Views: 341

Answers (1)

code1n
code1n

Reputation: 136

The trick is that @em is not saved to database while you call build_advertisement_execution. In this case @em.id and @ae.id are equal to nil (as they are not persisted), that's why @ae.execution_macro_id and @em.advertisement_execution_id are also set to nil. My suggestion is to rethink validation logic or save execution_macros without validation before creating advertisement_execution (see .save(validate: false)).

Upvotes: 1

Related Questions