Hello, I have two models, User and Person. Basically users are users of the system while people is a kind of address book. But every user is also a person so I created this relationship: class User < ActiveRecord::Base belongs_to :person end class Person < ActiveRecord::Base has_one :user end Now, on creating a user I want to automatically create a person. Is this the way to do it: before_validation :create_person def create_person if person.nil? && person_id.nil? self.person = Person.create!(:name => email, :tenant => tenant) end end Thanks. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/QwM_6LtsGoUJ. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
You might want to use after_initialize callback, e.g. after_initialize :build_person_if_no_person def build_person_if_no_person build_person if new_record? && person.nil? end The person.nil? check might be needed in some cases, for example if you want to use Person.new.build_user. (I did not try the above code, but this is almost an excerpt from my application, which uses this approach). I wouldn''t recommend creating object in before_validation callback, because: 1) when validation fails, you''re left with not needed Person records in the database 2) one day you may want to save User and skip validation, in which case you won''t have the Person object created. Overall, I like the idea of using composition between User and Person instead of inheritance - I usually do it the same way in my applications. -- 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-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
I''m assuming you don''t want to create a Person if your User validations fail and vice versa. One way to do it is as follows. This will validate your Person during the validation phase for User, and if all is good save your Person then save User. Note that this doesn''t preclude any database constraint/error from screwing up your User save, resulting in orphaned Persons. To be really safe you should wrap both Person and User save operations in a transaction (http:// api.rubyonrails.org/classes/ActiveRecord/Transactions/ ClassMethods.html). class User < ActiveRecord::Base bleongs_to :person, :validate => true before_validation :create_person before_create :save_person def create_person if person.nil? && person_id.nil? self.person = Person.new(:name => email, :tenant => tenant) end end def save_person self.person.save! end end On Aug 27, 12:42 pm, J. Pablo Fernández <pup...-GAtDADarczzQT0dZR+AlfA@public.gmane.org> wrote:> Hello, > > I have two models, User and Person. Basically users are users of the system > while people is a kind of address book. But every user is also a person so I > created this relationship: > > class User < ActiveRecord::Base > belongs_to :person > end > > class Person < ActiveRecord::Base > has_one :user > end > > Now, on creating a user I want to automatically create a person. Is this the > way to do it: > > before_validation :create_person > > def create_person > if person.nil? && person_id.nil? > self.person = Person.create!(:name => email, :tenant => tenant) > end > end > > Thanks.-- 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-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@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.
2011/8/28 J. Pablo Fernández <pupeno-GAtDADarczzQT0dZR+AlfA@public.gmane.org>> Hello, > > I have two models, User and Person. Basically users are users of the system > while people is a kind of address book. But every user is also a person so I > created this relationship: > > class User < ActiveRecord::Base > belongs_to :person > end > > class Person < ActiveRecord::Base > has_one :user > end > > Now, on creating a user I want to automatically create a person. Is this > the way to do it: > > before_validation :create_person > > def create_person > if person.nil? && person_id.nil? > self.person = Person.create!(:name => email, :tenant => tenant) > end > end > >If you use the method above, there''s a big chance that a Person is created when the associated User fails the validation. Look at accepts_nested_attributes_for.> Thanks. > > -- > You received this message because you are subscribed to the Google Groups > "Ruby on Rails: Talk" group. > To view this discussion on the web visit > https://groups.google.com/d/msg/rubyonrails-talk/-/QwM_6LtsGoUJ. > To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org > To unsubscribe from this group, send email to > rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org > For more options, visit this group at > http://groups.google.com/group/rubyonrails-talk?hl=en. >-- ------------------------------------------------------------- visit my blog at http://jimlabs.heroku.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-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@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.
As far as I know, all callbacks and the save is run inside a transaction, so if saving fails for the user, the person won''t be save. I still had the issue that just calling user.valid? would create a record in the database when not expected. I did switch to calling new instead of create and all my tests about it are passing. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/_XagD0hIQ5UJ. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Thanks for pointing to after_initialize, your point 2 is very valid. About point 1, everything is wrapped automatically in a transaction by Rails and I have tests for it. Is that not the case (and my tests are passing due to the magic of the universe or something?). My problem is a little bit more complex, as both users and people are in tenant, my code looks like this: def create_person if person_id.nil? && person.nil? self.person = Person.new self.tenant.people << self.person end end The problem is that in after_initialize, self.tenant is still nil. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/x1QO3wjWSGcJ. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Thanks. My code looks more like yours now, using new instead of create. But save_person is not needed, in my case at least, the person gets saved automatically and as far as I know, all callbacks and the saving are wrapped in a transaction by Rails automatically. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/J_1znmqJZvgJ. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.