DEV Community

RobL
RobL

Posted on • Updated on • Originally published at robl.me

Do We Really Need SimpleForm?

I’ve been using simple_form for as many years as I can remember. I love it’s simplicity. We’ve been adopting DRY since we all first adopted Rails back when we were less grey. So every time you see a form input like this it pains me.

<div>
  <%= form_for(User.new) do |f| %>
    <div class="field-group">
      <%= f.label :name, class: 'form-control' %>
      <%= f.text_field :name, class: 'form-input', placeholder: 'Name' %>
    </div>
    <div class="field-group">
      <%= f.label :role_ids, class: 'form-control' %>
      <%= f.select :role_ids, options_for_select([][1, 'One'],[2, 'Two']]), class: 'form-select' %>
    </div>
  <% end %>
</div>
Enter fullscreen mode Exit fullscreen mode

This example is a simple one, it doesn’t even cater for errors, placeholders, hints and even left / right alignment of inputs based on different situations.

I know we’re going to repeat this about 400 times in our application and if we want to upgrade from Bootstrap 4 to Bootstrap 5 or another CSS framework, or something custom we’re going to have to rewrite every form on the site which could take months and a developer out of circulation to do this. If you ever need an excuse not to do something. (Let’s not upgrade to Bootstrap 5 it will take a year and cost $1Billion). This is a big one.

SimpleForm offers the ability to reduce that code into one line per form group. It makes reasonable guesses about what kind of form element you want based on the data type of the Boolean is check_box, String is text, etc. However it’s customizable so you can determine on a per input basis what it should be.

<div>
  <%= form_for(User.new) do |f| %>
    <%= f.input :name, placeholder: 'Name' %>
    <%= f.select :role_ids, collection: [[1, 'One'],[2, 'Two']] %>
    <%= f.select :bio, as: :text %>
  <% end %>
</div>
Enter fullscreen mode Exit fullscreen mode

SimpleForm is ridiculously customisable and it caters for so many eventualities. Your form element could have 100 variations and SimpleForm’s not so simple config file will aid you to nail your form layouts. Trouble is your simple_form config can end up looking like this. Show that to your UX/UX peeps and they will stare blankly back at you and say things like WTF, or “you’re having a laugh” or worse “NO”.

config.wrappers :select, tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
    b.use :label, class: 'col-sm-7 col-md-6 col-lg-5 form-label'
    b.wrapper tag: 'div', class: 'col-sm-17 col-md-18 col-lg-19' do |ba|
      ba.use :input, class: 'form-control', error_class: 'is-invalid', data: { select: true }
      ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
    end
  end
Enter fullscreen mode Exit fullscreen mode

This kind of thing works if you’re a seasoned developer, and you can remember exactly what you did last week. But if you’re anything like me I jump from thing to thing and often don’t get a chance to take stock of everything before jumping into something else. But it occurred to me this morning that it’s not SimpleForm that I’m in love with it’s the simplicity I’m in love with and the implementation I can accept is pretty cool and I like to see elaborate things but I’m not particularly in love with the way it doesn’t allow everyone in the team to understand it without a week of poking it with a stick and in the end it’s a hinderance to development.

I can offer a different solution however, Rails has offered us a way to use custom FormBuilder and has since forever. It’s very nice to have a singing dancing solution, but a simple one will suffice. A simple solution needs to have some flexibility but it only needs to cater for the needs of our team not for every Ruby outfit on the planet.

We could easily just build our own solution but for the sake of our sanity make it compatible with SimpleForm arguments so we can just swap this in by changing simple_form_for with another_form_for.

class AnotherFormBuilder < ActionView::Helpers::FormBuilder
  def input(method, options = {})
    # delegate to a single method for each kind of form input based on type or options[:as]
  end

  def string
  end  

  def time_picker
  end

  def toggle_switch
  end
end

def another_form_for(name, &block)
  form_for(name, builder: AnotherFormBuilder, &block)
end
Enter fullscreen mode Exit fullscreen mode

Now that I’ve written this I’ve found this rather nice article after coming to this conclusion, it appears they are thinking along the same lines.

https://brandnewbox.com/notes/2021/03/form-builders-in-ruby/

Feeling slightly bad that the same week that I do a PR for SimpleForm then I’m off the mindset to move on.

Original Post on RobL.me

Top comments (2)

Collapse
 
lucianghinda profile image
Lucian Ghinda

Congrats for starting to post here more content about Ruby and Rails.

One short small advice if I may, you should use the canonical URL option instead of just writing directly in the body of the article where it was posted.

You can read here more about why use canonical URL

Here is where to find it:

Image description

You are welcome to hide this content :) as it is off-topic, but I was not sure where to write about this.

PS: I am not affiliated in any way with dev.to nor forem. I just care about Ruby and Rails content around the web and try to help creators where I can :)

Collapse
 
braindeaf profile image
RobL

Thank you that's really helpful Lucian, I am new to posting on I didn't see that option.

RobL