Reputation: 75
We have recently migrated our codebase from Ruby 2.7.x and Rails 5.2.x to Ruby 3.2.2 and Rails 6.1.7.3. Previously, our mailers were defined like this:
class ApplicationMailer < ActionMailer::Base
...
end
class MyMailer < ApplicationMailer
def custom(user: , timestamp: Time.now)
@user = user
@timestamp = timestamp
end
end
And we would deliver emails like this: MyMailer.custom(user: @myuser).deliver_now
. With the update, this now returns an ArgumentError: wrong number of arguments (given 1, expected 0; required keyword: user) (ArgumentError)
.
We have found that we are supposed to pass the arguments in a params hash and read from there, but that seems pretty cumbersome and unelegant compared to our previous solution. So my questions are,
This is the way that we are apparently supposed to pass parameters:
class MyMailer < ApplicationMailer
def custom
@user = params[:user]
@timestamp = params[:timestamp] || Time.now
end
end
Upvotes: 5
Views: 668
Reputation: 6147
I still see this issue with actionmailer 7.2.0.beta1
, mail 2.8.1
, and ruby 3.3.2
. I'm not sure why because it seems to have been resolved in rails in the meantime.
This is how I could resolve it, however:
send_action
in the ApplicationMailer
class ApplicationMailer < ActionMailer::Base
# ...
# This patch accounts for the error
#
# ArgumentError:
# wrong number of arguments (given 1, expected 0; required keywords:
#
# which has appeared with the switch to ruby 3.2.
#
# References:
# - https://github.com/rails/rails/issues/46883
# - https://github.com/rails/rails/issues/44846
# - https://stackoverflow.com/q/76262079/2066546
#
def send_action(*args)
if args.second.kind_of? Hash
super(args.first, **args.second)
else
super
end
end
end
args.first
is the name of the method in the mailer that will receive the arguments and raises the error because of the signature mismatch, e.g. custom
in the question.super
will essentially call send(args.first, ...)
, i.e. call the custom
method.**args.second
we convert the argument hash, which does not match the method signature, to a series of keyword arguments, which do match the signature.Upvotes: 0
Reputation: 55888
ActionMailer still accepts passing arguments on the mailer actions. Howevber, it appears that the keyword argument semantics in Ruby 3.2 are not fully expected by Rails 6.1 which causes the issue you are seeing.
Rails 6.1 was released before Ruby 3.2 was a thing. As recent Ruby releases have changed some semantics with keywords arguments, it's appears likely that Rails 6.1 is not (fully) compatible with Ruby 3.2.
While I have not found any authoritative documentation about this, for the latest commit on the Rails 6.1.7.3 tag, the actionmailer tests fail a test regarding keyword arguments with Ruby 3.2.
As such, you have two possible avenues to fix this issue:
As a quick fix, you could probably now first downgrade your Ruby version, then start upgading your Rails application further until you can bump your Ruby version again.
Upvotes: 2