Pull to refresh

19 необщеизвестных приёмов

Reading time 5 min
Views 2K
Original author: Питер Купер (Peter Cooper)
Заметка не новая, но я уверен, что и сейчас не все знают всё нижеперечисленное (Здесь и далее курсив переводчика).

Когда я смотрю на свой, да и на чужой, код на рельсах, я часто вижу нереализованные возможности для применения определённых рельсовых техник. Я бы хотел перечислить некоторые приёмы и советы для повышения эффективности приложения и кода, как памятку для себя и для вас.

Замер скорости в контроллерах — это очень просто. Используйте метод benchmark в любой модели.

User.benchmark("adding and deleting 1000 users") do
	1000.times do
		User.create(:name => 'something')
		x = User.find_by_name('something')
		x.destroy
	end
end

Ваш код, конечно, будет получше ;-) Обычные SQL логи не будут писаться внутри метода benchmark, только результаты.

acts_as_nested_set — почти все (хо-хо) хорошо знакомы с acts_as_tree, но незаметно в рельсах появилось acts_as_nested_set. Это похоже на acts_as_tree, но с удобствами: вы можете выбрать всех детей (и их наследников) одного узла одним запростом. Имеется список методов.
image

Простые коллекции через to_proc — надоело писать post.collect { |p| p.title } или post.select { |p| p.activated? }.collect{ |p| p.title}? С помощью небольшого хака переводим символы в процедуры. Можно писать post.collect(&:title) или post.select(&:activated?).collect(&:title)! Здесь об этом куда больше.

Превращение массивов в предложения — если вам в показе (view) надо вывести список имён, вы берёте массив типа ['Peter', 'Fred', 'Chris'], соединяете запятыми и добавляете «and» перед последним, что могло бы поднадоесть. Метод to_sentence спешит на помощь: names.to_sentence вернёт "Peter, Fred, and Chris". (Да, это не портабельно и англоцентрично. В примечаниях к оригинальной статье об этом больше.)

Отправка файла пользователю — обычно статические файлы передаются по прямому УРЛу в обход рельсового приложения. Тем не менее в ряде ситуаций может быть полезно спрятать расположение файла, особенно если вы посылаете что-либо ценное, наподобии е-книги. Может также требоваться ограничить посылку файлов только залогиненным пользователям. Проблему решает send_file. Файлы передаются по 4096 байтов, так что даже большие файлы систему не затормозят.

Выборка элементов страницы через RJS — поменять элемент в RJS нетрудно, но что если мы не знаем, какой именно элемент надо менять, и хотели бы адресоваться через CSS-запрос? Это возможно с методом select. Например, page.select('#items li').each { |item| item.hide }. Мощная штука!

Проверка существования — при выполнении Model.find(id) мы получим исключение, если элемента «id» не нашлось. Чтобы это избежать, сперва выполняем Model.exists?(id), чтобы узнать, есть ли такой.

Числовые хелперы для частых задач — они нечасто используются, но тем не менее весьма полезны:
number_to_currency(1234567.948) # => $1,234,567.95 или human_size(1234567890) # => 1.1GB или number_with_delimiter(999999999) # => 999,999,999. Есть и другие. (То же замечание относительно локализации.)

Простое тестирование роутинга — test_routing — хелпер, который подменяет умолчательный «routes» в routes.rb для опытов. Например:

with_routing do |set|
  set.draw { set.connect ':controller/:id/:action' }
  assert_equal(
     ['/content/10/show', {}],
     set.generate(:controller => 'content', :id => 10, :action => 'show')
  )
end

Здесь подробнее.

Много интересного о запросеrequest.post? и request.xhr? — популярные способы посмотреть на POST- и аякс-запросы, но есть и другие, не столь известные. Например, request.subdomains вернёт массив поддоменов, который можно использовать при авторизации, request.request_uri даст полный локальный URI, request.host это полное имя хоста, request.method вернёт метод в нижнем регистре, и request.ssl? определит, SSL ли это.

Дальнейшее повышение производительности — по умолчанию рельсы записывают сессии на локальную файловую систему. Многие меняют это на ActiveRecordStore для записи сессий в базу. Ещё более быстрая альтернатива будет Memcached, но его не так лекго установить (и не получится, если сервера чужие, и т.д.). И тем не менее можно сделать быстрее, чем ActiveRecordStore, через использование SQLSessionStore Стефана Кейса (Stefan Kaes). Плагин обходит недостатки ActiveRecordStore через свою SQL технику сохранения сессий.

Кеширование статического контента при старте — если у вас есть данные, которые не меняются от рестарта к рестарту, закешируйте их. Например, это мог бы быть YAML или XML файл в /config-e с настройками приложения, и его можно загружать в константу в environment.rb, ускоряя и упрощая доступ.

Проверка валидности (X)HTML-а — не для всех, но если ваш вывод валиден, то есть шансы, что ваши показы (view) рендерятся правильно. Скот Реймонд (Scott Raymond) разработал хелпер assert_valid_markup, который можно использовать для функционального тестирования.

Более опрятное тестирование HTML-вывода — объединим парсер Hpricot от вая (why) со специальным тестовым расширение, и получим мощные тесты наподобие assert_equal "My title", tag('title') или assert element('body').should_contain('something'). Это идеально подходит для тестирования пользовательских шаблонов. Так или иначе, уж лучше, чем assert_tag!

Запуск длинных процессов отдельно в фоне — есть небольшой фреймворк BackgrounDRbот Эзры Зигмунтовича (Ezra Zygmuntovich), который запускается в виде демона и принимает задачи от рельсового приложения, и выполняет их независимо. Мощная вещь, помогает в рассылке писем, получении УРЛов, и прочего, что может затормозить время выполнения запроса основного приложения. Демо-таск увеличивает переменную на 1, после чего делает sleep на 1 секунду. Далее делаем рельсовый метод, который опрашивает эту переменную, и чувствуем разницу. Здесь больше.

Красивые иды в УРЛах — заменим to_param в вашей модели и вернём что-нибудь вроде "#{id}-#{title.gsub(/[^a-z0-9]+/i, '-')}", для УРЛа вида yoursite.com/posts/show/123-post-title-goes-here.... Куда приятнее для пользователя, и не надо ничего менять в Post.find(params[:id]), так как нецифровые символы будут выкинуты автомагически. Полное объяснение тут. (ссылка битая, похоже)

Выделение кусков функциональности в энжины — все слышали про плагины, но прискорбно мало кто используюет энжины (engines)! Энжины это плагины на стероидах (или на барбитуратах). У них могут быть свои модели, контроллеры и показы, и они могут интегрироваться с любым приложением. Это позволяет выделять общие куски функциональности (логины, управление пользователями, контент-менеджмент и т.п.) в отдельные «движки», которые можно включать в разные проекты за считанные минуты. Скажем нет писанию дурацких логинов! Энжины это круто, но должны быть ещё гораздо круче.

Вычисления — желаете вычислить максимум, минимум, среднее, сумму для данных в таблице? Это возможно, с Calcuations из ActiveRecord. Person.average('age'), Person.maximum(:age, :group => 'last_name'), Order.sum('total'): всё это теперь воплощается. Большинство из этого можно настроить дополнительными опциями, почитайте, если этого ещё нет у вас в коде.

Вывод данных в XML или YAML — не только, чтобы создать .rxml шаблон Builder-a для вывода в XML. У ActiveRecord есть метод to_xml, выводящий результат в XML. Работает как с простыми объектами, так и с целыми таблицами: User.find(:all).to_xml. Инклуды также поддерживаются: Post.find(:all, :include => [:comments]).to_xml. То же самое в YAML, с помощью to_yaml.

Tags:
Hubs:
+23
Comments 30
Comments Comments 30

Articles