Rails 7中Devise动态设置default_url_options失效问题排查
问题描述
在Rails 7应用中,因需动态配置url_options,已禁用静态配置项:
# config.action_mailer.default_url_options = { host: 'some_domain' }
通过路由自定义了用户密码控制器:
devise_for :users, controllers: { passwords: 'users/passwords' }
并在该控制器的create方法中添加如下逻辑:
def create Rails.logger.info params[:user][:host] Rails.logger.info request.host default_url_options = { host: request.host } super end
日志显示上述两个打印项均为localhost,但执行时仍出现两个问题:
DEPRECATION WARNING: Initializing Mail::Sendmail with :arguments of type String is deprecated. Instead ensure :arguments is an array of strings, e.g. ["-i", "-t"] (called from create at /Users/deploy/r/some/app/controllers/users/passwords_controller.rb:16) [...] ActionView::Template::Error (Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true):
请问为何该方法无法正确处理参数或请求信息?当前实现存在哪些错误?
问题分析与解决方案
1. 动态设置default_url_options的方式完全错误
你在create方法里定义的default_url_options = { host: request.host }只是一个局部变量,根本没有关联到Action Mailer的全局配置。Devise的super调用(即原始的密码重置逻辑)在生成邮件链接时,依然会读取全局的action_mailer.default_url_options,而你已经禁用了这个静态配置,所以必然会报缺少host的错误。
正确的做法有两种:
方法一:重写控制器的default_url_options方法
在自定义的密码控制器中添加这个方法,Devise生成邮件链接时会自动调用它:
class Users::PasswordsController < Devise::PasswordsController protected def default_url_options { host: request.host }.merge(super) end end
方法二:直接给Devise邮件类动态配置
如果需要更灵活的控制,可以在调用super前修改Devise邮件类的配置:
def create Devise::Mailer.default_url_options = { host: request.host } super end
2. Sendmail参数的废弃警告
这个警告和host问题无关,是因为Rails 7要求config.action_mailer.sendmail_settings的:arguments必须是数组类型。如果你的配置里写的是字符串:
config.action_mailer.sendmail_settings = { arguments: "-i -t" }
改成数组即可解决:
config.action_mailer.sendmail_settings = { arguments: ["-i", "-t"] }
内容的提问来源于stack exchange,提问作者Jerome
相关产品推荐
相关产品推荐

