Пользовательские формы помощников - PullRequest
24 голосов
/ 12 апреля 2010

Есть ли способ, которым я могу создать пользовательский помощник формы, чтобы вместо:

special_field_tag :object, :method

Я могу достичь чего-то вроде:

form.special_field :method

Ответы [ 3 ]

47 голосов
/ 13 апреля 2010

Да, вы можете добавить класс FormBuilder и получить доступ к объекту, переданному в form_for. Я сделал это для многих вещей: даты, время, измерения и т. Д. Вот пример:

class ActionView::Helpers::FormBuilder
  include ActionView::Helpers::TagHelper
  include ActionView::Helpers::FormTagHelper
  include ActionView::Helpers::FormOptionsHelper
  include ActionView::Helpers::CaptureHelper
  include ActionView::Helpers::AssetTagHelper

  # Accepts an int and displays a smiley based on >, <, or = 0
  def smile_tag(method, options = {})
    value = @object.nil? ? 0 : @object.send(method).to_i
    options[:id] = field_id(method,options[:index])
    smiley = ":-|"
    if value > 0
      smiley = ":-)"
    elsif smiley < 0
       smiley = ":-("
    end
    return text_field_tag(field_name(method,options[:index]),options) + smiley
  end

  def field_name(label,index=nil)
    output = index ? "[#{index}]" : ''
    return @object_name + output + "[#{label}]"
  end

  def field_id(label,index=nil)
    output = index ? "_#{index}" : ''
    return @object_name + output + "_#{label}"
  end

end

Который вы можете использовать так:

<% form_for @quiz do |f| %>
  <%= f.smile_tag(:score) %>
<% end %>

Существуют некоторые переменные экземпляра, созданные Rails, к которым вы можете обращаться с помощью этих вспомогательных методов:

  • @ object - объект модели, указанный в форме
  • @ имя_объекта - имя класса объекта
  • @ template - я думаю, что это экземпляр ActionView, вы можете обойти все добавления, которые я добавил, вызывая методы в шаблоне. Еще не пробовал.
  • @ options - опции, передаваемые FormBuilder при его создании вызовом form_for

Я написал методы field_id и field_name для создания этих атрибутов в элементах ввода HTML так же, как это делают обычные помощники, я уверен, что есть способ привязать к тем же методам, которые использует Rails, но я этого не сделал нашел еще.

Небо - это предел того, что вы можете сделать с помощью этих вспомогательных методов, они просто возвращают строки. Вы можете создавать целые HTML-таблицы или страницы в одной, но вам лучше иметь веские причины для этого.

Этот файл должен быть добавлен в папку app / helpers

7 голосов
/ 25 июля 2014

@ Tilendor, большое спасибо за указатели. Вот пример вспомогательного тега формы enum_select, который использует перечисления Rails 4.1 для автоматического заполнения параметров тега select:

# helpers/application_helper.rb
module ApplicationHelper
  class ActionView::Helpers::FormBuilder
    # http://stackoverflow.com/a/2625727/1935918
    include ActionView::Helpers::FormTagHelper
    include ActionView::Helpers::FormOptionsHelper
    def enum_select(name, options = {})
      # select_tag "company[time_zone]", options_for_select(Company.time_zones
      #   .map { |value| [value[0].titleize, value[0]] }, selected: company.time_zone)
      select_tag @object_name + "[#{name}]", options_for_select(@object.class.send(name.to_s.pluralize)
        .map { |value| [value[0].titleize, value[0]] }, selected: @object.send(name))
    end
  end
end

Самая хитрая конструкция - @object.class.send(name.to_s.pluralize), которая создает хэш доступных значений (например, Company.time_zones). Помещение в helpers/application_helper.rb делает его автоматически доступным. Используется как:

<%= f.label :billing_status %>:
<%= f.enum_select :billing_status %><br />
3 голосов
/ 21 августа 2015

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

class ActionView::Helpers::FormBuilder
  def phone_text_field name, options = {}
    value = object.public_send(name).to_s
    if value.start_with? "9" # national number
      value = value[1..-1]
      options["value"] = value
    end
    text_field name, options
  end
end

Я помещаю это в app / helpers / application_helper.rb и использую его так же, как использую text_field() помощник. Надеюсь, это кому-нибудь поможет.

...