Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 5 - creating "Comments" for an "Article" with a has_many relationship between them

My questions is regarding section 6.4 of the official Rails guide

I have an articles and a comments model with a has_many relationship between them. Now, we edit the Article show template (app/views/articles/show.html.erb) to let us make a new comment for each Article:

<p>
  <strong>Title:</strong>
  <%= @article.title %>
</p>

<p>
  <strong>Text:</strong>
  <%= @article.text %>
</p>

<h2>Add a comment:</h2>
<%= form_with(model: [ @article, @article.comments.build ], local: true) do |form| %>
  <p>
    <%= form.label :commenter %><br>
    <%= form.text_field :commenter %>
  </p>
  <p>
    <%= form.label :body %><br>
    <%= form.text_area :body %>
  </p>
  <p>
    <%= form.submit %>
  </p>
<% end %>

<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>

Can someone ELI5 the form_with declaration ?

form_with(model: [ @article, @article.comments.build ], local: true)

I understand that each comment has to be created for a particular article and the description in the guide also mentions that the form_with call here uses an array but why do we need to pass an array to model: ? and why do we have two members in the array ? What if we just pass @article.comments to the model: ? What is the significance of the .build function call as compared to @article.comments.create call used in comments_controller.rb ?

like image 416
tac Avatar asked Mar 05 '23 15:03

tac


1 Answers

Rails generates the routes from form_with. Let's consider this case:

<%= form_with(@article) do |f| %>
 ...
<% end %>

when the article is new, and doesn't exists in database, Rails deduce that route would be:

articles_path(@article), action: :create

because you are creating a new one.

If article exists in database, Rails generates update route:

articles_path(@article), action: :update

Consequently, array means, that path will be nested. So, this code:

<%= form_with([@article, @article.comments.build]) do |f| %>
 ...
<% end %>

Generates this route, if the comment doesn't exist in database:

article_comments_path(@article, @article.comments.build), action: :create

Otherwise, route will be:

article_comments_path(@article, @comment), action: :update

More about difference between new and build: What is the difference between build and new on Rails?

More about comparison of form_for, form_with and form_tag https://m.patrikonrails.com/rails-5-1s-form-with-vs-old-form-helpers-3a5f72a8c78a

like image 112
barmic Avatar answered Apr 28 '23 18:04

barmic