Rails I18n randomly loads wrong locale - ruby-on-rails

The Rails app uses I18n. Users will be using the site in English and the site will randomly load in Spanish.
The application only switches locales in two places.
The application.rb has a method that switches locales based on the domain name.
There is a mailer that uses the with_locale method to switch locales based on the recipient's locale. This is done because a user whose primary locale is English, may send a message to a user whose primary locale is Spanish.
Here is the mailer method for a message notification:
class Notifier < ActionMailer::Base
def message_notification(message_id, recipient_id)
#message = Message.find(message_id)
#recipient = #user = User.find(recipient_id)
I18n.with_locale(#recipient.locale) do
mail(
to: #recipient.email,
subject: I18n.t('app.new_message.subject',
name: #message.sender.name),
from: I18n.t('app.notifier.from')
) do |format|
format.html { render layout: 'notifier-single' }
end
end
end
end
The app uses Sidekiq with Redis to process delayed jobs. So, the method above is delayed like so:
Notifier.delay.message_notification(self.id, recipient.id)
I wondered if something about the way Sidekiq handles threads might be causing this.
Any ideas?
UPDATE:
From this page on the Sidekiq wiki:
https://github.com/mperham/sidekiq/wiki/Problems-and-Troubleshooting
"aws-sdk (According to a somewhat old post in the discussion group, this gem is thread-safe with the exception of the use of autoload. More details here. Explicitly calling AWS.eager_autoload! during initialization should allow it to be used with Sidekiq)"
The app uses Amazon SES to deliver mail, by way of the aws-sdk gem.
I added AWS.eager_autoload! to the initializer. I will watch and see if the problem continues to persist (I haven't found a way to replicate or test it). That said I'm not sure if that would be related or not so any advice would be appreciated.

Related

sending emails using templates in Mandrill

I've read through the docs and still am unclear on how to actually use these templates in mandrill.
Currently I have a rails app with the standard Rails mailers (located in: App > views > welcome_mailer > welcome_email.html.erb) being sent through the Mandrill SMTP setup. This is working fine.
Now, I have a template in Mandrill ready to go, now what?
How do I actually use this template, do I need to adjust the code on my app to make a different call, or do I need to do something on the mandrill dashboard to tell it to use the new template instead of the rails version being sent now.
How do I actually use this template?
Thank you in advance.
You can use mandrill_mailer gem, inherit your mailer from MandrillMailer::TemplateMailer and then send it as usual InvitationMailer.invite(invitation).deliver.
Without any gems :
To use mandrill template you first need to create one in your mandrill account and then in your mailer add a correct header which tells the name of the template. Then mandrill will by magic automatically call that template.
Example:
# app/mailers
class CardMailer < ActionMailer::Base
default from: "admin#domain.ch"
def welcome(card)
mail to: card.responsable.email,
from: "\"Andrey\" <admin#domain.ch>",
subject: 'Welcome in my website'
headers['X-MC-MergeVars'] = "{\"TYPE\":\"#{card.card_type.name}\"}" # variables
headers['X-MC-Template'] = "welcome" # template
headers['X-MC-AutoText'] = 1 # generate text version
headers['X-MC-InlineCSS'] = "true" # inline css
end
end
In my case, it uses my "welcome" template. Just use the name of your mandrill template.
As you can see, there are many other headers available. See the full-list here.
Note : even if you don't use rails template any more, you still need one in your view.

Rails ActionMailer : filter emails to a specific list in development

Without editing any of my /app files, I'd like to edit either development.rb or an initializer where I set a whitelist of testers.
Then the emails are sent only to those people in the whitelist (not to spam other users mailbox).
I though of overriding deliver!, or the user.get_mail method but :
it's not in /config where it should be
it doesn't filter gem generated emailing (ie devise, mailboxer etc.)
You might want to check out Action mailer interceptors
And do something like this :
class BetaEmailInterceptor
def self.delivering_email(message)
message.perform_deliveries = false unless WHITELIST.include?(message.to.first)
end
end
And
ActionMailer::Base.register_interceptor(BetaEmailInterceptor)
This is a very naive implementation and will only work if the first recipient is whitelisted but you get the idea.

Better to attach a simple function as class method or a module?

I have a simple function to prevent emails from being sent to customers when testing locally:
def safe_emails emails
if Rails.env == 'production'
emails
else
emails.select{|e| ['staff#example.com', 'staff2#example.com'].include?(e) }
end
end
I want to share that function between mailers. I can see two options, a module or a class method.
Option 1: Module
class ReportMailer < ActionMailer::Base
include SafeEmailer
def daily emails
mail_to: safe_emails(emails)
end
end
Option2: Class Method
class ReportMailer < ActionMailer::Base
def daily emails
mail_to: SafeEmailer.safe_emails(emails)
end
end
The class method is a no-no according to some due to global scope, including a module with one method doesnt seem all that attractive. Monkey-patching ActionMailer to throw the method in there also seems like it could cause trouble (when Rails 4.3 introduces the safe_emails method or whatever).
I would go with module option even if it's a simple one function module. Keeping a generic function that can eventually be used by multiple classes in a module makes much more sense than defining it inside a class.
If Rails 4.3 is of your concern then you can simply replace your include MySafeEmailModule with whatever Rails 4.3 would include this function in, as compared to find and replace all calls to ReportMailer.daily_emails.
Neither – in your case, you'd need a policy object, that decides who receives email regarding the Rails.env. I'd keep that logic outside the ReportMailer.
I'd go with something like:
UserMailer.welcome_email(#user).deliver if SafeEmailer.new(#user.email).safe?
This is probably the easiest way.
Set the below configuration in your non production environments.(config/environments/.rb)
config.action_mailer.delivery_method = :smtp (default), :sendmail, :test, or :file
Have a look at letter opener gem. You could have the delivery_method set as letter_opener and have the emails open in browser instead of actually sending them in your non production environments.

How to intercept ActionMailer's messages on rails 3?

I'm trying to intercept messages in my rails (3.0.10) app to modify the body. While I was able to find some info about how to do that, it seems something has changed and now using the old methods no longer work.
I use a code that looks like this:
class Hook
def self.delivering_email(message)
message.subject = 'Hook changed the subject'
end
end
ActionMailer::Base.register_interceptor(Hook)
After sending an email, the subject doesn't get changed!
I also found a tweet that indicates that interceptors are not called when using the deliver method on messages, but the premailer-rails3 gem uses the same approach I used and it works there (The plugin specifically mentions it works with the deliver method)!
I'm out of ideas here, so what is causing my problem?
It sounds like it might be an order of operations problem.
Have you considered putting the entire code block you referenced in an initializer like config/initializers/mail_hook.rb?
If that premailer plugin works, the only difference I can think of is when the interception hook is registered in the app initialization process.
see RailsCast or AsciiCast Episode #206
http://railscasts.com/episodes/206-action-mailer-in-rails-3
http://asciicasts.com/episodes/206-action-mailer-in-rails-3
Relevant part from the first episode,
/lib/development_mail_interceptor.rb
class DevelopmentMailInterceptor
def self.delivering_email(message)
message.subject = "[#{message.to}] #{message.subject}"
message.to = "eifion#asciicasts.com"
end
end
/config/initializers/setup_mail.rb
Mail.register_interceptor(DevelopmentMailInterceptor) if Rails.env.development?

How do I preview emails in Rails?

This might be a dumb question but when I'm putting together an HTML email in Rails, is there a particularly easy built-in way to preview the template it in the browser or do I need to write some sort of custom controller that pulls it in as its view?
Action Mailer now has a built in way of previewing emails in Rails 4.1. For example, check this out:
# located in test/mailers/previews/notifier_mailer_preview.rb
class NotifierPreview < ActionMailer::Preview
# Accessible from http://localhost:3000/rails/mailers/notifier/welcome
def welcome
Notifier.welcome(User.first)
end
end
Daniel's answer is a good start, but if your email templates contain any dynamic data, it won't work. E.g. suppose your email is an order receipt and within it you print out #order.total_price - using the previous method the #order variable will be nil.
Here's a little recipe I use:
First, since this email preview functionality is definitely for internal use only, I set up some generic routes in the admin namespace:
#routes.rb
MySite::Application.routes.draw do
namespace :admin do
match 'mailer(/:action(/:id(.:format)))' => 'mailer#:action'
end
end
Next, I create the controller. In this controller, I create one method per email template. Since most emails contain dynamic data, we need to populate whatever member variables the template expects.
This could be done with fixtures, but I typically prefer to just grab some pseudo-random real data. Remember - this is NOT a unit test - this is purely a development aid. It doesn't need to produce the same result every single time - in fact - it's probably better if it doesn't!
#app/controllers/admin/mailer_controller.rb
class Admin::MailerController < Admin::ApplicationController
def preview_welcome()
#user = User.last
render :file => 'mailer/welcome.html.erb', :layout => 'mailer'
end
end
Note that when we render the template, we use layout=>:mailer. This embeds the body of your email inside the HTML email layout that you've created instead of inside your typical web application layout (e.g. application.html.erb).
And that's pretty much it. Now I can visit http://example.com/admin/mailer/preview_welcome to preview change to my welcome email template.
37Signals also has their own mail testing gem called mail_view. It's pretty fantastic.
The easiest setup I've seen is MailCatcher. Setup took 2 minutes, and it works for new mailers out of the box.
I use email_preview. Give it a try.
Easiest solution in rails 6: just remember one url:
http://localhost:3000/rails/mailers
I'm surprised no one's mentioned letter_opener. It's a gem that will render and open emails as a browser page whenever an email is delivered in dev.
I recently wrote a gem named Maily to preview, edit (template file) and deliver the application emails via a browser. It also provides a friendly way to hook data, a flexible authorization system and a minimalist UI.
I have planned to add new features in the near future, like:
Multiple hooks per email
Parametrize emails via UI (arguments of mailer method)
Play with translations keys (list, highlight, ...)
I hope it can help you.
rails generates a mail preview if you use rails g mailer CustomMailer.
You will get a file CustomMailerPreview inside spec/mailers/previews folder.
Here you can write your method that will call the mailer and it'll generate a preview.
For ex -
class CustomMailerPreview < ActionMailer::Preview
def contact_us_mail_preview
CustomMailer.my_mail(user: User.first)
end
end
Preview all emails at http://localhost:3000/rails/mailers/custom_mailer
You can use Rails Email Preview
REP is a rails engine to preview and test send emails, with I18n support, easy premailer integration, and optional CMS editing with comfortable_mexican_sofa.
There is no way to preview it directly out of the Mailer.
But as you wrote, you can write a controller, which looks something like this.
class EmailPreviewsControllers < ActionController::Base
def show
render "#{params[:mailer]}_mailer/#{params[:method]}"
end
end
But I think, that's not the best way to test emails, if they look correctly.
Rails Email Preview helps us to quickly view the email in web browser in development mode.
1) Add “gem ‘rails_email_preview’, ‘~> 0.2.29’ “ to gem file and bundle install.
2) Run “rails g rails_email_preview:install” this creates initializer in config folder and add routes.
3) Run “rails g rails_email_preview:update_previews” this crates mailer_previews folder in app directory.
Generator will add a stub to each of your emails, then u populate the stub with mock data.
Ex:
class UserMailerPreview
def invitation
UserMailer.invitation mock_user(‘Alice’), mock_user(‘Bob’)
end
def welcome
UserMailer.welcome mock_user
end
private
def mock_user(name = ‘Bill Gates’)
fake_id User.new(name: name, email: “user#{rand 100}#test.com”)
end
def fake_id(obj)
obj.define_singleton_method(:id) { 123 + rand(100) }
obj
end
end
4) Parameters in search query will be available as an instance variable to preview class. Ex: if we have a URL like
“/emails/user_mailer_preview-welcome?user_id=1” #user_id is defined in welcome method of UserMailerPreview it helps us to send mail to specific user.
class UserMailerPreview
def welcome
user = #user_id ? User.find(#user_id) : mock_user
UserMailer.welcome(user)
end
end
5) To access REP url’s like this
rails_email_preview.rep_root_url
rails_email_preview.rep_emails_url
rails_email_preview.rep_email_url(‘user_mailer-welcome’)
6) We can send emails via REP, this will use environment mailer settings. Uncomment this line in the initializer to disable sending mail in test environment.
config.enable_send_email = false
Source : RailsCarma Blog : Previewing Emails in Rails Applications With the Mail_View Gem
I prefer mails_viewer gem. This gem is quite useful as it save the HTML template into tmp folder.

Resources