I have a simple model where users have one or more emails and after_create is used to send new users a Welcome email. If I create and save a User then after_create is triggered but there is no email associated with the user. But the problem is that to add an Email to a User I need to have an id for User which only happens after a save. So is there a way to create both an Email and a User such that when the after_create for a user is called, the user has an associated email? Cheers ------ def self.up create_table "users", do |t| t.column :first_name, :string t.column :last_name, :string end create_table :emails do |t| t.column :email_address, :string t.column :primary, :boolean t.column :user_id, :integer end end class User < ActiveRecord::Base has_many :emails, :dependent => :destroy end class Email < ActiveRecord::Base belongs_to :user end class UserController < ApplicationController observer :user_observer def signup @user = User.new(params[:user]) @email = Email.new(params[:email]) return unless request.post? @email.user = @user #doesn''t work since @user hasn''t been saved yet @email.save! @user.save! end end class UserObserver < ActiveRecord::Observer def after_create(user) UserNotifier.deliver_welcome(user) end end class UserNotifier < ActionMailer::Base def welcome(user) setup_email(user) @subject = ''Welcome'' @body[:url] = ''Welcome to our website!" end protected def setup_email(user) @recipients = "#{Email.find_by_user_id_and_primary(user, true)}" @from = "foo-+LBmYUDmh58@public.gmane.org" @sent_on = Time.now @body[:user] = user end end --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
It looks like the standard way of dealing with this issue is to use build method added by has_many: class UserController < ApplicationController observer :user_observer def signup @user = User.new(params[:user]) @email = @user.emails.build(params[:email]) return unless request.post? @user.save! end end This still doesn''t solve the problem though, since the observer registered for after_create is called after the user record is created but before the email record is created, causing the code to fail since the email associated with the user hasn''t been created yet. On 10/9/06, Cocoa Guy <cocoa.guy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> I have a simple model where users have one or more emails and > after_create is used to send new users a Welcome email. If I create > and save a User then after_create is triggered but there is no email > associated with the user. But the problem is that to add an Email to a > User I need to have an id for User which only happens after a save. > > So is there a way to create both an Email and a User such that when > the after_create for a user is called, the user has an associated > email? > > Cheers > ------ > def self.up > create_table "users", do |t| > t.column :first_name, :string > t.column :last_name, :string > end > create_table :emails do |t| > t.column :email_address, :string > t.column :primary, :boolean > t.column :user_id, :integer > end > end > > class User < ActiveRecord::Base > has_many :emails, :dependent => :destroy > end > > class Email < ActiveRecord::Base > belongs_to :user > end > > class UserController < ApplicationController > observer :user_observer > > def signup > @user = User.new(params[:user]) > @email = Email.new(params[:email]) > return unless request.post? > @email.user = @user #doesn''t work since @user hasn''t been saved yet > @email.save! > @user.save! > end > > end > > class UserObserver < ActiveRecord::Observer > def after_create(user) > UserNotifier.deliver_welcome(user) > end > end > > class UserNotifier < ActionMailer::Base > def welcome(user) > setup_email(user) > @subject = ''Welcome'' > @body[:url] = ''Welcome to our website!" > end > > protected > def setup_email(user) > @recipients = "#{Email.find_by_user_id_and_primary(user, true)}" > @from = "foo-+LBmYUDmh58@public.gmane.org" > @sent_on = Time.now > @body[:user] = user > end > end >--~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---
I temporarily resolved this by using an after_create callback rather than an observer and moving the has_many call to after the after_create call as mentioned here: http://blog.inquirylabs.com/2006/09/23/an-after_create_before_association_create-callback/ (I also had to fix a minor bug replacing Email.find_by_user_id_and_primary(user, true) with Email.find_by_user_id_and_primary(user, true).email_address) I still have two basic Rails questions: 1. How can I force an observer to be called *after* all of the object''s associated objects have been created? 2. This technique of placing the callback before or after the has_many association is clever, but is this intended or simply a side effect of the ActiveRecord code? It seems like a fragile technique that can easily break with future Rails releases and I haven''t seen it mentioned elsewhere. On 10/9/06, Cocoa Guy <cocoa.guy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > It looks like the standard way of dealing with this issue is to use > build method added by has_many: > > class UserController < ApplicationController > observer :user_observer > > def signup > @user = User.new(params[:user]) > @email = @user.emails.build(params[:email]) > return unless request.post? > @user.save! > end > > end > > This still doesn''t solve the problem though, since the observer > registered for after_create is called after the user record is created > but before the email record is created, causing the code to fail since > the email associated with the user hasn''t been created yet. > > On 10/9/06, Cocoa Guy <cocoa.guy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > I have a simple model where users have one or more emails and > > after_create is used to send new users a Welcome email. If I create > > and save a User then after_create is triggered but there is no email > > associated with the user. But the problem is that to add an Email to a > > User I need to have an id for User which only happens after a save. > > > > So is there a way to create both an Email and a User such that when > > the after_create for a user is called, the user has an associated > > email? > > > > Cheers > > ------ > > def self.up > > create_table "users", do |t| > > t.column :first_name, :string > > t.column :last_name, :string > > end > > create_table :emails do |t| > > t.column :email_address, :string > > t.column :primary, :boolean > > t.column :user_id, :integer > > end > > end > > > > class User < ActiveRecord::Base > > has_many :emails, :dependent => :destroy > > end > > > > class Email < ActiveRecord::Base > > belongs_to :user > > end > > > > class UserController < ApplicationController > > observer :user_observer > > > > def signup > > @user = User.new(params[:user]) > > @email = Email.new(params[:email]) > > return unless request.post? > > @email.user = @user #doesn''t work since @user hasn''t been saved yet > > @email.save! > > @user.save! > > end > > > > end > > > > class UserObserver < ActiveRecord::Observer > > def after_create(user) > > UserNotifier.deliver_welcome(user) > > end > > end > > > > class UserNotifier < ActionMailer::Base > > def welcome(user) > > setup_email(user) > > @subject = ''Welcome'' > > @body[:url] = ''Welcome to our website!" > > end > > > > protected > > def setup_email(user) > > @recipients = "#{Email.find_by_user_id_and_primary(user, true)}" > > @from = "foo-+LBmYUDmh58@public.gmane.org" > > @sent_on = Time.now > > @body[:user] = user > > end > > end > > >--~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---