“...I've been working since 2008 with Ruby / Ruby on Rails, love a bit of Elixir / Phoenix and learning Rust. I also poke through other people's code and make PRs for OpenSource Ruby projects that sometimes make it. Currently working for InPay...”

Rob Lacey (contact@robl.me)
Senior Software Engineer, Brighton, UK

ActionMailer with ActiveRecord validation

I wanted to be able to send out a mail from a controller but also validate the incoming args in a clean way. Like so…

class MessagesController < ActionController::Base

def deliver
  @message = Message.build(params[:message])
  if @message.deliver
    redirect_to home_path
  else
    render :action
  end
end

ActionMailer::Base hides the initialize methods in method_missing and most of the time you are calling ActionMailer::Base.deliver_mymail(args). This allows you to specify all of the standard actionmailer settings in Message.build and return a Message object.

class Message < ActionMailer::Base

  include Validatable
  validates_presence_of :from, :body

  def self.build(args = {})
    new('default', args)
  end

  def self.action_mailer_methods
    return [
      :bcc,
      :body,
      :cc,
      :charset,
      :content_type,
      :from,
      :reply_to,
      :headers,
      :implicit_parts_order,
      :mime_version,
      :recipients,
      :sent_on,
      :subject,
      :template
    ]
  end

  def default(args)
    new_args = args.clone
    new_args.each do |k,v|
      if self.class.action_mailer_methods.include?(k)
        send(k, new_args.delete(k))
      end
    end

    if body.kind_of?(Hash)
      @body.merge!(new_args)
    end

  end

  def deliver
    if self.valid?
      return deliver!
    else
      return false
    end
  end

end