Skip to content

Instantly share code, notes, and snippets.

@gabriel-dehan
Last active May 17, 2018 16:13
Show Gist options
  • Save gabriel-dehan/d9f176d49efa6000f57d23d08cf9b70d to your computer and use it in GitHub Desktop.
Save gabriel-dehan/d9f176d49efa6000f57d23d08cf9b70d to your computer and use it in GitHub Desktop.
How does form_for works

Here are some explanations on "form_for" :

How does form_for works:

<%= form_for(@pet) do |f| %>
  ...
<% end %>

Will generate the following HTML:

<form class="new_pet" id="new_pet" action="/pets" method="post">
</form>

So form_for takes an object and from this object, infers if it should be an update or a create and sets the URL (action attribute in the form) to the right thing, same for the method. For instance for a create the url should be "/pets" and the method should be POST. For an update, the url should be "/pets/1" and the method should be PATCH.

How does form_for does that, here is what the code looks like ?

@pet = Pet.new


# The process is as follow:
@pet.class # => Pet
@pet.class.to_s # => "Pet"
@pet.class.to_s.downcase # => "pet"
@pet.class.to_s.downcase.pluralize # => "pets"

# Therefore the code is:
if @pet.id == nil # Then it is a create
    url = "/" + @pet.class.to_s.downcase.pluralize 
    # => /pets
    method = "POST"
else # Then this is an update
    url = "/" + @pet.class.to_s.downcase.pluralize + "/" + @pet.id
    # => /pets/1
    method = "PATCH"
end

Et Voila.

Same goes for a nested form even though it is a bit more complex: Provided that:

@restaurant = Restaurant.find(params[:restaurant_id])
@review = Review.new
<%= form_for([@restaurant, @review]) do |f| %>
  ...
<% end %>

Will generate the following HTML:

<form class="new_restaurant_review" id="new_restaurant_review" action="/restaurants/1/reviews" method="post">
</form>

How does form_for does that ?

@restaurant = Restaurant.find(params[:restaurant_id])
@review = Review.new

# The process is as follow:
@restaurant.class # => Restaurant
@restaurant.class.to_s # => "Restaurant"
@restaurant.class.to_s.downcase # => "restaurant"
@restaurant.class.to_s.downcase.pluralize # => "restaurants"

# The process is as follow:
@review.class # => Review
@review.class.to_s # => "Review"
@review.class.to_s.downcase # => "review"
@review.class.to_s.downcase.pluralize # => "reviews"

# Then the url is pretty much generated like that:
"#{@restaurant.class.to_s.downcase.pluralize}/#{@restaurant.id}/#{@review.class.to_s.downcase.pluralize}"

# And this gives you: /restaurants/1/reviews
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment