Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different Ways to use simple_form in Ruby on Rails | What is the difference?

What is the difference between these methods of addressing an edit form for "packs"?

How do these different approaches affect the stability of the application? It's versatility?

Where would these run into major problems? Why is one better than the other?

  1. Via "method?" <%= simple_form_for Pack.find(params[:id]), method: :patch do |f| %>
  2. Via Object <%= simple_form_for @pack, url: pack_path(@pack), method: :patch do |f| %>
  3. Via Symbol <%= simple_form_for :pack, url: pack_path(@pack), method: :patch do |f| %>

Any information would be nice, I would love to know!

like image 863
Jake Avatar asked May 22 '18 16:05

Jake


People also ask

What is simple form rails?

Rails forms made easy. Simple Form aims to be as flexible as possible while helping you with powerful components to create your forms. The basic goal of Simple Form is to not touch your way of defining the layout, letting you find the better design for your eyes.


2 Answers

1. and 2. - Binding a form helper to a model instance

Are basically identical besides the fact that in 2. you're referencing a model instance from an instance variable instead of just passing the return value of a method call.

The end result is that you get a form that is bound to a model instance. This means that the value attributes of the inputs will contain the values from the model.

In fact all of these will give the same result:

<% 
  @pack = Pack.find(params[:id]) 
  pack = Pack.find(params[:id]) 

%>

<%= simple_form_for Pack.find(params[:id]), method: :patch do |f| %>
<%= simple_form_for @pack |f| %>
<%= simple_form_for pack |f| %>

But the first is less desirable since you should avoid doing queries directly from the view. The view should recieve data from the controler and use it to create HTML and be as simple and declarative as possible. Another major problem is that .find will raise ActiveRecord::RecordNotFoundError which should have been caught much earlier in the controller if the id is invalid.

3. Calling the form helpers with a symbol:

<%= simple_form_for :pack, url: pack_path(@pack), method: :patch do |f| %>

This creates a form that is "scoped" without necissarily being bound to an specific model instance. Take this example:

<%= simple_form_for :thing do  |f| %>
  <%= f.input :name %>
<% end %>

This generates the following HTML:

<form novalidate="novalidate" class="simple_form thing" action="/things/new" accept-charset="UTF-8" method="post">
  <input name="utf8" type="hidden" value="&#x2713;" /><input type="hidden" name="authenticity_token" value="F4r1gLuboZc1CKIdn9qac0sefxSVIvkjxk9KsD+sRl1wnVtEIKzHvWY0mPuLPvHI1Kcv3TIWD883YXHKXA+yJQ==" />
  <div class="input string required thing_name">
    <label class="string required" for="thing_name"><abbr title="required">*</abbr> Name</label>
    <input class="string required" type="text" name="thing[name]" id="thing_name" />
  </div>
</form>

Note name="thing[name]" which means it will give a params hash which is just like if we had a model instance:

{
   thing: {
     name: "foo"
   }
}

This is not as commonly used (at least not correctly) since most of the time you're manipulating model instances but it does have a use in special cases like search forms.

Note that Rails will try to resolve the local variable @thing but will not raise an error if it is nil. Using this form is therefore generally not advised as it can mask errors.

The best way to understand this behavior is to read the docs for ActionView::FormHelpers which SimpleForm is just sugar on top of.

like image 53
max Avatar answered Sep 30 '22 17:09

max


All three approaches yield the same form (assuming you're setting @pack to be Pack.find(params[:id]), however there are trade-offs:

  1. It's not advisable to have an ActiveRecord call in your view code. Views should just be responsible for laying out the form, not for querying the database. Maintaining this separation will make long-term maintenance much more straightforward. Using a variable also means you can have the same form for both the new and edit screens, by setting @pack = Pack.new in your controller for the new view. For these reasons, I'd advise against option [1].

  2. Using the object (@pack) or the symbol (:pack) yields the same results because internally the Rails form_for helper uses the symbol to look up the variable. IMHO option [2] and referencing the object directly is "better" because there's less magic going on, so it's easier for people new to the project (or you in a year's time) to understand. Option [2] is also consistent with the Rails docs and SimpleForm docs, so it's less of a surprise for people to see.

like image 35
spikeheap Avatar answered Sep 30 '22 15:09

spikeheap