Рецепт использования Asset Pipeline

    Пост навеян долгим апробированием различных гипотез правильной работы с изображениями через Asset Pipeline после перехода на Ruby on Rails 3.1 с предыдущих версий.

    Итак, Задача


    В CSS файле указать изображение, находящееся в папке assets. Изображение в production-среде должно быть предварительно скомпилировано.
    Казалось бы, ну что тут такого ведь есть официальный гайд, адаптированный перевод гайда, скринкаст, в конце-то концов. Здесь правило «It just works» работает только, если вы не допускали своих (или чужих) рук до чувствительных точек. Каких именно?

    Решение


    В ходе экспериментов подтвердилась только одна гипотеза, которую для удобства изложения удобно разбить на несколько частей.
    Дерево файлов будет выглядеть так (.erb — прихоть, работа через движок sass-rails также возможна):

    app/
    … assets/
    …… images/
    ……… rails.png
    …… stylesheets/
    ……… application.css.erb

    1. Для прекомпилирования используем не rake assets:precompile, а немного переделанный rake task
    Периодически у меня возникала ошибка
    rake assets:precompile
    rake aborted! rails.png isn't precompiled

    Причина её появляения мне непонятна, но точно знаю, что не я один такой: решение этой проблемы было найдено на гитхабе.

    2. Для указания пути в css используем хелпер asset_path erb-шаблонизатора.
    Есть куча хелперов для SASS, но ни один из них не сработал в своём проекте я его пока не использую.
    Содержимое application.css.erb:
    #header { background-image: url(<%= asset_path("rails.png") %>)

    В случае использования sass (application.css.scss):
    #header { background-image: image_url('rails.png') }

    3. Настройки production.rb, которые также играют роль:
    config.assets.compile = false # ведь мы будем компилировать заранее
    config.assets.digest = true # в названия файлов будут вставляться их подписи (для облегчения кеширования)
    config.action_dispatch.x_sendfile_header = "X-Sendfile" # 'X-Accel-Redirect' для nginx, или совсем комментируем, если http-server не поддерживает эту директиву

    Последняя строка немало меня напрягла при запуске на локальной машине:
    Изображение «localhost:3000/assets/rails-s43o54m765t656ed76i8gest.png» не может быть показано, так как содержит ошибки.
    Проблема заключалась в том, что http-сервер Webrick'a не поддерживает директиву x_sendfile_header (возможно ошибаюсь, но что-то там точно не сработало).

    Заключение


    Кончено, в теме до конца я ещё не разобрался, но, как выразился Александр Сергеевич,
    О, сколько нам открытий чудных
    Готовят просвещенья дух


    UPD: создал проект на github, демонстрирующий работу с использованием sass-rails
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 22

      0
      Т.е. пока что бы добавлять картинки из ассетов в цсс, нужно вводить erb в дополнительный слой компиляции?
        +2
        Нет. Должен помогать хэлпер image_url (вместо url) из движка sass_rails.
          +1
          Ну как сказано выше, ни один из них не сработал.
            0
            Должен помогать, но пока не получается. Проверил ещё раз созданием проекта с нуля.
            sass (3.1.7)
            sass-rails (3.1.0)
              +1
              В официальной документации image-url, что я успешно использую.
                0
                Да, кода не было под рукой, вы абсолютно правы.
              0
              Да, похоже на то. На проблему этих хелперов указывал EvilShadow. У меня они не интерпретировались в то, во что должны были.
                0
                А вы не в .css.erb а в .css.scss попробуйте
                  0
                  Ваш комментарий вдохновил меня попробовать ещё раз. Получилось, спасибо. Дело было не в бобине, а в невнимательности и нечистоте экспериментов.
                  Выложил версию, работающую через sass…
              0
              Они assets/images добавили в пути? Мне в каком то из релиз-кандидатов приходилось config.assets.paths << "images" в конфигах прописывать.
                0
                Да, в стабильной версии этой проблемы уже нет.
                  0
                  С rc6 проблем не замечалось.
                +1
                Столкнулись с той же проблемой в своем проекте.
                Путем проб и ошибок был найден работающий вариант для sass-файлов. Необходимо использовать хелпер asset_path. Например, так.

                background: url(asset_path('image.png', image)) 50% 30% no-repeat white

                Ассеты для sass в таком случае нормально отрабатывают.
                Так и не побежденной осталась корректная компиляция ассетов для изображений из coffee-файлов.
                Но я решил, что опеределение представлений через js — это все-таки bad-style, и вынес все определения элементов с картинками в sass.
                  +3
                  Блин, у меня ощущение что в Rails 3.1 внезапно что-то слишком намутили.
                  Он какой-то не «тупо-простой» стал.
                    +1
                    «It just works».
                      0
                      спасибо, исправился
                      +2
                      Я один не вижу смысла использовать изображения в assets? Не легче их положить как раньше в public/images и все. Никаких танцев с бубном. Они же все равно не компилируются.
                        0
                        Думаю смысл есть в том, что бы не мешать изображения закаченные пользователями, от изображений, яаляющимися частью сайта
                          +1
                          Но опять же сделайте папочку public/images/upload и все, не нужны опять никакие танцы с бубном и переписывание всех css. Я сначала тоже сделал «по феншую», но потом решил вернуть все назад. Да яваскрипт и css имеет смысл запихивать в assets, но картинки пусть как обычно лежат в паблике.
                            0
                            Ну смысл, полагаю, в том, что если у вас вдруг какое-то изображение изменится, то у него изменится и хеш в названии, так что браузер гарантированно его перезагрузит, а не возьмет из кеша.
                          0
                          Долго боролся вот с этим при переносе 3.1 в продакшн.
                          config.assets.compile = true неожиданно помогло — может, кому пригодится.
                            0
                            Да, документация это большая проблема в рельсах.

                            Я еще добавлю, что с assets можно делать так
                            //=require 'something.js'
                            

                            чтобы собрать файл еще на стороне сервера

                            И писать, например something.js.coffee, а потом CoffeScript прозрачно скомпилируется в джаваскрипт.

                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                            Самое читаемое