0

I'd like to know what the best way is to send off an email when a record is created or updated specifically in the inherited_resources framework.

Right now I'm doing this:

  def create
    create!
    UserMailer.create(object).deliver if @user.valid?
  end

  def update
    update!
    UserMailer.update(object).deliver if @user.valid?
  end

It makes sense but seems a little bit clunky. I tried doing it in the success response block but that seems like a bad thing to do too. I've also tried chaining on to the update_resource and create_resource methods. They all work, but all of them don't seem very elegant.

Maybe I'm trying to minimise code too much!

Brendon Muir
  • 4,540
  • 2
  • 33
  • 55

5 Answers5

1

I prefer the DDD approach, using ActiveRecord callbacks

So, if you want to send an email after each save of your model Example, you should do this

class Example < ActiveRecord::Base
  after_save :send_email

  protected
  def send_email
    UserMailer.create(object).deliver
  end
end
Paul Ballesty
  • 86
  • 1
  • 3
  • This seems like the obvious approach until it's necessary to not email after every change to the model. After a lot of thought, I'm certain it's better to send the email from the controller (this makes the application more flexible and testing easier). – Brendon Muir Sep 14 '13 at 06:28
  • Yeap. This approach is going to send an email after every model update. But if you need to change that behavior, you can do it adding code to the send_email function (you can check the model variables if you want). If you place your functionality in the controller, and you need to send the same email in another part of the app, it's highly probable that your going to repeat the code, and that's not good. So I don't think that your app is more flexible. And about testing, I think that is the same, you can test your controller or your model, or both. – Paul Ballesty Sep 15 '13 at 03:05
  • Thanks Paul, I think there are benefits to both approaches. Having to use a one liner two or three times in the app doesn't really count as repetition in my book. Another way around this problem is to use an abstraction framework like [Interactor](https://github.com/collectiveidea/interactor). – Brendon Muir Sep 16 '13 at 05:54
1

Here's what I'm doing currently. To me it's the best and less obfuscated approach:

  after_filter :send_create_email, :only => :create
  after_filter :send_update_email, :only => [:update, :update_password]

  private

  def send_create_email
    UserMailer.create(@user).deliver if @user.valid?
  end

  def send_update_email
    UserMailer.update(@user).deliver if @user.valid?
  end

Nathans approach was good until I needed non-standard method names.

Brendon Muir
  • 4,540
  • 2
  • 33
  • 55
0

I prefer this approch :

def create
  if @user.save # if your user is saved it should be valid
    do something
  else
    do something else
  end
end

def update
  if @user.update_attributes(params[:user])
    do something
  else
    do something else
  end
end
phron
  • 1,795
  • 17
  • 23
  • Thanks for this. Unfortunately I can't accept this answer because it doesn't deal with inherited_resources specifically. – Brendon Muir May 14 '13 at 02:08
0

You could refactor the sending of email and use an after filter. In this case, both create and update could be removed unless you're modifying their default behavior. Untested but this is the idea:

after_filter :send_email, :only => [ :create, :update ]

private
def send_email
  UserMailer.send(request[:action].to_sym, @user).deliver if @user.valid?
end
nbrew
  • 771
  • 5
  • 6
0

I reckon overwriting create_resource is good approach:

  # Responsible for saving the resource on :create method. Overwriting this
  # allow you to control the way resource is saved. Let's say you have a
  # PassworsController who is responsible for finding an user by email and
  # sent password instructions for him. Instead of overwriting the entire
  # :create method, you could do something:
  #
  #   def create_resource(object)
  #     object.send_instructions_by_email
  #   end
  #
  def create_resource(object)
    object.save
  end

It can look like that:

  ActiveAdmin.register SomeModel do
    controller do
      def create_resource(object)
        # TODO
      end
    end
  end
Ivan
  • 3,187
  • 1
  • 19
  • 16