在表单中创建自定义标签字段

时间:2009-06-21 23:45:18

标签: ruby-on-rails ruby forms

我希望能够生成以下标记:

<label for="field">Something <span class="hint">Field hint</span></label>

来自以下代码:

form_for ... do |f|
    f.label :field, :hint => "Field hint"
end

到目前为止,我已经创建了一个初始化程序来存储自定义功能,重新打开ActionView :: Helpers :: FormBuilder并更改标签方法,但是我不确定实际获得跨度的最佳方法是什么标签的文字。如果我尝试将文本直接放入,那么正确地使用rails,就会逃避内容。

我非常想使用现有的标签基础架构,因为它具有所有验证错误支持。这排除了使用content_tag并自己生成它(这可行,但似乎不正确)。

2 个答案:

答案 0 :(得分:3)

您应该创建自定义构建器并使用:builder参数将其传递给表单,而不是更改默认构建器。

class HintFormBuilder < ActionView::Helpers::FormBuilder
end

form_for @resource, :builder => HintFormBuilder do |f|
# ...
end

Hint构建器继承所有FormBuilder功能,包括验证,错误消息等。现在,您应该更改需要更改的内容以自定义行为。 这是一个非常原始的草案。

class HintFormBuilder < ActionView::Helpers::FormBuilder

  (%w(label)).each do |selector|
    src = <<-end_src
      def #{selector}(method, options = {})
        hint = options.delete(:hint)
        returning(super) do |element|
          # replace here the value of element with hint 
          # if hint != nil
          # remember to use gsub! and not gsub
        end
      end
    end_src
    class_eval src, __FILE__, __LINE__
  end

end

根据第一条评论编辑:

不要破解Rails内部结构总是一个好主意,因为您可能需要现在或将来使用依赖于原始行为的插件或功能。如果您不想在表单中手动附加构建器,则可以创建一个帮助程序。

def search_form_for(record_or_name_or_array,* args,&amp; proc)     options = {:builder =&gt; HintFormBuilder}

form_for(record_or_name_or_array, 
         *(args << options),
         &proc)

如果您想重新打开原始类,我建议创建一个新方法。此解决方案也适用于自定义帮助程序,并且具有您可以自定义它而不需要gsub的好处!响应。是的,gsub!这是常用的方法,因为在扩展原始方法时,您只能访问方法/选项和结果,没有值(由@object变量注入)。

class ActionView::Helpers::FormBuilder

  def label_with_hint(method, text = nil, options = {})
    hint = options.delete(:hint)
    # do your own customizations...
    @template.label(@object_name, method, text, objectify_options(options))
  end

end

编辑:我错了,您可以将自定义文字作为参数传递,这样您就不需要gsub了!返回的字符串。我对text_field标签感到困惑。 此时,您可以使用第一个(使用/不使用自定义方法的子类),第二个(黑客内部)或第三个选项(使用自定义方法的黑客内部),并在将文本值发送到@ template.label之前拦截文本值。 / p>

另请注意,文字可以为零。如果为nil,则从方法自动生成该值。你应该知道这一点。

答案 1 :(得分:1)

这就是我要做的。

# config/initializers/[anything].rb
ActionView::Base.default_form_builder = CustomFormBuilder

# lib/custom_form_builder.rb
class CustomFormBuilder < ActionView::Helpers::FormBuilder
  def label(field, text, options = {})
    if options[:hint]
      hint = @template.content_tag(:span, options[:hint], :class => "hint")
      super(field, "#{field.to_s.humanize} #{hint}", options)
    else
      super
    end
  end
end