8

I have several mailer previews under spec/mailer/previews. On development I can view all the previews under /rails/mailers/. However by default this functionality does not exist on other environments.

I wanted to enable it on the staging environment and took a queue from this post here.

I made the following changes -

config/routes.rb

# Add the routes manually
if Rails.env.staging?
  get "/rails/mailers" => "rails/mailers#index"
  get "/rails/mailers/*path" => "rails/mailers#preview"
end

config/environments/staging.rb

Rails.application.configure do
  # Define the mailer preview path
  config.action_mailer.preview_path = "spec/mailers/previews"

  # Specifically add that path and all files under it to the autoload paths
  config.autoload_paths = Dir["#{config.root}/#{config.action_mailer.preview_path}/**"]
end

class ::Rails::MailersController
  include Rails.application.routes.url_helpers

  # Override the method just for this controller so `MailersController` thinks
  # all requests are local.
  def local_request?
    true
  end
end

However on staging, I'm getting the following error when trying to load the /rails/mailers page -

LoadError (No such file to load -- spec/mailers/previews/admin_mailer_preview):

The odd thing is... that file definitely exists. And when I check the autoload paths on staging that file is definitely in the Array/list.

Any thoughts on what might be happening here, or how else I should go about exposing that endpoint?

Thanks!

user2490003
  • 10,706
  • 17
  • 79
  • 155

3 Answers3

9

Having consider_all_requests_local = true or patching local_request? can be security issue. Here is solution we use, it uses authentication to allow only admins to access previews:

# in any enviroment
config.action_mailer.show_previews = true

# in initializers/mailer_previews.rb
# (use your own authentication methods)

# Allow admins to see previews if show_previews enabled.
# It does not affect dev env, as this setting is nil there.
if Rails.application.config.action_mailer.show_previews
  Rails::MailersController.prepend_before_action do
    authenticate_user!
    head :forbidden unless current_user.admin?
  end
end

# If you use rspec-rails, it makes rails use spec/mailers/previews
# as previews path. Most likely you don't have rspec-rails on
# staging/production, so need to add this to application.rb:
#
# Make previews available in environments without rspec-rails.
config.action_mailer.preview_path = Rails.root.join('spec', 'mailers', 'previews')

# Bonus: specs. Update with your `sign_in` implementation
# and have `config.action_mailer.show_previews = true` in test.rb
RSpec.describe Rails::MailersController do
  shared_examples 'visible to admin only' do
    it { should redirect_to new_user_session_path }

    context 'for signed in user' do
      sign_in { create(:user) }
      it { should be_forbidden }

      context 'admin' do
        let(:current_user) { create(:user, admin: true) }
        it { should be_ok }
      end
    end
  end

  describe '#index' do
    subject { get('/rails/mailers') && response }
    include_examples 'visible to admin only'
  end

  describe '#preview' do
    subject { get('/rails/mailers/devise/mailer') && response }
    include_examples 'visible to admin only'
  end
end
prcu
  • 903
  • 1
  • 10
  • 23
  • Thanks a lot! Very handy – BinaryButterfly Aug 01 '18 at 19:43
  • In my case i needed a concern that isn't in the same namespace but was able to do it with this https://gist.github.com/rromanchuk/486f6fbd4fec28c8fa69d36220795343 – Ryan Romanchuk Oct 31 '18 at 03:16
  • The before_action fails with `undefined local variable or method 'current_user' for #`. Same for my replacement of your `authenticate_user!` line. It appears to me that this code only works for normally controllers, not mailer controllers. – iconoclast Oct 15 '21 at 18:37
  • `current_user` is helper from devise gem that returns signed in user. Devise adds it to this controller. You need to use your own auth implementation and replace this check. – prcu Oct 15 '21 at 18:44
  • Adapted the initializer for rails 7 also: "does not affect dev env" was not true for me at least ```# Allow staff to see previews if show_previews enabled. Rails.application.config.after_initialize do if Rails.application.config.action_mailer.show_previews Rails::MailersController.prepend_before_action do authenticate_user! head :forbidden unless current_user.admin? end end end ``` – Aeramor Nov 16 '22 at 01:35
6

It depends on what Rails version are you running, but if you are on 4.2+ adding these lines to staging.rb should help:

config.action_mailer.show_previews = true
config.consider_all_requests_local = true
Danil Pyatnitsev
  • 2,172
  • 2
  • 26
  • 39
shlajin
  • 1,416
  • 10
  • 23
2

Another option would be to use a service like https://mailtrap.io/ and also get some more interesting information about the email such as spam and responsiveness analysis - I find it to be the best option for my staging environment.

Guy Dubrovski
  • 1,542
  • 1
  • 20
  • 25