Easy layout in forced places: helpers, decorators, form elements

    Many already know that in views it is not recommended to use logic or generally any data manipulations. To do this, such code is placed in decorators , custom form elements , components, and simply helpers in the end.

    Indeed, with this approach, view files begin to look better. But custom form elements and helpers are simply unbearable.

    But there is a simple and elegant way to make them cleaner and simpler ...



    For example, take a custom form element 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
    

    This element is easy to call from the form:

    = simple_form_for current_search_form, :url => :search, :method => "get" do |f|
        = f.input :price_range, :label => false, :as => :price_range
    

    but having simplified the form itself, the custom element has become difficult to understand. Its structure is easy to get confused.

    There is an exit


    The solution is to use Arbre - Ruby Object Oriented HTML Views.

    It makes it easy to use layout in code, as well as create reusable components. Arbre was born in the acive_admin project and is, in fact, its foundation.

    Get to the point


    Let's start by adding an assistant to the base class of form elements. This is one of the rare examples of an appropriate monkey patch.

    class SimpleForm::Inputs::Base
    private
      def arbre assigns={}, &block
        Arbre::Context.new assigns.reverse_merge(:builder=>@builder), template, &block
      end
    end
    

    Now we can refactor the form element:

     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
    

    They removed all unnecessary, left only what is really needed. The code looks nicer and clearer.

    Advantages of Arbre


    And so to summarize a brief summary.

    1. Use
    Arbre
    allows you to get rid of the buffer for storing generated tags:

    # было
    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. saves us from having to use the garbage content_tagin the code and gives vozmzhonost directly specify your tag:

    # было
    template.content_tag(:div, class: 'row')
     # стало
    div class: 'row'
    

    3. And the most interesting thing is the components.

    Proprietary components


    Another amazing fact is that Arbreit makes it easy to add your own elements and use them in any context.

    class Row < Arbre::Component
      builder_method :row
      def build(title, attributes = {})
        super(attributes.merge class: 'row')
      end
    end
    


    Immediately after the announcement, the component is ready for use anywhere in the arbre context. Now instead of:

    template.content_tag(:div, class: 'row') do
      ...
    

    can write

    row do
      ...
    

    and at the output we get the code:

    ...

    In general, arbre helps to make the inevitable - layout in the code, more enjoyable. Recommend.

    Also popular now: