Действительно, при таком подходе view-файлы начинают выглядить лучше. Но кастомные элементы форм и хелперы становятся просто невыносимыми.
Но есть простой и элегантный способ как сделать их чище и проще…
К примеру возьмем кастомный элемент формы PriceRangeInput
.
class PriceRangeInput < SimpleForm::Inputs::Base def input output = template.content_tag(:div, class: 'j-price-slider') do div = '' div << template.content_tag(:div, class: 'row') do row = "" row << template.content_tag(:span, class: 'span3') do @builder.input(:min_total_price, label: false, input_html: { class: 'input-small j-min-total-price'}) end row << template.content_tag(:span, class: 'span3') do @builder.input(:max_total_price, label: false, input_html: { class: 'input-small j-max-total-price'}) end row.html_safe end div << template.content_tag(:div, class: 'row') do template.content_tag(:span, class: 'span6') do template.content_tag(:div, class: 'j-slider', :data => :slider_data) do end end end div.html_safe end output.html_safe end end
Этот элемент легко вызвать из формы:
= simple_form_for current_search_form, :url => :search, :method => "get" do |f| = f.input :price_range, :label => false, :as => :price_range
но упростив саму форму, кастомны элемент стало сложно понимать. В его структуре легко запутаться.
Выход есть
Решение — использовать Arbre — Ruby Object Oriented HTML Views.
Он позволяет легко использовать верстку в коде, а также создавать повторно используемые компоненты. Arbre рожден в проекте acive_admin и является, по сути, его основой.
Ближе к делу
Начнем с добавление помощничка в базовый класс элементов форм. Это один из редких примеров уместного monkey patch.
class SimpleForm::Inputs::Base private def arbre assigns={}, &block Arbre::Context.new assigns.reverse_merge(:builder=>@builder), template, &block end end
Теперь можем зарефаторить элемент формы:
def input arbre slider_data: slider_data do div class: 'j-price-slider' do div class: 'row' do span class: 'span3' do builder.input :min_total_price, label: false, input_html: { class: 'input-small j-min-total-price'} end span class: 'span3' do builder.input :max_total_price, label: false, input_html: { class: 'input-small j-max-total-price'} end end div class: 'row' do span class: 'span6' do div class: 'j-slider', data: slider_data end end end end end
Убрали все лишнее, оставили только то, что действительно нужно. Код выглядит приятнее и понятнее.
Достоинства Arbre
И так подведем краткое резюме.
1. Использование
Arbre
позволяет избавиться от буфера, для хранение генерируемых тегов:
# было buffer = '' buffer << template.content_tag(:div, class: 'row') do ... buffer << template.content_tag(:div, class: 'row') do buffer.html_safe # стало div class: 'row' do ... div class: 'row' do ...
2. Избавляет нас от необходимости применять мусорный content_tag
в коде и дает возмжоность прямо указывать необходимый тег:
# было template.content_tag(:div, class: 'row') # стало div class: 'row'
3. И самое интересное — компоненты.
Собственные компоненты
Удивительное еще и то, что Arbre
позволяет легко добавлять собственные элементы и использовать их в любом контексте.
class Row < Arbre::Component builder_method :row def build(title, attributes = {}) super(attributes.merge class: 'row') end end
Сразу после обьявления компонент готов к использованию в любом месте arbre-контекста. Теперь вместо:
template.content_tag(:div, class: 'row') do ...
можно писать
row do ...
а на выходе полчим код:
<div class="row"> ...
В общем arbre помогает сделать неизбежное — верстку в коде, более приятным. Рекомендую.
ссылка на оригинал статьи http://habrahabr.ru/post/184528/
Добавить комментарий