为什么Carrierwave和资产管道似乎以不同的方式解释config.asset_host?

时间:2016-08-14 06:39:42

标签: ruby-on-rails asset-pipeline carrierwave

在我的Rails应用程序中的Prawn PDF生成器中出现此问题,其中我有以下行:

image open(@user.avatar.url)

在测试中,这一行开始失败,出现以下错误:

No such file or directory @ rb_sysopen - /images/fallback/default.png

Avatar是一个Carrierwave上传器,带有默认图片(see here

def default_url(*args)
  ActionController::Base.helpers.asset_path("images/fallback/default.png" )
end

这似乎很容易解决 - 在test.rb中定义资产主机

config.asset_host = Rails.root.join('app', 'assets').to_s

然后我所有启用JS的功能测试都开始失败

Capybara::Poltergeist::JavascriptError:
One or more errors were raised in the Javascript code on the page.
ReferenceError: Can't find variable: SomeVariable

因为路径是用两个assets构建的,例如

...app/assets/assets/jquery..

我显然正在做一些违反Rails做事方式的“非常规”。所以我想知道这里的惯例是什么。

一种解决方案是移动我将test.rb中的资产文件夹定义到上传者的位置。

#config/environments/test.rb
config.asset_host = Rails.root.join('app').to_s
#app/uploaders/avatar.eb
def default_url(*args)
  ActionController::Base.helpers.asset_path("assets/images/fallback/default.png" )
end

但这意味着helpers.asset_path实际上并没有调用资产路径而是app文件夹,这似乎也违背了Rails惯例。

我以为localhost会工作

config.asset_host = "http://localhost"

但JS文件再次失败

我确定我忽略了一些显而易见的事情。感谢正确方向的指针。

1 个答案:

答案 0 :(得分:2)

我认为这归结为混合了路径和URL的各种含义。

如果要将资产文件从不同的服务器提供给应用程序(即从cdn),则首先使用asset_host。如果查看asset_path rails的源,首先计算资产的路径,然后预先设置主机。这会创建一个浏览器稍后会尝试获取的网址,因此在/Users/andy/some_app之类的路径前添加不会有意义

将其设置为http://localhost不起作用,因为它采用默认的http端口,而capybara在随机端口上运行您的应用。您不应该在测试环境中设置asset_host

转到carrierwave,avatar.url还从浏览器的角度提供了URL(在您的情况下只是路径部分) - 它被设计为嵌入在img标记中,例如。另一方面,open方法对浏览器和服务器一无所知,只想获得本地文件系统上文件的路径。

如果您需要本地文件系统路径,则需要avatar.path方法。据我所知,路径上没有default_url的等价物,所以你需要做好准备让它返回nil(并将其替换为你的后备路径)

#config/environments/test.rb
# do not set config.asset_host

#pdf_generator.rb
image open(@user.avatar.path)

#app/uploaders/avatar.rb
def path(*args)
  if model.avatar?
    super
  else
    "#{Rails.root}/app/assets/images/fallback/" + ["default_",version_name, ".png"].compact.join('')
  end
end