0
votes

I've upgraded simple_form from 2.1.0 to 3.0.3 (yes, still pretty old) and Rails from 3.2.22 to 4.2.10, and it seems like as a result, I've lost it setting for textarea elements associated with a text column a default of cols being 40, and rows being 20. Now it doesn't seem to set any values for cols and rows.

Is it possible to configure simple_form to set cols and rows for textarea for text application-wide? Or do I have to set something like

<%= f.input :message, input_html: {cols: 40, rows: 20} %>

for every input in the application?

I tried searching the simple_form github repo, and there's only three mentions of input_html in their wiki, none of which addressed this issue.

2
I think the only way from their documentation is to build a custom wrapper. Hope this helps!Kedarnag Mukanahallipatna

2 Answers

2
votes

Simple Form offers an easy way to change the default behaviour (v3.0.3) by redefining existing Simple Form inputs. This is done by creating a new class with the same name. For instance, if you want to set default rows and cols, you can do:

# app/inputs/text_input.rb
class TextInput < SimpleForm::Inputs::TextInput
  def input
    input_html_options[:cols] ||= 40
    input_html_options[:rows] ||= 20
    super
  end
end
1
votes

Problem:

In Rails 4.2, setting a global default value for textarea cols and rows:

TL;DR:

Because there seems to be no public-API from both SimpleForm 3.0 and Rails 4.2 to be able to set default textarea cols and rows values (see my Debugging below as to why), then I have come up with the following workarounds:

Workaround 1 (tested working):

create the following file:

# config/initializers/text_area_extensions.rb

module TextAreaExtensions
  def render
    @options[:cols] ||= 40
    @options[:rows] ||= 20
    super
  end
end

ActionView::Helpers::Tags::TextArea.class_eval do
  prepend TextAreaExtensions
end

... would render any textarea -- simpleform builder or rails form builder or text_area_tag -- to have default cols and rows like the following:

<textarea class="text" cols="40" rows="20"></textarea>

NOTE that this is a workaround of which is not a long-term robust solution, because this is only guaranteed to work to this specific version of ActionView::Helpers::Tags::TextArea class. Later Rails major or even minor versions might not work!

Workaround 2:

Instead of "patching" ActionView::Helpers::Tags::TextArea above, you can also patch SimpleForm::Inputs::TextInput if you only want to set default cols and rows for SimpleForm forms but do not set default for Rails forms, but because I prefer Workaround 1 above and my answer is too lengthy already, so I skip. But if anyone interested to know, let me know, and I'll update this.

Workaround 3:

Probably a better approach is to use custom method that you can call (i.e. a view helper method), that will have the default cols and rows already, instead of "patching" the gem code like Workaround 1 above. However, I was under the impression that you have a big application already that you'd want to just simply set a global code, instead of manually setting/updating all affected view files (which you even said above), and thus my Workaround 1 above.

Debugging:

I traced the code of execution:

  • SimpleForm "text" input:

    module SimpleForm
      module Inputs
        class TextInput < Base
          enable :placeholder, :maxlength
    
          def input
            @builder.text_area(attribute_name, input_html_options)
          end
        end
      end
    end
    
  • ... which do not suggest a public API in SimpleForm to set global-default cols and rows, and so following input_html_options:

    # ...
    @input_html_options = html_options_for(:input, input_html_classes).tap do |o|
      o[:readonly]  = true if has_readonly?
      o[:disabled]  = true if has_disabled?
      o[:autofocus] = true if has_autofocus?
    end
    # ...
    
  • ... also do not suggest a public API in SimpleForm for setting global cols and rows. And so following Rails' @builder.text_area (see code above), which led me here:

    def text_area(object_name, method, options = {})
      Tags::TextArea.new(object_name, method, self, options).render
    end
    
  • of which which led me here: for TextArea.new

    def initialize(object_name, method_name, template_object, options = {})
      @object_name, @method_name = object_name.to_s.dup, method_name.to_s.dup
      @template_object = template_object
    
      @object_name.sub!(/\[\]$/,"") || @object_name.sub!(/\[\]\]$/,"]")
      @object = retrieve_object(options.delete(:object))
      @options = options
      @auto_index = retrieve_autoindex(Regexp.last_match.pre_match) if Regexp.last_match
    end
    
  • ... which also has no public API to set global cols and rows, and so following next here: for TextArea.new.render

    def render
      options = @options.stringify_keys
      add_default_name_and_id(options)
    
      if size = options.delete("size")
        options["cols"], options["rows"] = size.split("x") if size.respond_to?(:split)
      end
    
      content_tag("textarea", options.delete("value") { value_before_type_cast(object) }, options)
    end
    
  • ... which also do not have a public API to set global cols and rows, which left me no choice but to "patch" the code using the workaround 1 above.

Trivia:

  • I verified that you are right when you said that Rails 4 no longer sets default cols and rows values for textarea, because seems like DEFAULT_TEXT_AREA_OPTIONS = { "cols" => 40, "rows" => 20 } is only implemented until Rails version 3.2.13 as you can see here