Has_many and after_create

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 = “[email protected]
@sent_on = Time.now
@body[:user] = user
end
end

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.

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.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs