Набор Ruby библиотек для CMS и сайта медиа издания
Набор библиотек для разработки CMS медиа издания практически ничем не отличается от любого другого приложения. На примере приложения для Ленты и Ведомостей мы решили прокомментировать выбор каждой библиотеки. Описание составлено в формате обсуждения каждого гема.Предыдущая обзорная статья: Перезапуск медиа издания: обзор
CMS Ленты.руНаписанное про Ленту было актуально до апреля 2014 года. gem 'unicorn' foxweb: Здесь должно быть объяснение, почему не Puma.7even: Его не существует.zaur: Это мой консервативный подход не даёт парням свободы, чтобы раскрыть потенциал веб-сервера Puma. Я предпочитаю использовать классическую модель работы веб-сервера, когда работает несколько процессов. А модель, где обработчики конкурентно обрабатывают запросы в разных потоках в классическом интерпретаторе, мне не нравится. Отсутствие уверенности в потокобезопасности MRI-интерпретатора и нежелание всех переходить на jRuby или Rubinius предопределило выбор.7even: Готов перейти на рубиниус.foxweb: Ну теперь-то да.zaur: 7even, совсем недавно был другого мнения.7even: Рубиниус быстро развивается. Еще несколько месяцев назад он падал на конструкциях вида %i (foo bar). gem 'newrelic_rpm' gem 'newrelic-redis' foxweb: Наше Rails-приложение и очередь сообщений в Redis работали под постоянным мониторингом сервиса NewRelic. Если позволяют финансы, обязательно стоит использовать этот инструмент на всех критичных проектах. NewRelic сохраняет часы и трудодни, спокойный сон разработчиков, а некоторых спасает от увольнения и даже от физических увечий. До того, как кто-нибудь из редакции прибегал с криками «Ничего не работает!», мы уже знали, что именно, на каком сервере, по какой причине не работает, кто сломал, кто будет чинить и какая часть тела будет ампутирована. Некоторые графики мы вывели на HTML-страницу, которая 24 часа в сутки крутилась на большом мониторе на стене. Все всегда знали «что у нас с сайтом». Косяки одного разработчика видит вся команда. NewRelic максимально сокращает время реакции «упало — подняли». Для онлайн-СМИ это особенно критично.zaur: При настройке модуля надо не забывать исключать тестовое и дев окружение. Делается в конфигурационных файлах.
gem 'rails', '~> 3.2' foxweb: Это Rails.zaur: При этом старые рельсы. На новые так и не перешли, всё боялись, что «всё сломается».foxweb: Если быть точнее, большая часть гемов на тот момент не была адаптирована под Rails 4. gem 'faye' foxweb: Faye — простая реализация WebSockets, pub/sub заточенный на обмен сообщениями между разными пользователями, сидящими на одном сайте. Изначально это такой удобный чатик на вебсокетах. В нашем проекте Faye отправлял/получал сообщения между редакторами, сидящими в админке. Кто-то сохранил новый текст, кто-то залил 10 картинок — получили сообщения. Через какое-то время сервер сообщает, что картинки сгенерировались и опубликовались — получили сообщения все, кто занимается в данный момент именно этой статьёй. Всё это было очень удобно для редакции, повысило уровень взаимодействия и ускорило работу редакции в целом. Не нужно было писать в скайп «пацаны, никто не трогайте эту новость, я её сейчас сохраняю!» или «го в галерею, я создал!» Всегда было видно, какие редакторы в данный момент правят именно эту статью. В сочетании с системой журналирования и версионирования, а также сервиса сравнения по diff, коллективная работа редакции над одними и теми же материалами стала по-настоящему удобной. Единственное, что мы не успели реализовать — разделение по ролям и уровням доступа в системе оповещений. Было бы интересно сделать так, чтобы, к примеру, главный редактор мог видеть вообще всё на особой странице, при этом нигде не «светиться», а стажёры получали бы сообщения определённого вида. Хотя, большой объём работы ушёл на то, чтобы faye нельзя было использовать со стороны. Всякое бывает. Например, была реализована в какой-то степени авторизация через cookie и токены, хранящиеся в Redis. Токен привязывался к учётной записи конкретного редактора. Благодаря этому редакция могла видеть сообщения как бы от лица автора — «Василий Петров сохранил документ». В базовой версии faye никак не занимается авторизацией пользователей и защитой сообщений, а также вообще никак не связан с окружением Rails.ksavelyev: Ну на самом деле не очень простая, всем хорош Faye, но не масштабируется. gem 'faye-redis' foxweb: Плагин для faye, позволяющий использовать в качестве промежуточного хранилища для pub/sub сообщений, как видно из названия, Redis. У нас он использовался только для авторизации и хранения токенов (кажется).zaur: …и для хранения очереди фоновых процессов, таких как Resque или Cloudy (самописная поделка для работы с видео). gem 'thin' foxweb: Thin — это сервер для Faye.zaur: Не ваша любимая Puma.7even: А вот тут zaurа не смущает асинхронный сервер :)ksavelyev: У Заура не было выбора, по другому Faye не работает ;) gem 'pg' foxweb: Славный переезд с MySQL на Postgres. Сделали отдельную ветку в git, там всё наладили, протестировали и смерджили. Сначала сдампили структуру в SQL-файл. Естественно, он оказался непригоден для импорта напрямую в Postgres. Пришлось заменить, например, кавычки по всему файлу, какие-то вещи правились вручную. Думаю, 7even напишет большой рассказ о том, почему MySQL в таких проектах — плохо.7even: В MySQL нет hstore:) Вообще, если серьезно, Postgres в Ruby-сообществе намного популярнее и, как следствие, нагуглить решение любой проблемы проще. Плюс кастомные типы данных (массивы, json и тот же hstore) здорово облегчают жизнь. Psql (консольный клиент) в разы удобнее (если хотя бы немного его освоить).zaur: А вот ksavelyev считает, что надо было полностью переходить на MongoDB. gem 'postgres_ext' gem 'activerecord-postgres-json', github: 'michaelbn/activerecord-postgres-json' gem 'activerecord-postgres-hstore' zaur: Когда переходили с MySQL на PostgreSQL, рельсы были третьей версии. Использовали эти библиотеки для поддержки расширений PostgreSQL. gem 'marionette-rails' ksavelyev: Добавляет библиотеку Марионетт в Asset Pipelite. Марионетт добавляет к Бэкбону еще один уровень абстракции, вводит понятие модуля, приложения, позволяет удобно работать с визуальными представлениями коллекций. Делает из Бекбона почти, что Ангуляр.zaur: от Angular открещивался до последнего. gem 'haml_assets' gem 'dust_assets' gem 'haml_coffee_assets' ksavelyev: Добавляет поддержку haml/dust шаблонов, позволяет писать шаблоны с указанным синтаксисом и использовать их внутри Asset Pipeline, в итоге внутри JS приложения мы получаем переменную содержащую скомпилированные и готовые к использованию шаблоны, которые изначально были написаны на haml/dust. gem 'turbo-sprockets-rails3' ksavelyev: Ускоряет выполнение rake assets: precompile благодаря компиляции и объединения только изменившихся ассетов, содержит дополнительные функции по удалению старых ассетов. gem 'terminal-notifier-guard' foxweb: Гем-интерфейс к системной утилите вывода всплывающих уведомлений. Во время тестирования в системах Linux и OS X выводится всплывающее сообщение о статусе — успешно, неуспешно. Удобно: тесты прогоняются сами по себе, в это время можно переключиться на другое окно, а всплывающее уведомление напомнит о завершении тестирования. gem 'guard' gem 'guard-rspec' gem 'guard-zeus' foxweb: В Rails 4.1 появился Spring для фоновой предзагрузки кода. В Rails 3 для этой же цели приходилось использовать Zeus. Если разработчик меняет какой-то файл — немедленно происходит его перезагрузка Zeus«ом и прогон относящихся к нему тестов RSpec«ом. Guard многим известен как инструмент отслеживания событий, связанных с изменением файлов проекта. guard-rspec как раз запускает тесты при сохранении файлов.zaur: Что один, что второй доставляли больше неудобств. Запустить нужный тест проще напрямую руками. А так сплошные оправдания низкой производительности ruby.7even: Дело не в «низкой производительности ruby», а в медленном старте рельсового приложения. Естественно, если бы оно стартовало за пару секунд, эти костыли бы не понадобились.foxweb: 470 спеков за 14 секунд — это достаточно быстро.
gem 'rspec-rails', '~> 2.14' foxweb: Кажется, раньше мы использовали TestUnit, но потом с подачи 7even довольно быстро перешли на RSpec. Это подняло процесс тестирования на новый уровень. У нас был полноценный TDD. Потом мы перестали писать тесты, потому что нового кода почти не появлялось, а какой-то код было очень сложно или нецелесообразно (по времени) покрывать тестами.zaur: Спорное решение, победило большинство. А этот новый уровень называется «нафиг тесты». gem 'ffaker' foxweb: При создании новых сущностей нужно было протестировать и наполнить случайными данными (имя, фамилия, емейл, должность и прочее). В процессе отладки обычному программисту под силу сделать 1–3 записи, потом надоедает, а код так и остаётся недоотлаженным. Собственно, при помощи классов этого гема можно генерировать очень разнообразную и, самое главное, правдоподобную информацию. 7even внёс в него свой вклад добавлением генератора русских имён и фамилий. Таким образом можно было отладить производительность на разных наборах данных до деплоя в production. Применение этого гема не связано с тестами. При написании тестов использовались, например, стандартные рельсовые fixtures. gem 'quiet_assets' foxweb: Молчаливые ассеты? ksavelyev: Именно, молчаливые. Когда рельсовое приложение запускается локально на машине разработчика в дев режиме, веб-сервер отдает статику сам. В продакшне этим занимается Nginx, который ведёт отдельные логи для ассетов. В девелопменте информация о том, что веб сервер отдал пачку ассетов обычно никому не нужна, этот гем блокирует мусорные сообщения о том, что статические файлы были отданы браузеру. В случае необходимости, если такого гема нет, всегда можно фильтровать логи используя grep, например команда tail -f development.log | grep SELECT будет мониторить лог на появление в них SQL запросов. gem 'colorize' foxweb: При выводе данных в консоль (может быть, логов импорта или каких-то rake-тасков) можно было рубишными методами выводить в консоль цветные строки, что повышало общую читабельность логов. gem 'rails-erd' foxweb: В какой-то момент число сущностей и связей между ними увеличилось настолько, что стало сложно держать их в голове и передавать знания новым сотрудникам. При помощи этого гема можно было в пару действий сгенерировать диаграммы моделей со связями и кучей разных опций. Диаграмму потом печатали на большом листе A3 и много думали.zaur: Потом выбрасывали и рисовали на доске. gem 'ruby_parser' foxweb: Кто-то экспериментировал с парсингом Ruby. Возможно, для собственного механизма аннотации файлов. 7even: Не я. gem 'capistrano' foxweb: С Capistrano всё было хорошо, пока не появилась Mina. Capistrano работал медленно, зато умел делать мультисерверный деплой. Mina быстрая, и ее вывод намного читабельнее. Не успели перевести CMS и фронтенд на Mina, зато спецпроекты и, например, Дом.лента.ру деплоили изначально при помощи Mina. Мультисерверный деплой довольно просто «эмулировался» при помощи простого цикла по списку хостов (кажется, максимум их было 4). То есть, просто 4 деплоя на 4 хоста за один проход.zaur: Сейчас для деплоя не используется ни то, ни то. Перешли на схему управления с помощью ansible. Деплой без перерыва в работе сервиса обеспечивает HAProxy.7even: Стало раз в 5 медленнее мины, зато zero-downtime.foxweb: Скажу тебе по секрету, оно в текущей настройке даже не zero-downtime;) gem 'better_errors' gem 'binding_of_caller' ksavelyev: better_errors значительно улучшает стандартный информационный экран 500-й ошибки. Появляется браузер стека вызова и интерактивная руби-консолька, позволяющая просматривать состояние объектов.foxweb: Не понимаю, как мы раньше отлаживали рельсовые приложения без консоли в браузере.7even: Тесты надо писать, а не в браузере ссылочки вручную тыкать.ksavelyev: Если бы фронтендеры писали тесты в бекенде, а бекендеры делали бы тенюшки и интегрировали шрифты в страницу, мир однозначно был бы лучше.foxweb: Я имел ввиду как раз те случаи, когда в обычной консоли невозможно поймать ошибки вёрстки, например. gem 'jazz_hands' 7even: Набор из pry, awesome_print и нескольких плюшек для pry.foxweb: Добавляет в консоль красивую раскраску, подсветку синтаксиса и форматирование вывода в стандартной рельсовой консоли. Оставлено в production, потому что частенько приходилось лазить в консоль на работающих серверах. gem 'active_record-annotate' 7even: Для аннотации моделей изначально использовали annotate_models, но в определенный момент он начал ломаться на новых типах данных в PostgreSQL — и мы решили написать свою реализацию.foxweb: ты решил, ты написал.7even: Github. gem 'rabl' gem 'jbuilder' gem 'gon' zaur: Для сериализации мы начинали использовать Rabl. Ужасно медленное решение. Постепенно стали переходить на JBuilder. А для передачи JSON на страницу на этапе генерации HTML использовали Gon. gem 'fast_seeder' foxweb: Из того же разряда, что и Ffaker, но умеет использовать в качестве источника данные из CSV-файлов. gem 'oj' 7even: Самый быстрый парсер JSON.foxweb: Питер лучше чем Москва. А чем лучше? Чем Москва. gem 'slim' foxweb: Сначала был Haml, но потом оказалось, что Slim не только легче читается и пишется, но ещё и быстрее рендерится. Для замены Haml на Slim по всему проекту можно использовать, например, haml2slim. gem 'russian' foxweb: Известный гем для русификации дат и стандартных рельсовых сообщений. gem 'whenever', require: false foxweb: Кронификатор — библиотека для управления крон-тасками на языке Ruby. Что-то у нас там раз в сутки с новостями такое происходило. gem 'redcarpet' foxweb: Гем для работы с Markdown, только никто не помнит, где мы его использовали. gem 'kaminari' foxweb: Пагинатор — разбивает большие списки на страницы (1,2,3…100). gem 'truncate_html' ksavelyev: Лень-матушка заставляет добавлять в гемфайл гемы из одной функции. В данном случае нам лениво было корректно откусывать кусок HTML регулярным выражением.foxweb: Не знал про такое. gem 'devise' gem 'devise-encryptable' zaur: Классика жанра для создания авторизации на сайте. gem 'mini_magick' foxweb: Гем-интерфейс к ImageMagick. gem 'mimemagic' foxweb: Гем для определения типа загружаемого контента. gem 'foreman' foxweb: Простой менеджер процессов для разработчика. Когда работаешь над большим проектом, требуется запускать много маленьких сервисов. Foreman запускает всё нужное одной командой. В нашем примере это Rails, Faye, тесты, сервисы очередей публикации и обработки картинок.7even: Запуск тестов через Foreman делал их вывод настолько нечитаемым, что вскоре я выпилил их из Procfile.foxweb: Вспомнил, кажется, в общий вывод вместе с тестами попадало вообще всё, включая сообщения Faye и логи приложения. gem 'faraday' 7even: Фарадай — незаменимая библиотека для обращения к внешним сетевым ресурсам. Благодаря системе middleware (аналогичной Rack) можно один раз задать все трансформации как запроса, так и ответа — например, добавить заголовок OAuth-авторизации к запросу перед его отправкой, или распарсить JSON ответа и обернуть его в Hashie: Mash.foxweb: «Внешние сетевые ресурсы» — банальные HTTP-запросы на старую версию сайта.7even: Окей, к любым сетевым ресурсам. В данном случае старая версия сайта, но фарадай мы использовали в самых разных ситуациях — были и API, и HTML-ки. gem 'faraday_middleware' 7even: В этом геме есть много полезных middleware для фарадая.foxweb: Это, например, JSON?7even: И, например, mashify. gem 'hashie' 7even: Hashie — собрание расширений к хэшам. Мы использовали Hashie: Mash — вариация хэша, в которой обращение к элементам идет не как обращение к ключу, а как вызов одноименного метода (например, не user[: name], а user.name). К сожалению, в дальнейшем этим гемом стали злоупотреблять и использовать как замену моделям.foxweb: Новый формат полюбили верстальщики и назвали его «дот-нотацией».7even: Вот я об этом и говорю. gem 'nokogiri' foxweb: Известная библиотека для разбора XML/HTML. Активно использовалась при разборе старых архивов. При помощи неё в процессе импорта мы заменяли устаревшие ссылки, теги картинок, вычищали неактуальный код, мусор и много всего прочего. Вроде бы даже закрывали незакрытые тэги. gem 'eventmachine' gem 'em-synchrony' gem 'em-hiredis' 7even: Для обработки видео использовался сторонний сервис E**** *******m, взаимодействие с которым шло через их REST API. На нашей стороне работал демон, который через очередь в редисе получал путь к загруженному редактором видеофайлу, отправлял его на сервер E****, перекладывал в другую Redis-очередь, опрашивал сервер каждые 5 минут — и когда обработка на стороне E**** была завершена, демон выкачивал готовые файлы. Так как все эти процессы должны были проходить параллельно, демон был написан на EventMachine.zaur: Звёздочками закрашен не мат. gem 'streamio-ffmpeg' 7even: Эта обертка вокруг ffmpeg позволила получать ширину, высоту, битрейт, длительность и другие метаданные видеофайла.foxweb: Эти данные потом использовались для отображения видеоконтента на страницах сайта. gem 'ruby-progressbar' foxweb: Простая реализация прогресс-бара в консоли. Использовался при импорте данных из старой базы в новый формат. Когда впереди тебя ждёт обработка более 500.000 материалов, прогресс-бар хорошо помогает планировать время и медитировать в процессе. Класс довольно простой. На входе задаются такие параметры, как конечное число цикла, всякие настройки вида и т.д. При выводе сам считает проценты, время, крутит счётчик, двигает полоску, в общем, делает всё, что и обычный прогресс-бар в любой ОС. Сообщить главному редактору, что на импорт старых данных нужно трое суток — бесценно. gem 'version' foxweb: Гем-безделушка, который увеличивает номер версии в файле VERSION по запросу и ставит соответствующий тэг на коммитах в Git. Поиграли и забыли. gem 'environment' zaur: Один из велосипедов, для распределения настроек по разным окружениям, коих было больше трёх. Ошибка проектирования, расплата.7even: Канул в лету. gem 'settings' 7even: Для хранения настроек приложения в разное время использовались и configatron, и rails_config. Но где-то гем не работал вне контекста Rails — что лишало нас возможности обращаться к настройкам из Faye и демона на эвентмашине —, а где-то были другие проблемы; поэтому в итоге была написана своя реализация. В настоящее время она доступна на Github. gem 'bluepill' 7even: Тут все просто: мониторинг сервисов.foxweb: Часто нужно было перезапускать упавшие или зависшие сервисы прямо на продакшене. Потом нам надоело и мы поставили Bluepill. Типа Foreman, только для сервера.zaur: Ужасный мониторинг сервисов. Но другие были не лучше. Нужно было уметь следить за процессом, который мог изменить PID. Одновременно это делать могли не многие. Менял веб-сервер свой процесс в момент zero-downtime restart. Например во время деплоя, для бесперебойной работы приложения, использовали такую замечательную функциональность Unicorn. gem 'diffy' foxweb: Офигенно полезный для редакции инструмент. Позволяет смотреть историю редактирования текстов, как в Википедии. Естественно, чтобы было с чем сравнивать, должна сохраняться история версий. Она у нас уже работала, а прикрутить такой инструмент было делом пары часов. Полезный эффект для редакции был огромен.zaur: Был у нас случай, когда редактор сделал опечатку. На сайте-то поправили вовремя, а вот в RSS на главную страницу Рамблер.Новостей ушёл, конечно, неправильный вариант.ksegoh: И тут парни узнали разницу между Сирией и Ливией.
zaur: Один из сценариев использования версионирования. Можно проследить, как стажёр пишет заметку. Например, он может последовательно писать по абзацу новости. А может расписать план в несколько предложений, а далее расширить текст. То есть можно увидеть ход мысли человека, или выявить копипастера.
gem 'roo' foxweb: Гем для извлечения данных из таблиц Excel. Пригодился во время Олимпиады, когда редакторы и поставщики контента предоставляли данные по соревнованиям и участникам в табличном виде. Городить веб-интерфейс для работы с таблицами не было ни времени, ни желания. gem 'net-scp' foxweb: Тоже «олимпийский» гем, предоставлял возможность эти самые таблицы забирать по SSH с файловых серверов. gem 'resque' gem 'resque-web' gem 'resque-pool' zaur: Генерация изображений разных размеров производилась в фоне. Одной из причин были неведомые проблемы в работе ImageMagick. При этом некоторое время (а я до сих пор) частично вменяли вину Sidekiq (менеджер конкурентных фоновых процессов). Сменили версии библиотеки, пробовали другие, переустанавливали ОС, меняли сервер. В общем, до сих пор это привидение летает в том доме. Фоновые процессы обрабатывает Resque, конвертирует ImageMagick. В фоне обрабатывались и архивы с изображениями.foxweb: Мистика мистикой, но были и рациональные объяснения. Часто я бегал к редакторам, которые под видом JPEG заливали, например, PNG или использовали недопустимые символы в имени файла Что, конечно, не снимает вины с ImageMagick.zaur: И с Вас. «Неправильные» символы и в текущей админке доставили удовольствие. Кириллица — ваше проклятие. Попались они, кстати, в HTTP заголовках…
gem 'ar_after_transaction' zaur: Я не знаю, зачем это здесь.ksavelyev: Как зачем? Ты и Сева решали проблему выполнения кода после окончания успешной транзакции.API-сервис редакционной админки Ведомостей gem 'rails-api' 7even: Так как сервис задумывался исключительно как API, отдающий JSON, было решено облегчить приложение и использовать только необходимый набор функциональности, который дает rails-api. gem 'active_model_serializers' 7even: После ковыряния с rabl и jbuilder оптимальным выбором для сериализации объектов в JSON представлялась разработка из того же rails-api, позволяющая использовать объектный подход. gem 'awesome_pry' 7even: В определенный момент jazz_hands утратил совместимость с новыми версиями Ruby (а, может, и каких-то гемов), к тому же мы все равно не использовали всю его функциональность — поэтому появился такой мини-гем, просто объединяющий в себе pry и awesome_print. gem 'ice_nine', require: %w (ice_nine ice_nine/core_ext/object) 7even: Глубокая заморозка объектов. Руби позволяет изменять значения констант, поэтому для настоящей иммутабельности нужно использовать #freeze; для хэшей и массивов же обычный #freeze только запрещает добавлять и удалять элементы —, а чтобы запретить изменение самих элементов, нужно рекурсивно заморозить все объекты. Или подключить этот гем и вызвать #deep_freeze. gem 'highline' 7even: Для самодостаточности приложения и возможности проверить каждый роут без использования фронт-энда был написан небольшой консольный API-клиент, в котором и пригодился highline. gem 'rack-cors' 7even: Поддержка CORS-запросов. gem 'database_cleaner' 7even: Так как тесты используют БД, для очистки всех таблиц перед каждым тестом использовался database_cleaner.zaur: Ещё он пригодился, когда писали свои rake task для обнуления базы данных в дев режиме. Такая необходимость возникает из-за того, что pow держит приложение запущенным. А, значит, у базы данных были активные соединения, которые не позволяли просто пересоздать базу. gem 'guard-yard' 7even: Плагин для guard, который запускает генерацию YARD-документации из изменившихся файлов. gem 'apiaryio' 7even: Для документирования API решили использовать apiary.io, а данный гем дает возможность генерировать документацию в HTML и просматривать локально. group: development do gem 'puma' end foxweb: Тут Puma, а в production всё-таки Unicorn. group: production do gem 'unicorn' end foxweb: Тут Unicorn, а в development всё-таки Puma.Фронтенд CMS Ведомостей source 'https://rubygems.org' source 'https://rails-assets.org' ksavelyev: Строка с источником rails-assets.org стала появляться всё чаще и чаще в проектах с богатым фронтендом. Смысл добавления еще одного источника в том, что rails-assets может сделать гем практически из любого github репозитория. Для того, чтобы репозиторий трансформировался в гем нужно, чтобы он был валидным bower-репозиторием. Указав дополнительный источник мы сможем добавлять в гем-файл вызовы типа gem 'rails-assets-BOWER_PACKAGE_NAME'. Все JS/CSS ресурсы этого гема будут доступны в Asset Pipeline и дальше их можно будет использовать в своем проекте так, как будто вы добавили руками необходимые файлы. gem 'puma' gem 'unicorn', group: : production zaur: Ну вы понимаете, что я об этом думаю.
gem 'compass-rails' ksavelyev: Это мой самый любимый гем, сколько времени он мне сэкономил, даже не могу представить. Это такой швейцарский нож для технолога. Основная задача Компаса — упростить и систематизировать работу с различными вендорными префиксами в SASS/SCSS. Компасс добавляет множество полезных функций которые помогают технологу вставлять на страницу кастомные шрифты, превращать каталоги с иконками в спрайты, задавать сложные градиенты в CSS, оперировать бекграундами, тенями, транзишнами не думая о том, как они реализованы в разных браузерах и делать еще много разных интересных и полезных вещей. В общем, освобождает время для творчества. gem 'rails-assets-angular' gem 'rails-assets-angular-cookies' gem 'rails-assets-angular-animate' gem 'rails-assets-angular-sanitize' gem 'rails-assets-angular-ui-router' gem 'rails-assets-angular-promise-tracker' gem 'rails-assets-angular-loading-bar' gem 'rails-assets-restangular' gem 'rails-assets-angular-contenteditable' gem 'rails-assets-angular-ui-ace' gem 'rails-assets-angular-bootstrap-colorpicker' gem 'rails-assets-ng-sortable' ksavelyev: На самом деле это не гемы, а bower-репозитории, которые трансформировались в гемы благодаря rails-assets, о котором я писал выше.Для вас старались:
foxweb (foxweb) — Алексей Курепин (бильд заметки!) 7even (7even) — Всеволод Ромашов ksavelyev (ksavelyev) — Константин Савельев ksegoh — Ксения Гохгут zaur (kavkaz) — Заур Абасмирзоев