Подтвердить что ты не робот

Rails 3.1 не может компилировать активы на prod из-за конфигурации хоста актива

Моя производственная конфигурация asset_host выглядит следующим образом:

  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 
  } 

... который более или менее прямо из документов:

http://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html

Когда я перехожу к активам: прекомпиляция, я получаю следующее:

$ RAILS_ENV=production bundle exec rake assets:precompile 
rake aborted! 
This asset host cannot be computed without a request in scope. Remove 
the second argument to your asset_host Proc if you do not need the 
request. 

.... за исключением того, что я не могу удалить второй аргумент, потому что мне нужно знать, является ли запрос ssl или нет. Тем не менее, я понимаю, что запроса нет во время рейк-задачи для генерации активов....

Итак, как мне выйти из этого улова 22?

4b9b3361

Ответ 1

Это произойдет, когда (1) ваши активы используют пути, например:

background:url(image_path('awesome-background.gif'))

и (2) ваш asset_host установлен в lambda/proc, для которого требуется второй аргумент (request).

Ваши варианты - либо удалить аргумент request (если вы его вообще не используете), либо сделать его необязательным (и обрабатывать случай, когда он равен nil). Это легко в Ruby 1.9 (и должно быть проще, см. Примечания):

config.action_controller.asset_host = ->(source, request = nil, *_){
  # ... just be careful that request can be nil
}

Если вы хотите быть совместимым с Ruby 1.8, нет прямого способа создать Proc/lambda с параметрами со значениями по умолчанию, но вы можете использовать:

config.action_controller.asset_host = Proc.new do |*args|
  source, request = args
  # ...
end

Или сделайте это с помощью метода:

def MyApp.compute_asset_host(source, request = nil)
  # ...
end

config.action_controller.asset_host = MyApp.method(:compute_asset_host)

Примечания:

  • Ваш блок может вернуть nil, чтобы обозначить "хост по умолчанию", не нужно использовать "#{request.protocol}#{request.host_with_port}"
  • В теории вам не нужно указывать протокол; url, начинающийся с //, должен использовать протокол по умолчанию (http или https). Я говорю "должен", поскольку он выглядит как IE <= 8 будет загружать ресурсы css дважды, и я столкнулся с проблемами с PDFkit.

Итак, в вашем конкретном случае ваш asset_host можно упростить до:

config.action_controller.asset_host = Proc.new { |source, request = nil, *_| 
  "//assets#{(source.length % 4) + 1}.example.com" if request && !request.ssl? 
}

Изменить: используйте lambda или *_, чтобы избежать ошибка в Ruby.

Ответ 2

Для метода ruby ​​1.8.x, @Marc-Andre method(:compute_asset_host) для меня не работало. Несмотря на то, что метод был определен непосредственно выше, NameError: undefined method `compute_asset_host' for class `Object' был поднят.

Вот что сработало для меня:

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