【问题标题】:Creating customized label fields in forms在表单中创建自定义标签字段
【发布时间】:2009-06-21 23:45:18
【问题描述】:

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

<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 并自己生成它(这会起作用,但似乎……不对)。

【问题讨论】:

    标签: ruby-on-rails ruby forms


    【解决方案1】:

    您应该创建一个自定义构建器并使用 :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, &proc) options = { :builder => 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 标签感到困惑。 此时,您可以使用第一个(使用/不使用自定义方法的子类化)、第二个(hacking internals)或第三个选项(使用 custom method hacking internals)并在将文本值发送到@template.label 之前拦截它。

    还要注意 text 可以为 nil。如果为 nil,则从方法中自动生成该值。你应该意识到这一点。

    【讨论】:

    • 我真的不想指定我想在每个表单上使用的表单生成器。另外,我敢肯定在值中一定有比 gsub-ing 更好的方法...
    【解决方案2】:

    这就是我会做的。

    # 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
    

    【讨论】:

    • 我不知道您可以设置默认表单生成器,这是一个非常有用的功能。你试过这种方法吗?我认为它遇到了同样的问题,即超级方法 html 对文本进行编码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-02
    • 2021-06-12
    • 1970-01-01
    • 2012-02-29
    • 1970-01-01
    • 2017-08-20
    • 2012-11-20
    相关资源
    最近更新 更多