ruby-on-railsrails-activerecordparametersform-forform-helpers

how form_for works in Ruby on Rails


I am an newbie. I have read the API documentation. But still don't understand how form_for works.

Firstly, from Ruby on Rails Tutorial, the form for follow button:

<%= form_for(current_user.relationships.build(followed_id: @user.id)) do |f| %>
  <div><%= f.hidden_field :followed_id %></div>
  <%= f.submit "Follow", class: "btn btn-large btn-primary" %>
<% end %>

I understand current_user.relationships.build(followed_id: @user.id) means a new record. But why can we not just submit and trigger controller to save the record without hidden_field? Why do we still need to post followed_id to controller?

Secondly, in hidden_field, what does :followed_id means? I believe that is a symbol, i.e. it equals only "followed_id" not a variable of id. If that is only the name of the input field, then what is its value?

Thirdly, how does form_for know where the submission should be sent to? Which controller and action the form_for will post to?

Fourth, how does params work with form_for? In this follow button case, params[:relationship][:followed_id] will return @user.id in controller. How does it know the first hash attribute is :relationship? We have neither mentioned form_for :relationship nor form_for @relationship.

I know these questions can be very dumb, but I am really stuck. Any help will be appreciated.


Solution

  • I didnt do that tutorial so mind me if i dont answer directly to your question.

    Take a look at the rails guide about form helpers and it explains in details your questions, probably in a more articulate way than i can.

    form_for(path/to/your/controller/action) is a helper method to create HTML form elements with the url path to the POST or GET request. The helper knows if it should be a new record or an update record based on what you are asking to do in your controller action.

    For example In your controller

    def new
      @my_instance_variable = Myobject.new
    end
    

    In your view new.html.erb

    <%= form_for @my_instance_variable do |f| %>
    ...
    <% end %>
    

    In your case the logic was directly written in the helper and you could also directly write

    <%= form_for Myobject.new %>
    

    Both will result with the following html

    <form action="/myobjects/new" method="post">
    # in this case rails knows its a `POST` request because the route new action
    # is by default a POST request. You can check these routes and their request 
    # by using `rake routes` in terminal.
    

    Then the hidden_field is another helper to contain a value, in your case the @user.id that will be passed as parameter then saved as a Create or update action for the given object. The reason it doesnt add the value in the hidden field tag is because you already have a model association that knows the id of user since the link of form uses the build method with user id.

    Last part you need to understand the form_for link logic

    current_user.relationships 
    # implies the association of the current_user has many relationships 
    current_user.relationships.build 
    # .build is a method to populate a new object that can be save as a new record
    # means you will create a new relationship record by populating the user_id 
    # column with the current_user.id and the followed_id with the target @user.id