From my research, it seems there's a general consensus that sending email is something that belongs in the Controller. So for example, if I have a signup form for People, when a user submits a signup form, I would validate the Person, and then once the Person is saved, the People controller would do more stuff - for example, send an email confirmation message, send a welcome email with attachments, and send an email to an admin.
That's fine until there's another part of the application that ALSO creates people. Easy enough to call the Person model and create(), but what about all that extra stuff that might (or might not!) need to happen... should the developer have to remember to do all that stuff in any controller of the application? How do you keep your code DRY in this case?
My inclination was to make an "after create" filter in the Person model, and perhaps add an optional parameter that would disable sending of email when a Person is created, but testing becomes a nightmare, etc.
How do you keep from having all the other parts of the application have to know so many rules about creating a new Person? I want to refactor, but not sure which direction to go.
So, you create users in controllers and you create them somewhere else, and you want to keep DRY? This calls for a builder!
class UserBuilder
attr_reader :user_params, :user, :send_welcome_email
def initialize(user_params, send_welcome_email: true)
@user_params = user_params
@send_welcome_email = send_welcome_email
end
def build
instantiate_user
end
def create
instantiate_user
before_create(user)
return false unless user.save
after_create(user)
end
private
def instantiate_user
@user ||= User.new(user_params)
end
def before_create(user)
end
def after_create(user)
# or do whatever other check you can imagine
UserMailer.welcome_email(user) if send_welcome_email
end
end
Usage:
# in controller
UserBuilder.new(params[:user]).create
# somewhere else
user_params = { email: '[email protected]' }
UserBuilder.new(user_params, send_welcome_email: false)
Also, CFWheels only provides sendEmail() for controllers, not models
This is ruby, it has built-in email capabilities. But fine, I'll play along. In this case, I would add some event/listener sauce on top.
class UserBuilder
include Wisper::Publisher
...
def after_create(user)
# do whatever you always want to be doing when user is created
# then notify other potentially interested parties
broadcast(:user_created, user)
end
end
# in controller
builder = UserBuilder.new(params[:user])
builder.on(:user_created) do |user|
sendEmail(user) # or whatever
end
builder.create