Friday, March 19, 2010

When Regular Assignment Fails, update_attributes!...?

I've run into my second gotcha with Rails now, solved by the same function: update_attributes!. Both times it took me entirely too long to figure out.



I have a many-to-many assocation, whose proper model implementation is excellently described in the official guide. As expected, my join model :belongs_to each of the models in the many-to-many relationship. We have 3 models, all related to each other; 2 of them are related through the third:



Or, in code:


## in the Receipt class...
:belongs_to :store
:belongs_to :customer

## in the Store class..
:has_many :receipts
:has_many :customers, :through => :receipts

## in the Customer class...
:has_many :receipts
:has_many :stores, :through => :receipts



This ends up being really handy, because we can easily do things with collections owned by either a store or a customer:

@store.receipts.total_price.each do |r|...

Adapting this blog-building example from the Rails guides, led me to create a receipt while building on a store:

@receipt = @store.receipts.build(params[:receipt])

Being new at the time I wrote this code, I figured an easy-enough way to also determine customer ownership of receipts was to extend the assignments:

@receipt = @store.receipts.build(params[:receipt]) = @customer.receipts.build(params[:receipt])

Seems like it should work, but this throws undefined method `build=' errors. I promptly erased that last error-causing bit and headed back to the drawing board -- this time checking the server logs while executing a successful new/create operation. All of my attributes but customer_id were being passed.

Solution: change controller's create method to update the attributes (new portion in bold):


@receipt = @store.receipts.build(params[:receipt])
@receipt.update_attributes!(:customer_id => current_user.id)



Just like that, we're passing all attributes and everything in the @customer.receipts collection is working!



  • Note this does assume the excellent RESTful authentication plugin is being used and the user is logged in. Not a problem, since I don't expose my create method to users who aren't logged in, but worth noting nonetheless.

No comments:

Post a Comment