views:

22

answers:

2

I implemented an authentication system using authlogic, and have added password reset functionality as per this tutorial http://github.com/rejeep/authlogic-password-reset-tutorial

It all works, but I am confused as to why it does..

There is this code..

class User < ActiveRecord::Base
  def deliver_password_reset_instructions!
    reset_perishable_token!
    Notifier.deliver_password_reset_instructions(self)
  end
end

and this

class Notifier < ActionMailer::Base
  def password_reset_instructions(user)
    subject      "Password Reset Instructions"
    from         "[email protected]"
    recipients   user.email
    content_type "text/html"
    sent_on      Time.now
    body         :edit_password_reset_url => edit_password_reset_url(user.perishable_token)
  end
end

This line confuses me

Notifier.deliver_password_reset_instructions(self)

as the method in the Notifier class is called

password_reset_instructions

without the deliver_ bit.

So whats going on here? how come it all works?

+1  A: 

This is the Rails 2 ActionMailer convention.

To deliver an email, use YourMailerClass.deliver_NAME_OF_THE_METHOD. To initialize an email, use YourMailerClass.create_NAME_OF_THE_METHOD.

Rails will automatically creates an instance of the Mailer class, call your method and deliver the email object.

Simone Carletti
+3  A: 

Great Question, A lot of people forget to ask these questions.

Do you notice, that you never really Instantiate your mailer class objects. Your mailer class methods are usually wrapped with this deliver_<method_name>

So internally this uses the concept of method_missing in ruby. Suppose you call a certain method in a ruby which doesn't exist for that object, ruby calls the method_missing method. Which is defined in the "ActionMailer::Base" code

def method_missing(method_symbol, *parameters)#:nodoc:
  case method_symbol.id2name
    when /^create_([_a-z]\w*)/  then new($1, *parameters).mail
    when /^deliver_([_a-z]\w*)/ then new($1, *parameters).deliver!
    when "new" then nil
    else super
  end
end

so if a method matches "deliver_" and any combination of lower cases letters, Rails instantiates your Mailer Class ( by calling the "new" ) and sends it with the parameters to the initializer and calls "deliver!" method to finally deliver the mail.

Same goes for "create_<method_name>" type methods

Rishav Rastogi
Thanks very much for your detailed explanation, it makes sense now.
pingu