Rails 6 ActionMailer params is nil in preview - ruby-on-rails

I get this error after visit http://localhost:3000/rails/mailers/user_mailer/confirm_email:
undefined method '[]' for nil:NilClass
#user = params[:user]
My code:
class UserMailer < ApplicationMailer
def confirm_email
#user = params[:user]
mail to: "to#example.org"
end
end
class UserMailerPreview < ActionMailer::Preview
def confirm_email
UserMailer.with(user: User.first).confirm_email
end
end
If I change code to this:
class UserMailer < ApplicationMailer
def confirm_email(user)
#user = user
mail to: "to#example.org"
end
end
class UserMailerPreview < ActionMailer::Preview
def confirm_email
UserMailer.confirm_email(User.last)
end
end
I receive this:
wrong number of arguments (given 0, expected 1)
I cant understand, what I'm doing wrong?
My rails version is 6.0.2.1
Update:
First case worked from console, but not worked from browser preview. Second case not worked from console.

I was able to resolve this same problem by removing the Letter Opener gem from my project. Letter Opener has similar functionality to the now built-in ActionMailer previews.

Related

How to test instance variables in an ActionMailer object?

There is a before_action callback method in my ActionMailer object which is responsible for setting some instance variables.
class TestMailer < ApplicationMailer
before_action :set_params
def send_test_mail
mail(to: #email, subject: subject)
end
def set_params
#account = account.email
#date = some_action(account.updated_at)
end
end
The question is How one can test these variables in a rspec test?
some thing like:
describe TestMailer do
describe '#set_params' do
described_class.with(account: account, subject: subject).send_test_mail.deliver_now
expect(#date).to eq(Date.today)
end
end
any clue would be highly appreciated.
I think that instead of testing the instance variables, it would be better to test the email body, for example:
expect(mail.body.encoded).to include(account.updated_at)
you could setup a spy inside a mock method instance_variable_set, then validate that spy
class TestMailer < ApplicationMailer
attr_accessor :day
# ...
end
describe TestMailer do
let(:freeze_today) { Time.now.utc }
it '#set_params' do
# freeze today
allow_any_instance_of(TestMailer).to receive(:some_action)
.with(account.updated_at)
.and_return(freeze_today)
# spy
#spy = nil
allow_any_instance_of(TestMailer).to receive(:day=) do |time|
#spy = time
end
described_class.with(account: account, subject: subject)
.send_test_mail
.deliver_now
expect(#spy).to eq(freeze_today)
# or just simple like this
expect_any_instance_of(TestMailer).to receive(:day=).with(freeze_today)
end
end

Include application_helper.rb in ActionMailer

I'm trying to get access to some of my application_helper methods within my mailer, but nothing seems to be working from these SO posts:
View Helpers in Mailers
Access Helpers from mailer
In app/helpers/application_helper.rb I have the following:
module ApplicationHelper
def get_network_hosts
.. stuff get get a #network_hosts object
end
end
In my mailer at app/mailers/user_notifier.rb I have the following:
class UserMailer < ActionMailer::Base
default from: "Support <support#me.co>"
add_template_helper(ApplicationHelper)
def trial_notifier(user)
get_network_hosts
#user = user
#total = user.company.subscription.per_device_charge * #network_hosts.count
if #total < 501
#message = "You'd pay #{#total}/month if you converted to full-access now!"
else
#message = "You'd pay #{#total}/month if you converted to full-access now, but we have a better deal for you!"
end
#url = edit_user_registration_url
mail(to: #user.email, subject: 'What's up?')
end
end
In my mailer I've tried all of the suggestions in the above SO posts, but I'm still getting this error:
`NameError: undefined local variable or method `get_network_hosts' for #<UserMailer:0x007fe756c67c18`>
I'm currently using Rails 4.1.7.
So what do I have to actually do to be able to use my application_helper methods within a mailer?
You can try to do this as following:
In your mailer at app/mailers/user_notifier.rb:
class UserMailer < ActionMailer::Base
default from: "Support <support#me.co>"
helper :application
or you can try this:
helper ApplicationHelper

Sending multiple mails from a single method in ActionMailer

I have a simple mailer
class ApplyMailer < ActionMailer::Base
def inform_teacher
end
def inform_division
end
def inform_everyone
inform_teacher.deliver
inform_division.deliver
end
end
Calling inform_teacher and inform_division everything works well. But when I try to call inform_everyone just one blank email arrives.
Is it possible to combine multiple email method though one method?
Found solution to this:
class ApplyMailer < ActionMailer::Base
def inform_teacher
end
def inform_division
end
def self.inform_everyone
ApplyMailer.inform_teacher.deliver
ApplyMailer.inform_division.deliver
end
end

Rails4: Cannot send email from lib/module

I have this weird thing going on in my rails4 app:
I created event.rb in the lib folder.
In there, I call a mailer:
def whatever
puts 'here'
UserMailer.welcome(user)
puts 'there'
end
which is calling
class UserMailer < ActionMailer::Base
def welcome(user)
#user = user
mail(to: #user.mailer, subject: 'Welcome to my app').deliver
end
end
The weird thing is that the method welcome is never called, while whatever is called, without raising any error (the logs are there).
But if I call UserMailer.welcome(User.first) in the console, it is sent.
What am I doing wrong? Is it that it is not possible to send an email from a module? I should move this code to a model? That would be weird.
Thanks in advance
IMO mailer should look like this:
class UserMailer < ActionMailer::Base
def welcome(user)
#user = user
mail(to: #user.mailer, subject: 'Welcome to my app') #.deliver removed
end
end
and should be invoked with this manner:
def whatever
puts 'here'
UserMailer.welcome(user).deliver_now # and added here
puts 'there'
end

Suspend sending emails in ActionMailer

In my Rails application I want to temporarily stop sending email for specific users (e.g. when I get bounces due to quota) until the user confirms he is able to receive email again.
I have a common superclass for all mailer classes. There I always call a method setup_email before sending a mail.
Where is the best place to call #user.mail_suspended??
Here is some simplified sample app, I use Rails 2.3:
# Common super class for all Mailers
class ApplicationMailer < ActionMailer::Base
protected
def setup_mail(user)
#recipients = user.email
#from = ...
end
end
# Specific Mailer for User model
class UserMailer < ApplicationMailer
def message(user, message)
setup_mail(user)
#subject = "You got new message"
#body[:message] = message
end
end
# Use the UserMailer to deliver some message
def MessagesController < ApplicationController
def create
#message = Message.new(params[:message])
#message.save
UserMailer.deliver_message(#message.user, #message)
redirect_to ...
end
end
I solved this by setting the ActionMailer::Base.perform_deliveries to false:
def setup_mail(user)
email = user.default_email
if email.paused?
ActionMailer::Base.perform_deliveries = false
logger.info "INFO: suspended mail for #{user.login} to #{email.email})"
else
ActionMailer::Base.perform_deliveries = true
end
# other stuff here
end
I wouldn't set perform_deliveries universally, just per message, e.g.
after_filter :do_not_send_if_old_email
def do_not_send_if_old_email
message.perform_deliveries = false if email.paused?
true
end
I tried many ways, but no one could help me except this one.
class ApplicationMailer < ActionMailer::Base
class AbortDeliveryError < StandardError; end
before_action :ensure_notifications_enabled
rescue_from AbortDeliveryError, with: -> {}
def ensure_notifications_enabled
raise AbortDeliveryError.new unless <your_condition>
end
...
end
Make a class inherited with standardError to raise exception.
Check the condition, if false then raise exception.
Handle that exception with the empty lambda.
The empty lambda causes Rails 6 to just return an
ActionMailer::Base::NullMail instance, which doesn't get delivered
(same as if your mailer method didn't call mail, or returned
prematurely).

Resources