diff --git a/README.rdoc b/README.rdoc
index 85236a2f..63818a98 100644
--- a/README.rdoc
+++ b/README.rdoc
@@ -7,7 +7,7 @@ Devise is a flexible authentication solution for Rails based on Warden. It:
* Allows you to have multiple roles (or models/scopes) signed in at the same time;
* Is based on a modularity concept: use just what you really need.
-Right now it's composed of four mainly modules:
+Right now it's composed of five mainly modules:
* Authenticable: responsible for encrypting password and validating authenticity of a user while signing in.
* Confirmable: responsible for verifying whether an account is already confirmed to sign in, and to send emails with confirmation instructions.
@@ -170,6 +170,37 @@ Devise let's you setup as many roles as you want, so let's say you already have
current_admin
admin_session
+== I18n
+
+Devise check for flash messages using i18n, so you're able to customize them easily. For example, to change the sign in message you should setup your locale file this way:
+
+ en:
+ devise:
+ sessions:
+ signed_in: 'Signed in successfully.'
+
+You can also create distinct messages based on the resource you've configured:
+
+ en:
+ devise:
+ sessions:
+ user:
+ signed_in: 'Welcome user, you are signed in.'
+ admin:
+ signed_in: 'Hello admin!'
+
+Devise notifier uses the same pattern to create subject messages, but it is not able to know what scope you are, he just know the record (ie user instance) that was sent to it. So you need to customize messages based on the model class name (usually the same as the resource name, if you follow basic conventions):
+
+ en:
+ devise:
+ notifier:
+ confirmation_instructions: 'Hello everybody!'
+ user:
+ confirmation_instructions: 'Hello User! Please confirm your email'
+ reset_password_instructions: 'Reset instructions'
+
+Take a look at our locale file to check all available messages.
+
== TODO
Please refer to TODO file.
diff --git a/TODO b/TODO
index 58eb0175..978cc4bf 100644
--- a/TODO
+++ b/TODO
@@ -2,7 +2,6 @@
* Create generators
* Allow stretches and pepper per model
-* Mailer subjects namespaced by model
* Use request_ip in session cookies
* Session timeout
@@ -34,3 +33,4 @@
* Sign user in automatically after confirming or changing it's password
* Add remember me
+* Mailer subjects namespaced by model
diff --git a/app/models/notifier.rb b/app/models/notifier.rb
index d7050761..0e5bfbd6 100644
--- a/app/models/notifier.rb
+++ b/app/models/notifier.rb
@@ -4,20 +4,19 @@ class Notifier < ::ActionMailer::Base
# Deliver confirmation instructions when the user is created or its email is
# updated, and also when confirmation is manually requested
def confirmation_instructions(record)
- subject translate(:confirmation_instructions, :default => 'Confirmation instructions')
- setup_mail(record)
+ setup_mail(record, :confirmation_instructions)
end
# Deliver reset password instructions when manually requested
def reset_password_instructions(record)
- subject translate(:reset_password_instructions, :default => 'Reset password instructions')
- setup_mail(record)
+ setup_mail(record, :reset_password_instructions)
end
private
# Configure default email options
- def setup_mail(record)
+ def setup_mail(record, key)
+ subject translate(record, key)
from self.class.sender
recipients record.email
sent_on Time.now
@@ -25,7 +24,20 @@ class Notifier < ::ActionMailer::Base
body record.class.name.downcase.to_sym => record, :resource => record
end
- def translate(key, options={})
- I18n.t(key, {:scope => [:devise, :notifier]}.merge(options))
+ # Setup subject namespaced by model. It means you're able to setup your
+ # messages using specific resource scope, or provide a default one.
+ # Example (i18n locale file):
+ #
+ # en:
+ # devise:
+ # notifier:
+ # confirmation_instructions: '...'
+ # user:
+ # notifier:
+ # confirmation_instructions: '...'
+ def translate(record, key)
+ I18n.t(:"#{record.class.name.downcase}.#{key}",
+ :scope => [:devise, :notifier],
+ :default => key)
end
end
diff --git a/lib/devise/controllers/helpers.rb b/lib/devise/controllers/helpers.rb
index 3e344546..65dc1e3d 100644
--- a/lib/devise/controllers/helpers.rb
+++ b/lib/devise/controllers/helpers.rb
@@ -76,8 +76,7 @@ module Devise
# devise:
# passwords:
# #default_scope_messages - only if resource_scope is not found
- # user:
- # passwords:
+ # user:
# #resource_scope_messages
#
# Please refer to README or en.yml locale file to check what messages are
diff --git a/test/mailers/confirmation_instructions_test.rb b/test/mailers/confirmation_instructions_test.rb
index bfbf38de..644b9b4e 100644
--- a/test/mailers/confirmation_instructions_test.rb
+++ b/test/mailers/confirmation_instructions_test.rb
@@ -1,42 +1,59 @@
-require 'test_helper'
+require 'test/test_helper'
class ConfirmationInstructionsTest < ActionMailer::TestCase
def setup
setup_mailer
- I18n.backend.store_translations :en, {:devise => { :notifier => { :confirmation_instructions => 'Account Confirmation' } }}
Notifier.sender = 'test@example.com'
- @user = create_user
- @mail = ActionMailer::Base.deliveries.first
+ end
+
+ def user
+ @user ||= create_user
+ end
+
+ def mail
+ @mail ||= begin
+ user
+ ActionMailer::Base.deliveries.first
+ end
end
test 'email sent after creating the user' do
- assert_not_nil @mail
+ assert_not_nil mail
end
test 'content type should be set to html' do
- assert_equal 'text/html', @mail.content_type
+ assert_equal 'text/html', mail.content_type
end
test 'send confirmation instructions to the user email' do
- assert_equal [@user.email], @mail.to
+ mail
+ assert_equal [user.email], mail.to
end
test 'setup sender from configuration' do
- assert_equal ['test@example.com'], @mail.from
+ assert_equal ['test@example.com'], mail.from
end
test 'setup subject from I18n' do
- assert_equal 'Account Confirmation', @mail.subject
+ store_translations :en, :devise => { :notifier => { :confirmation_instructions => 'Account Confirmation' } } do
+ assert_equal 'Account Confirmation', mail.subject
+ end
+ end
+
+ test 'subject namespaced by model' do
+ store_translations :en, :devise => { :notifier => { :user => { :confirmation_instructions => 'User Account Confirmation' } } } do
+ assert_equal 'User Account Confirmation', mail.subject
+ end
end
test 'body should have user info' do
- assert_match /#{@user.email}/, @mail.body
+ assert_match /#{user.email}/, mail.body
end
test 'body should have link to confirm the account' do
host = ActionMailer::Base.default_url_options[:host]
- confirmation_url_regexp = %r{}
- assert_match confirmation_url_regexp, @mail.body
+ confirmation_url_regexp = %r{}
+ assert_match confirmation_url_regexp, mail.body
end
end
diff --git a/test/mailers/reset_password_instructions_test.rb b/test/mailers/reset_password_instructions_test.rb
index 66772b27..835dcbc2 100644
--- a/test/mailers/reset_password_instructions_test.rb
+++ b/test/mailers/reset_password_instructions_test.rb
@@ -1,43 +1,62 @@
-require 'test_helper'
+require 'test/test_helper'
class ResetPasswordInstructionsTest < ActionMailer::TestCase
def setup
setup_mailer
- I18n.backend.store_translations :en, {:devise => { :notifier => { :reset_password_instructions => 'Reset instructions' } }}
Notifier.sender = 'test@example.com'
- @user = create_user
- @user.send_reset_password_instructions
- @mail = ActionMailer::Base.deliveries.last
+ end
+
+ def user
+ @user ||= begin
+ user = create_user
+ user.send_reset_password_instructions
+ user
+ end
+ end
+
+ def mail
+ @mail ||= begin
+ user
+ ActionMailer::Base.deliveries.last
+ end
end
test 'email sent after reseting the user password' do
- assert_not_nil @mail
+ assert_not_nil mail
end
test 'content type should be set to html' do
- assert_equal 'text/html', @mail.content_type
+ assert_equal 'text/html', mail.content_type
end
test 'send confirmation instructions to the user email' do
- assert_equal [@user.email], @mail.to
+ assert_equal [user.email], mail.to
end
test 'setup sender from configuration' do
- assert_equal ['test@example.com'], @mail.from
+ assert_equal ['test@example.com'], mail.from
end
test 'setup subject from I18n' do
- assert_equal 'Reset instructions', @mail.subject
+ store_translations :en, :devise => { :notifier => { :reset_password_instructions => 'Reset instructions' } } do
+ assert_equal 'Reset instructions', mail.subject
+ end
+ end
+
+ test 'subject namespaced by model' do
+ store_translations :en, :devise => { :notifier => { :user => { :reset_password_instructions => 'User Reset Instructions' } } } do
+ assert_equal 'User Reset Instructions', mail.subject
+ end
end
test 'body should have user info' do
- assert_match /#{@user.email}/, @mail.body
+ assert_match /#{user.email}/, mail.body
end
test 'body should have link to confirm the account' do
host = ActionMailer::Base.default_url_options[:host]
- confirmation_url_regexp = %r{}
- assert_match confirmation_url_regexp, @mail.body
+ reset_url_regexp = %r{}
+ assert_match reset_url_regexp, mail.body
end
end
diff --git a/test/support/model_tests_helper.rb b/test/support/model_tests_helper.rb
index 4457f13a..221eb59b 100644
--- a/test/support/model_tests_helper.rb
+++ b/test/support/model_tests_helper.rb
@@ -3,6 +3,15 @@ class ActiveSupport::TestCase
ActionMailer::Base.deliveries = []
end
+ def store_translations(locale, translations, &block)
+ begin
+ I18n.backend.store_translations locale, translations
+ yield
+ ensure
+ I18n.reload!
+ end
+ end
+
# Helpers for creating new users
#
def generate_unique_email