My production asset_host config looks like this:
config.action_controller.asset_host = Proc.new { |source, request|
if request.ssl?
"#{request.protocol}#{request.host_with_port}"
else
"#{request.protocol}assets#{(source.length % 4) + 1}.example.com"
end
}
...which is more or less straight from the docs:
http://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html
When I go to assets:precompile, I get this:
$ RAILS_ENV=production bundle exec rake assets:precompile
rake aborted!
This asset host cannot be computed without a request in scope. Remove
the seco开发者_如何学Pythonnd argument to your asset_host Proc if you do not need the
request.
....except that I can't really remove the 2nd arg because I need to know if the request is ssl or not. That said, I understand that a request isn't present during the rake task to generate the assets....
So how do I get out of this catch 22?
This will happen when (1) your assets use paths, for example:
background:url(image_path('awesome-background.gif'))
and (2) your asset_host
is set to a lambda/proc that requires the second argument (request
).
Your options are to either remove the request
argument (if you don't actually use it) or make it optional (and handle the case where it is nil
). This is easy in Ruby 1.9 (and should be easier, see notes):
config.action_controller.asset_host = ->(source, request = nil, *_){
# ... just be careful that request can be nil
}
If you want to be compatible with Ruby 1.8, there is no direct way to create a Proc/lambda with parameters with defaults, but you can use:
config.action_controller.asset_host = Proc.new do |*args|
source, request = args
# ...
end
Or do it using a method:
def MyApp.compute_asset_host(source, request = nil)
# ...
end
config.action_controller.asset_host = MyApp.method(:compute_asset_host)
Notes:
- Your block can return
nil
to signify the "default host", no need to use"#{request.protocol}#{request.host_with_port}"
- In theory you don't need to specify the protocol; a url starting with
//
should use the default protocol (http or https). I'm saying "should" as it looks like IE <= 8 will download the css assets twice and I've ran into problems with PDFkit.
So in your particular case, your asset_host
can be simplified to:
config.action_controller.asset_host = Proc.new { |source, request = nil, *_|
"//assets#{(source.length % 4) + 1}.example.com" if request && !request.ssl?
}
Edit: Use a lambda or else the *_
to avoid a bug feature of Ruby.
For ruby 1.8.x, @Marc-Andre's method(:compute_asset_host)
technique didn't work for me. Even though the method was defined directly above, NameError: undefined method `compute_asset_host' for class `Object'
was raised.
Here's what worked for me:
config.action_controller.asset_host = Proc.new do |*args|
source, request = args
if request.try(:ssl?)
'ssl.cdn.mysite.com'
else
'cdn%d.mysite.com' % (source.hash % 4)
end
end
Rails bug. Fixed.
https://github.com/rails/rails/issues/2947
精彩评论