Rails: 缺少链接的主机!请提供 :host 参数或设置 default_url_options[:host]。

237

我已经谷歌了大约90分钟,还是找不到答案。我在哪里设置default_url_options?我已经为config.action_mailer.default_url_options设置了它,以解决其他地方的同样错误,但现在在尝试在RSpec spec内使用URL辅助程序时出现此错误。我不知道它希望设置default_url_options在哪里。

 Failure/Error: listing_url(listing).should match(/\/\d+-\w+$/)
 RuntimeError:
   Missing host to link to! Please provide :host parameter or set default_url_options[:host]
 # ./spec/routing/listing_routing_spec.rb:9:in `block (3 levels) in <top (required)>'

这段代码与电子邮件/ActionMailer无关,只是需要一个URL而不是一个路径。

有什么想法吗?


主机到底是什么? - Jwan622
17个回答

302

你需要在每个环境中添加以下行:

config.action_mailer.default_url_options = { :host => "yourhost" }

这样,它就可以在所有环境中工作,并且在不同的环境下可能会有所不同。例如:

development.rb

config.action_mailer.default_url_options = { :host => "dev.yourhost.com" }

test.rb

config.action_mailer.default_url_options = { :host => "test.yourhost.com" }

production.rb

config.action_mailer.default_url_options = { :host => "www.yourhost.com" }

23
请确保在添加完这些内容后重新启动你的 Rails 服务器。config/ 目录下的文件不会自动重新加载。 - Stenerson
3
我已经做过类似的事情,设置action_mailer的default_url_option也无济于事。用例与此类似: Rails.application.routes.url_helpers.message_image_url(2) - Boti
2
无论在生产环境中是否使用www前缀,我都遇到了相同的错误。根据@d11wtq的建议添加了路由,问题得以解决。这是Rails4引起的行为变化吗?在升级之前从未遇到过这种情况,只有在一个特定的邮件发送(devise-automated)中出现。 - JosephK
可以确认这在我的Rails 4项目中不起作用。在路由中设置它根本不是一个选项。 - b1nary
为什么会出现这个错误?解决方案中的“host:”是什么?它是用来做什么的? - Jwan622
4
无法在Rails 5中工作。不过,我添加了default_url_options Rails.application.config.action_mailer.default_url_options,这个方法很有效,正如另一个评论者所建议的那样。 - BooBailey

89
Your::Application.routes.draw do
  default_url_options :host => "example.com"

  # ... snip ...
end

routes.rb的某个地方 :)


41
如果您有许多不同的环境和不同的URL,那么情况就不太好。 - Neil Middleton
3
如果你有多个环境域名,你应该怎么做? - wejrowski
1
你可以为每个URL单独指定它,可以在路由映射中指定,也可以在url helper调用中指定:listing_url(listing, :host => "whatever.com") - d11wtq
16
在每个环境的配置文件中,我会添加此自定义选项:config.domain ='staging.myapp.com' (当然,对于每个环境,应该替换为正确的域名)。然后在routes.rb中,我可以自由使用default_url_options host: Rails.application.config.domain,并且它将在任何环境下都能正常工作。不用谢。 - Prathan Thananart
11
更好的方法是,在路由文件中这样做:default_url_options Rails.application.config.action_mailer.default_url_options - siannopollo

47

每个环境的配置文件中都应该指定主机。例如:

config/environments/development.rb

请查看这个问题这个问题


5
谢谢,我认为这个答案比使用routes.draw的答案更好。 - joelparkerhenderson
1
这个答案在使用不同的域和解决其他问题时并没有帮助。 - rxgx
1
@Ryan,你可以使用环境变量来解决这个问题。 - courtsimas

46

default_url_options设置为使用你的action_mailer.default_url_options

在每个环境文件(例如development.rbproduction.rb等)中,您可以指定用于action_mailerdefault_url_options

config.action_mailer.default_url_options = { host: 'lvh.me', port: '3000' }

然而,这些并未针对 MyApp:Application.default_url_options 进行设置:

$ MyApp::Application.config.action_mailer.default_url_options
#=> {:host=>"lvh.me", :port=>"3000"}

$ MyApp::Application.default_url_options
#=> {}

这就是为什么在ActionMailer之外的任何地方都会出现错误的原因。

您可以将应用程序的default_url_options设置为使用适当环境文件(development.rbproduction.rb等)中为action_mailer定义的内容。

为了使事情尽可能DRY,请在您的config/environment.rb文件中执行此操作,这样您只需要执行一次即可:

# Initialize the rails application
MyApp::Application.initialize!

# Set the default host and port to be the same as Action Mailer.
MyApp::Application.default_url_options = MyApp::Application.config.action_mailer.default_url_options

现在,当您启动应用程序时,您整个应用程序的default_url_options将匹配您的action_mailer.default_url_options:

$ MyApp::Application.config.action_mailer.default_url_options
#=> {:host=>"lvh.me", :port=>"3000"}

$ MyApp::Application.default_url_options
#=> {:host=>"lvh.me", :port=>"3000"}

@pduersteler致敬,因为他引导我走上了这条路。


2
config/environment.rb设置如你所述,是让我的邮件发送器在控制台中正常工作的关键。谢谢! - Eric D. Fields
@EricD.Fields 非常感谢您,Eric!我认为这非常有用,应该内置到Rails核心中。 - Joshua Pinter
4
对于Rails 5.2+来说,这段代码的意思是 Rails.application.default_url_options = Rails.application.config.action_mailer.default_url_options - Sandro L
谢谢,@SandroL!我们仍在使用Rails 4.2,所以尚未在更新版本上进行测试。 - Joshua Pinter
1
有些人推荐这样做。我猜这只是因为人们倾向于出于历史原因配置action_mailer.default_url_options,但是设置基于application.default_url_options不是更合理吗?为什么要在配置网站链接工作方式时涉及虚假的邮件引用呢? - Harry Wood
@HarryWood 我同意,但对于我们这些从Rails 2开始就一直在使用的人来说,它始于action_mailer,因此我们通常将主机和端口配置存储在那里。 - Joshua Pinter

25
当你使用任何listing_url方法时,将返回完整的URL(而不是通常的相对路径)。这就是为什么Rails要求你提供主机名来计算整个URL的原因。
你可以通过以下几种方式告诉Rails主机名: 1.在每个环境中添加此选项:
[/config/development.rb]
config.action_mailer.default_url_options = { host: "localhost:3000" }
[/config/test.rb]
config.action_mailer.default_url_options = { host: "localhost:3000" }
[/config/production.rb]
config.action_mailer.default_url_options = { host: "www.example.com" }
注意:如果您正在工作的是在一个rails engine中,请记得对引擎测试中的虚拟应用程序执行相同操作:path_to_your_engine/test/dummy/config/environments/*,因为当您测试引擎时,它就是Rails所测试的内容。
2.像这样向foo_url方法添加host选项:
listing_url(listing, host: request.host) # => 'http://localhost:3000/listings/1'

3.不使用:only_path选项输出主机名。

listing_url(listing, only_path: true ) # => '/listings/1'   

我个人认为这个没有必要,因为在这种情况下,我会使用listing_path方法。


步骤1对我总是有效的,今天使用refinery-cms gem宝石,只有步骤2救了我。感谢您的评论。 - lucianosousa
非常有用的答案,因为提到了在使用Rails引擎时的场景!在我的情况下,当我尝试执行一个使用引擎内模型的rake任务时遇到了错误。我像这样将我的action_mailer配置加载到引擎中,最终能够运行该任务。 MyEngine::Engine.config.action_mailer.default_url_options = Rails.application.config.action_mailer.default_url_options MyEngine::Engine.routes.default_url_options = Rails.application.config.action_mailer.default_url_options - siax

20

Rails.application.routes.default_url_options[:host]= 'localhost:3000'

在 developemnt.rb / test.rb 文件中,可以更简洁地写成以下内容:

Rails.application.configure do
  # ... other config ...

  routes.default_url_options[:host] = 'localhost:3000'
end

16
有趣的是,设置config.action_mailer.default_url_options对我没有帮助。而且,在我认为不属于的地方搞环境无关的设置也不令我满意。此外,我想要一个在生成sidekiq/resque工作器中的URL时能够正常工作的解决方案。
到目前为止,我的做法是将其放入config/environments/{development, production}.rb中。
MyApp::Application.configure do
    # Stuff omitted...

    config.action_mailer.default_url_options = {
      # Set things here as usual
    }
end

MyApp::Application.default_url_options = MyApp::Application.config.action_mailer.default_url_options

这在Rails版本 >= 3.2.x 上对我有效。


1
只有这个方法可以让邮件程序包含URL,但它会破坏我的应用程序中的其他link_to函数。 - user1431084
1
棒极了,@pduesteler!我实际上更进一步,在config/environment.rb文件中只添加了一行代码就实现了这个功能。并提供了详细的答案:https://dev59.com/kWw05IYBdhLWcg3weBvu#48529627 谢谢你指引我的方向。 - Joshua Pinter

8
您可以始终将主机作为参数传递给URL助手程序:
listing_url(listing, host: request.host)

注意:您还可以添加端口 listing_url(listing, host: request.host, port: 3000) - drhenner
但是如果您没有请求上下文呢?比如除了控制器之外的大多数情况下呢? - courtsimas

7

上面的答案对我没有用,至少不是我想要的。在安装devise后,我发现config.action_mailer.default_url_options = { host: "localhost", port: 3000 }。希望这能帮助有同样问题的人。


6

进入 config/environments/test.rb 文件

Rails.application.routes.default_url_options[:host] = 'localhost:3000'


2
答案需要更多信息。请描述您实际提出的解决方案是什么。 - Levi Roberts
1
以下是关于 [answer] 的一些有用提示。我发现它们很有参考价值。 - Garrett Motzner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接