belongs_to and callbacks

I have an Order, which belongs to a Buyer. Part of the order#form allows the user to enter the email address of the buyer. If they email address doesn't exist in the system, then a Buyer record is created in a before_save filter.

The weird thing is I have to explicitly set the buyer_id field in a callback filter. That's telling me that I'm either doing something wrong, or Rails isn't doing what it should. Here's the sanitized code:

class Order < ActiveRecord::Base   attr_accessor :ordered_by

  belongs_to :user   belongs_to :buyer, :class_name => "User", :foreign_key => "buyer_id"

  before_save :assign_buyer_by_email

  private

  def assign_buyer_by_email     self.buyer = User.find_by_email(ordered_by)     if buyer.nil?       self.buyer = User.create(:email => ordered_by)       # snip       self.buyer_id = self.buyer.id # Won't work without this line, seems un-DRY or worse     end   end end

ordered_by is the email address on the order#form. You'll notice buyer shares the table with user. To head off questions about find_or_create_by, I have other things do to the new user where you see snip, and it also results in the user being created but the buyer_id is not set.

Can someone explain what's happening here?

What's the value of self.buyer_id before you force it ?

Fred

At the point

If I stop in the debugger at   self.buyer_id = self.buyer.id # Won't work without this line, seems un-DRY or worse

Then...   self.buyer has a valid :id   self.buyer_id is nil

At the point

If I stop in the debugger at self.buyer_id = self.buyer.id # Won't work without this line, seems un-DRY or worse

I'd try stepping through the assignment in self.buyer = foo. In theory you should end up in BelongsToProxy#replace which in turn should be setting buyer_id

Fred

Shouldn't this happen only after you save the initial object? I mean that at the time you do self.buyer = User.create ... it creates a new associated object in the memory as an attribute of self, but buyer_id still doesn't have that information because at the time you fetched a self object into the memory it just didn't exist. I think if you do self.save (in your example it should be only for testing purposes because it's already inside the save callback) and self.reload after self.buyer = User.create you should see a value assigned.

> On Jan 7, 5:03 pm, IAmNan <dger...@gmail.com> wrote:> At the point

> > If I stop in the debugger at > > self.buyer_id = self.buyer.id # Won't work without this line, seems > > un-DRY or worse

> I'd try stepping through the assignment in self.buyer = foo. In theory > you should end up in BelongsToProxy#replace which in turn should be > setting buyer_id

Shouldn't this happen only after you save the initial object? I mean that at the time you do self.buyer = User.create ... it creates a new associated object in the memory as an attribute of self, but buyer_id still doesn't have that information because at the time you fetched a self object into the memory it just didn't exist.

Depends on the type of relationship and whether what you're setting the object to is already saved. Here we're using the return value of User.create, so it should be a saved object, so you just need to take the id of that object and stick it in buyer_id. If the relationship had been as one then we'd have to wait until the Order object had an id.

Fred

I think if you do self.save (in your example it should be only for