Preview devise mailer not found - ruby-on-rails

I try to have a preview of devise mailer but when it doesn't work.
I have followed this rails guide and it doesn't seems difficult and many things to do.
Devise already have a mailer class here
So I should only have to create a preview file so here is what I have done so far.
I generated my devise views in the repository app/views/users/mailer/
I have my devise.rbwhich look like that
Devise.setup do |config|
# ==> Mailer Configuration
# Configure the e-mail address which will be shown in Devise::Mailer,
# note that it will be overwritten if you use your own mailer class
# with default "from" parameter.
config.mailer_sender = 'please-change-me-at-config-initializers-devise#example.com'
# Configure the class responsible to send e-mails.
config.mailer = 'Devise::Mailer'
# Configure the parent class responsible to send e-mails.
#config.parent_mailer = 'ActionMailer::Base'
end
I have my test/mailers/previews/devise_mailer_preview.rb
class DeviseMailerPreview< ActionMailer::Preview
def confirmation_instructions
Devise::Mailer.confirmation_instructions(User.first, "faketoken")
end
def reset_password_instructions
Devise::Mailer.reset_password_instructions(User.first, "faketoken")
end
end
I didn't change the path config.action_mailer.preview_pathin my application.rb because test/mailers/previews is the default path
So now when I try to access to http://localhost:3000/rails/mailers I have a white empty page
and if I try http://localhost:3000/rails/mailers/users/mailer/confirmation_instructions I have this error Mailer preview 'users/mailer/confirmation_instructions' not found
I tried many different link but still have the same error, I also tried to followed this stackoverflow answer but no success.
It's seems so easy but I can't succeed ...

Ok I found out why.
Because I'm using the gem rspec-rails the repository test is replaced tp spec
I just needed to move my test/mailers/previews/devise/mailer_preview.rbto spec/mailers/previews/devise/mailer_preview.rb and still not need to change the configuration of config/application.rb
Hope it will help some people
also note that in rails 6 your devise mailer preview should be wrote with a module
module Devise
class MailerPreview< ActionMailer::Preview
def confirmation_instructions
Devise::Mailer.confirmation_instructions(User.first, "faketoken")
end
def reset_password_instructions
Devise::Mailer.reset_password_instructions(User.first, "faketoken")
end
end
end

Moving the mailers folder worked for me!

Related

How to include Concern inside DeviseMailer - strange name_error

I'm using engines inside my Rails 7 app. I've got Core engine where I can find a devise mailer (from devise_invitable gem). Think there is only 1 Devise application mailer possible, and I don't need a copy anything inside devise.rb.
My goal is to to override invitation_instructions method from Core engine into PaymentProcess engine. To do that I'll use concerns, so in a nutshell:
add a devise mailer concern inside payment_engine and include it to devise mailer inside payment_process/engine.rb initializer
overwrite invitation_instructions, but keep super when a user is not a payment_process user.
Here is my code:
engines/core/app/mailers/devise_application_mailer.rb
class DeviseApplicationMailer < Devise::Mailer
def invitation_instructions(recipient, *args)
account, = recipient.accounts
scope = 'devise.mailer.invitation_instructions'
#invited_by_text = invited_by_text(account, recipient.invited_by, scope)
mail = super
mail.subject = I18n.t('subject_with_account', account_name: account.name, scope:) if account.present?
mail
end
# other stuff (...)
end
engines/payment_process/app/mailers/concerns/devise_application_mailer_concern.rb:
module DeviseApplicationMailerConcern
extend ActiveSupport::Concern
included do
def invitation_instructions(resource, *args)
if resource.is_a?(PaymentProcess)
recipient, customer = resource
scope = 'devise.mailer.invitation_instructions'
#invited_by_text = invited_by_text(customer, recipient.invited_by, scope)
mail = super
mail.subject = I18n.t('subject', scope:) if customer.present?
mail
else
super
end
end
end
end
So now I want to include everything inside engine initializer:
engines/payment_process/lib/payment_process/engine.rb
module PaymentProcess
class Engine < ::Rails::Engine
engine_name 'payment_process'
isolate_namespace PaymentProcess
# some other stuff
config.to_prepare do
# some other stuff
Devise::Mailer.include(PaymentProcess::DeviseApplicationMailerConcern)
end
end
end
And all of these produces me an error of:
block in class:Engine': uninitialized constant PaymentProcess::DeviseApplicationMailerConcern (NameError)
Devise::Mailer.include(PaymentProcess::DeviseApplicationMailerConcern)
I've tried to require file path inside the engine but it won't help. I also tried to include concern directly inside the engines/core/app/mailers/devise_application_mailer.rb but I'm getting the same error.
What did I missed? or maybe it's not possible with to include anything to Devise ?

Passing params into MailView or ActionMailer::Preview in Ruby on Rails

Is it possible when using the MailView gem or Rails 4.1 mail previews to pass parameters into the MailView? I would love to be able to use query string parameters in the preview URLs and access them in the MailView to dynamically choose which record to show in the preview.
I stumbled upon the same issue and as far as I understand from reading the Rails code it's not possible to access request params from mailer preview.
Crucial is line 22 in Rails::PreviewsController (email is name of the mailer method)
#email = #preview.call(email)
Still a relevant question and still very few solutions to be found on the web (especially elegant ones). I hacked my way through this one today and came up with this solution and blog post on extending ActionMailer.
# config/initializers/mailer_injection.rb
# This allows `request` to be accessed from ActionMailer Previews
# And #request to be accessed from rendered view templates
# Easy to inject any other variables like current_user here as well
module MailerInjection
def inject(hash)
hash.keys.each do |key|
define_method key.to_sym do
eval " ##{key} = hash[key] "
end
end
end
end
class ActionMailer::Preview
extend MailerInjection
end
class ActionMailer::Base
extend MailerInjection
end
class ActionController::Base
before_filter :inject_request
def inject_request
ActionMailer::Preview.inject({ request: request })
ActionMailer::Base.inject({ request: request })
end
end
Since Rails 5.2, mailer previews now have a params attr reader available to use inside your previews.
Injecting requests into your mailers is not ideal as it might lead to thread safety issues and also means your mailers won't work with ActiveJob & co

Creating a custom Devise Strategy

Been fighting with this for a while now, not sure why it isn't working.
The gist is looking to use Devise with LDAP. I don't need to do anything except for authenticate so I have no need to use anything except for a custom strategy.
I created one based on https://github.com/plataformatec/devise/wiki/How-To:-Authenticate-via-LDAP and as far as I can tell everything should work except whenever I try to run the server (or rake route) I get a NameError
lib/devise/models.rb:88:in `const_get': uninitialized constant Devise::Models::LdapAuthenticatable (NameError)
I've traced the error down to my app/models/user.rb
class User < ActiveRecord::Base
devise :ldap_authenticatable, :rememberable, :trackable, :timeoutable
end
If I remove :ldap_authenticatable then the crash goes away but I have no routes to user#session and a login prompt cannot be accessed.
My supporting files:
lib/ldap_authenticatable.rb
require 'net/ldap'
require 'devise/strategies/authenticatable'
module Devise
module Strategies
class LdapAuthenticatable < Authenticatable
def authenticate!
if params[:user]
ldap = Net::LDAP.new
ldap.host = 'redacted'
ldap.port = 389
ldap.auth login, password
if ldap.bind
user = User.where(login: login).first_or_create do |user|
success!(user)
else
fail(:invalid_login)
end
end
end
def login
params[:user][:login]
end
def password
params[:user][:password]
end
end
end
end
Warden::Strategies.add(:ldap_authenticatable, Devise::Strategies::LdapAuthenticatable)
And finally, inside config/initializers/devise.rb
Devise.setup do |config|
# ==> LDAP Configuration
require 'ldap_authenticatable'
config.warden do |manager|
manager.default_strategies(:scope => :user).unshift :ldap_authenticatable
end
end
I've exhausted my searches, maybe someone can see something I am missing.
Cheers
Is your lib/ldap_authenticatable.rb is in the autoload path or explicitly required? Since Rails 3 code in lib folder isn't autoloaded by default any more. Here is one way on how to solve it
IMHO Devise is a great gem. However in order to write your own strategy you have to be familiar not only with Devise but with Warden source code as well, and a lot of boilerplate code needs to be written in various places, so I start to investigate how to make customizations easier for Devise and come up with this gem devise_custom_authenticatable. You can check it and probably it'll solve your problem in a different way. This gem is used in production code base for rather busy application, so it battle proven :)
File paths should match namespaces. You need to add 2 levels of directories.
mkdir lib/devise
mkdir lib/devise/strategies
mv lib/ldap_authenticatable.rb lib/devise/strategies/ldap_authenticatable.rb
Since you are namespaced to
module Devise
module Strategies
class LdapAuthenticatable < Authenticatable
...
few steps to take care while creating custom strategy:
you will have to take care of the strategies folder as #csi mentioned along with it create a models folder and inside models create ldap_authenticatable.rb . so the structure will look like this.
lib/devise/strategies/ldap_authenticatable.rb
lib/devise/models/ldap_authenticatable.rb
Add these lines to lib/devise/models/ldap_authenticatable.rb
require Rails.root.join('lib/devise/strategies/ldap_authenticatable')
module Devise
module Models
module LdapAuthenticatable
extend ActiveSupport::Concern
end
end
end
In config/initializers/devise.rb add these lines to the top.
Devise.add_module(:ldap_authenticatable, {
strategy: true,
controller: :sessions,
model: 'devise/models/ldap_authenticatable',
route: :session
})
This should take care of the custom auth.

Rails 4.1 Mailer Previews and Devise custom emails

I have a brand new Rails 4.1.1 app where I'm customizing the Devise emails. I want to have them displayed on the new Rails email preview feature so I did the following:
1) Added the following snippet to my config/development.rb file:
config.action_mailer.preview_path = "#{Rails.root}/lib/mailer_previews"
2) Created my custom Devise email UserMailer in app/mailers/user_mailer.rb:
class UserMailer < Devise::Mailer
helper :application # gives access to all helpers defined within `application_helper`.
include Devise::Controllers::UrlHelpers # Optional. eg. `confirmation_url`
layout "notifications_mailer"
end
3) Changed config/initializers/devise.rb to contain the following snippet:
config.mailer = 'UserMailer'
4) Added the class UserMailerPreview to lib/mailer_previews with the following content:
class UserMailerPreview < ActionMailer::Preview
def confirmation_instructions
UserMailer.confirmation_instructions(User.first, {})
end
def reset_password_instructions
UserMailer.reset_password_instructions(User.first, {})
end
def unlock_instructions
UserMailer.unlock_instructions(User.first, {})
end
end
So far, so good. Looks like I've done everything right. But then I try to see the preview for the confirmation_instructions email at the /rails/mailers/user_mailer/confirmation_instructions route and I get the following error:
undefined method `confirmation_url' for #<#<Class:0x007fa02ab808e0>:0x007fa030fb7e80>
the code for my confirmation_url.html.erb template looks like this:
<%= t("notifications.texts.greeting") + #user.display_name %>,
<p>You can confirm your account email through the link below:</p>
<p><%= link_to 'Confirm my account', confirmation_url(#resource, :confirmation_token => #token) %></p>
What am I doing wrong? I guess it is something wrong with the way I call the confirmation_url method. Anyone can help me here?
For those looking to preview Devise emails without using custom mailers, (but still custom emails) this is what I did:
Configure your app for email previewing.
Set up the Devise Mailer Preview class
a. Rails ~> 4.1
# mailer/previews/devise_mailer_preview.rb
class Devise::MailerPreview < ActionMailer::Preview
def confirmation_instructions
Devise::Mailer.confirmation_instructions(User.first, "faketoken")
end
def reset_password_instructions
Devise::Mailer.reset_password_instructions(User.first, "faketoken")
end
...
end
b. Rails ~> 5.0
class DeviseMailerPreview < ActionMailer::Preview
... # same setup as Rails 4 above
Restart the server
Using Rails 5 and found the syntax slightly different from #steel's excellent answer, with the use of double "::" being the difference:
# Preview all emails at http://localhost:3000/rails/mailers/devise_mailer
class DeviseMailerPreview < ActionMailer::Preview
def reset_password_instructions
Devise::Mailer.reset_password_instructions(User.first, "faketoken")
end
end
You will get undefined method for the devise url helpers when you have forgotten to include the necessary devise modules in your model. e.g. if your model is User and you want the confirmation_url, you must ensure that the :confirmable module is included:
devise <...snipped...>, :confirmable
Be aware that if this module is not currently loaded that your application most likely does not use e.g. confirmations!
Including the :confirmable module might then lock out all your users. See https://github.com/plataformatec/devise/wiki/How-To:-Add-:confirmable-to-Users
I found this question because I was trying to figure out how to preview Devise emails myself. I copied your code almost exactly and it works fine for me.
The only thing I did differently was to remove the line layout "notifications_mailer" from UserMailer - when I included it I got an error message Missing template layouts/notifications_mailer. What happens if you remove it?
The line Devise::Controllers::UrlHelpers definitely includes the method confirmation_url (you can see this for yourself by opening up the Rails console and running include Devise::Controllers::UrlHelpers then confirmation_url, so I suspect the problem is that your previews aren't being rendered by UserMailer at all. I'm not sure why, but the line layout "notifications_mailer" might be the culprit.
Do you have a class called NotificationsMailer? Does including Devise::Controllers::UrlHelpers in there solve your problem?

Rails - URL helpers not working in mailers

I tried:
class MyMailer
def routes
Rails.application.routes.url_helpers
end
def my_mail
#my_route = routes.my_helper
... code omitted
end
Also inside mailer:
include Rails.application.routes.url_helpers
def my_mail
#my_route = my_helper
Also, the simple way, in mailer template:
= link_to 'asd', my_helper
But then when I try to start console I get:
undefined method `my_helper' for #<Module:0x007f9252e39b80> (NoMethodError)
Update
I am using the _url form of the helper, i.e. my_helper_url
For Rails 5, I included the url helpers into the my mailer file:
# mailers/invoice_mailer.rb
include Rails.application.routes.url_helpers
class InvoiceMailer < ApplicationMailer
def send_mail(invoice)
#invoice = invoice
mail(to: #invoice.client.email, subject: "Invoice Test")
end
end
Doing this broke my other routes.
# mailers/invoice_mailer.rb
include Rails.application.routes.url_helpers
Doing this is not the right way, this will break application as routes are reloading and routes will not be available is those are reloading
module SimpleBackend
extend ActiveSupport::Concern
Rails.application.reload_routes!
Right answer is to use *_url and not *_path methods in email templates as explained below in Rails docs.
https://guides.rubyonrails.org/action_mailer_basics.html#generating-urls-in-action-mailer-views
I ran into the same issue but with a Concern, i was unable to use any of the url helpers in my code even using directly Rails.application.routes.url_helpers.administrator_beverages_url i was getting this error:
undefined method `administrator_beverages_url' for #<Module:0x00000002167158> (NoMethodError)
even unable to use the rails console because of this error the only way i found to solve this was to use this code in my Concern
module SimpleBackend
extend ActiveSupport::Concern
Rails.application.reload_routes! #this did the trick
.....
The problem was Rails.application.routes.url_helpers was empty at the moment of the initialization. I don't know the performance implication of using this but for my case this is a small application and i can take the bullet.
In the mailer add
helper :my
or the helper you need
and it will load app/helpers/my_helper.rb & includes MyHelper
Enjoy
The rails route helpers are in Rails.application.routes.url_helpers. You should just be able to put
include Rails.application.routes.url_helpers at the top of your class, though I haven't tested this
I came across this issue while working with a newly added route that seemed to be unavailable in my Mailer. My problem was I needed to restart all the workers, so they would pick up the newly added route. Just leaving this footnote in here in case someone runs into the same issue, it can be tricky to solve if you don't know this is happening.
Please take a look at this blog which explains how you can make use of Rails.application.routes.url_helpers in the right manner.
http://hawkins.io/2012/03/generating_urls_whenever_and_wherever_you_want/
You need to use the my_helper_url

Resources