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