So, imagine the following: class User < ActiveRecord::Base has_many :emails has_one :address end class Email < ActiveRecord::Base belongs_to :user end class Address < ActiveRecord::Base belongs_to :user end Now I am wondering what the correct Ruby-way to create a user object is in the controller when through a form, a new user, a couple of email addresses and a street address is posted. The obvious @user = User.new(params[:user]) was my first attempt. The problem here is that @user.emails.build and @user.address.build calls are fine, until we try to save the @user object. It then gives an error that it can not save the emails and address, because it doesn''t know what user_id to write in its foreign keys. The only way I could devise was an intricate scheme where I would first try to save the emails and address, and then the user object. Whenever something would fail along the way it would rollback any previous changes and destroy the correct object. This results in a very complex non-ruby if/then stack which I really hate. How am I supposed to save an object spanning multiple models at once and consistent? -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
There is an explanation of this in the Rails API documentation here: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html Scroll down to the section: Unsaved objects and associations On Jul 7, 9:29 am, Chris Dekker <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> So, imagine the following: > > class User < ActiveRecord::Base > has_many :emails > has_one :address > end > > class Email < ActiveRecord::Base > belongs_to :user > end > > class Address < ActiveRecord::Base > belongs_to :user > end > > Now I am wondering what the correct Ruby-way to create a user object is > in the controller when through a form, a new user, a couple of email > addresses and a street address is posted. > > The obvious @user = User.new(params[:user]) was my first attempt. The > problem here is that @user.emails.build and @user.address.build calls > are fine, until we try to save the @user object. It then gives an error > that it can not save the emails and address, because it doesn''t know > what user_id to write in its foreign keys. > > The only way I could devise was an intricate scheme where I would first > try to save the emails and address, and then the user object. Whenever > something would fail along the way it would rollback any previous > changes and destroy the correct object. This results in a very complex > non-ruby if/then stack which I really hate. > > How am I supposed to save an object spanning multiple models at once and > consistent? > -- > Posted viahttp://www.ruby-forum.com/.--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
> So, imagine the following:class Recipe has_many :ingredients end class Ingredient belongs_to :recipe end this is my console output>> r = Recipe.new(:name => ''spaghetti carbonara'')=> #<Recipe id: nil, name: "spaghetti carbonara", description: nil, created_at: nil, updated_at: nil>>> r.ingredients.build( :name => ''pasta'' )=> #<Ingredient id: nil, name: "pasta", recipe_id: nil, created_at: nil, updated_at: nil>>> r.ingredients=> [#<Ingredient id: nil, name: "pasta", recipe_id: nil, created_at: nil, updated_at: nil>]>> r.ingredients.first.recipe_id=> nil>> r.save=> true>> r.ingredients.first.recipe_id=> 4 Im on rails 2.1 out of the box. On Jul 7, 2:29 pm, Chris Dekker <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> So, imagine the following: > > class User < ActiveRecord::Base > has_many :emails > has_one :address > end > > class Email < ActiveRecord::Base > belongs_to :user > end > > class Address < ActiveRecord::Base > belongs_to :user > end > > Now I am wondering what the correct Ruby-way to create a user object is > in the controller when through a form, a new user, a couple of email > addresses and a street address is posted. > > The obvious @user = User.new(params[:user]) was my first attempt. The > problem here is that @user.emails.build and @user.address.build calls > are fine, until we try to save the @user object. It then gives an error > that it can not save the emails and address, because it doesn''t know > what user_id to write in its foreign keys. > > The only way I could devise was an intricate scheme where I would first > try to save the emails and address, and then the user object. Whenever > something would fail along the way it would rollback any previous > changes and destroy the correct object. This results in a very complex > non-ruby if/then stack which I really hate. > > How am I supposed to save an object spanning multiple models at once and > consistent? > -- > Posted viahttp://www.ruby-forum.com/.--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
After looking through that documentation and your scenario, I suppose one possibility is to perform your saves in a database transaction: transaction do # save the association objects # save the user object end So if any failure occurs during save the whole transaction gets rolled back. I''m not sure if this is the best way to do this though. It does seem like it would be nice if Rails would automatically create a transaction if an object has unsaved associations. Then perform saves on the associations then save the parent object. But, I''m sure there''s probably a good reason that it doesn''t. That being said, I''m more used to a system that maintains an in-memory object graph that takes care of all those details for you. However, that opens up a whole new level of complexity, and a new set of potential gotchas to have to deal with. On Jul 7, 9:45 am, Robert Walker <r0b3rt4...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> There is an explanation of this in the Rails API documentation here: > > http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMet... > > Scroll down to the section: Unsaved objects and associations > > On Jul 7, 9:29 am, Chris Dekker <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> > wrote: > > > So, imagine the following: > > > class User < ActiveRecord::Base > > has_many :emails > > has_one :address > > end > > > class Email < ActiveRecord::Base > > belongs_to :user > > end > > > class Address < ActiveRecord::Base > > belongs_to :user > > end > > > Now I am wondering what the correct Ruby-way to create a user object is > > in the controller when through a form, a new user, a couple of email > > addresses and a street address is posted. > > > The obvious @user = User.new(params[:user]) was my first attempt. The > > problem here is that @user.emails.build and @user.address.build calls > > are fine, until we try to save the @user object. It then gives an error > > that it can not save the emails and address, because it doesn''t know > > what user_id to write in its foreign keys. > > > The only way I could devise was an intricate scheme where I would first > > try to save the emails and address, and then the user object. Whenever > > something would fail along the way it would rollback any previous > > changes and destroy the correct object. This results in a very complex > > non-ruby if/then stack which I really hate. > > > How am I supposed to save an object spanning multiple models at once and > > consistent? > > -- > > Posted viahttp://www.ruby-forum.com/.--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Well then.... Disregard my last post. Apparently, at least with Rails 2.1, it does seems to take care of the associations when saving the parent. On Jul 7, 10:07 am, Robert Walker <r0b3rt4...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> After looking through that documentation and your scenario, I suppose > one possibility is to perform your saves in a database transaction: > > transaction do > # save the association objects > # save the user object > end > > So if any failure occurs during save the whole transaction gets rolled > back. I''m not sure if this is the best way to do this though. > > It does seem like it would be nice if Rails would automatically create > a transaction if an object has unsaved associations. Then perform > saves on the associations then save the parent object. But, I''m sure > there''s probably a good reason that it doesn''t. > > That being said, I''m more used to a system that maintains an in-memory > object graph that takes care of all those details for you. However, > that opens up a whole new level of complexity, and a new set of > potential gotchas to have to deal with. > > On Jul 7, 9:45 am, Robert Walker <r0b3rt4...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > There is an explanation of this in the Rails API documentation here: > > >http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMet... > > > Scroll down to the section: Unsaved objects and associations > > > On Jul 7, 9:29 am, Chris Dekker <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> > > wrote: > > > > So, imagine the following: > > > > class User < ActiveRecord::Base > > > has_many :emails > > > has_one :address > > > end > > > > class Email < ActiveRecord::Base > > > belongs_to :user > > > end > > > > class Address < ActiveRecord::Base > > > belongs_to :user > > > end > > > > Now I am wondering what the correct Ruby-way to create a user object is > > > in the controller when through a form, a new user, a couple of email > > > addresses and a street address is posted. > > > > The obvious @user = User.new(params[:user]) was my first attempt. The > > > problem here is that @user.emails.build and @user.address.build calls > > > are fine, until we try to save the @user object. It then gives an error > > > that it can not save the emails and address, because it doesn''t know > > > what user_id to write in its foreign keys. > > > > The only way I could devise was an intricate scheme where I would first > > > try to save the emails and address, and then the user object. Whenever > > > something would fail along the way it would rollback any previous > > > changes and destroy the correct object. This results in a very complex > > > non-ruby if/then stack which I really hate. > > > > How am I supposed to save an object spanning multiple models at once and > > > consistent? > > > -- > > > Posted viahttp://www.ruby-forum.com/.--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
> Well then.... > > Disregard my last post. Apparently, at least with Rails 2.1, it does > seems to take care of the associations when saving the parent. >Rails has always done wrapped new parent/child commits in a transaction; that''s nothing new to 2.1. I suspect that Chris'' issue has to do with validations. My guess is that what he''s omitted from his class declarations in the initial post is that he''s validating for the presence/numericality of user_id but it''s not yet known. If my guess is correct then it''s a pretty simple refinement of the validation call. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---