Ruby on rails CSRF protection forms - ruby-on-rails

I understand that rails add CSRF tokens to the forms created with its custom functions like form_with etc. BUT does it also generate CSRF tokens (a.k.a authenticity_token in rails terms) for general HTML
I am seeing mixed answers for this. Anyone with hands-on experience on Rails help me here?

I figured I should make this into a full fledged answer.
No, manually creating a <form></form> in Rails will not automatically insert the authenticity token. The token is only inserted when using a Rails form helper. These helpers allow you to specify the fields for a form without specifying the authenticity token; it will put the token field into the form automatically. For example:
<%= form_for #person do |f| %>
<%= f.label :first_name %>:
<%= f.text_field :first_name %><br />
<%= f.label :last_name %>:
<%= f.text_field :last_name %><br />
<%= f.submit %>
<% end %>
Generates the following HTML with the hidden authenticity_token field:
<form action="/people" class="new_person" id="new_person" method="post">
<input name="authenticity_token" type="hidden" value="NrOp5bsjoLRuK8IW5+dQEYjKGUJDe7TQoZVvq95Wteg=" />
<label for="person_first_name">First name</label>:
<input id="person_first_name" name="person[first_name]" type="text" /><br />
<label for="person_last_name">Last name</label>:
<input id="person_last_name" name="person[last_name]" type="text" /><br />
<input name="commit" type="submit" value="Create Person" />
</form>
But if you manually generate the HTML, for example using HAML:
%html
%head
%body
%form
The generated HTML looks like:
<html>
<head></head>
<body>
<form></form>
</body>
</html>
...without any authenticity_token field.
In the article you linked to, it says "A typical form generated in Rails..." meaning generated using a Rails form helper. Manually created forms are not "generated" in the sense used in this context.

Related

Rails text_field_tag id attribute

I'm going through Michael Hartl's Rails tutorial. One of the exercises for chapter 8 is to rewrite the code using form_tag instead of form_for. After viewing the source that form_for was giving me and looking up each tag in the Rails documentation, I was able to successfully put it together.
My question is: How does Rails know what id attribute to give the <input> tag created by text_field_tag, so that it matches the id of the <label> tag created by the label_tag that precedes it?
Here's the code for the form:
<%= form_tag(sessions_path) do %>
<%= label_tag "session_email", "Email" %>
<%= text_field_tag "session[email]" %>
<%= label_tag "session_password", "Password" %>
<%= password_field_tag "session[password]" %>
<%= button_tag("Sign in", name: "commit", type: "submit") %>
<% end %>
Here's the resulting html:
<form accept-charset="UTF-8" action="/sessions" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="c9a5KJveRSOQyDo/ckUtpmQAbjw2f1alnB6Dn1lu3XU=" /></div>
<label for="session_email">Email</label>
<input id="session_email" name="session[email]" type="text" value="{:id=>"session_email"}" />
<label for="session_password">Password</label>
<input id="session_password" name="session[password]" type="password" value="{:id=>"session_password"}" />
<button name="commit" type="submit">Sign in</button>
Note that since Rails 5.1, the recommended form helper to use is form_with.
And form_with no longer automatically generates id's and class's for DOM elements any more like form_for and form_tag used to.
This has implications for adding markup like labels which used to link up to their corresponding input fields automatically. Now, for a label to properly pair up to an input field (with the for attribute) you need to explicitly add the id attribute to the input.
Example
ERB:
<%= form_with model: User.new do |f| %>
<%= f.label :name %>
<%= f.text_field :name, id: :user_name %>
<% end %>
which generates HTML:
<form action="/users" method="post">
<label for="user_name">Name</label>
<input id="user_name" type="text" name="user[name]">
</form>
See also
https://medium.com/#tinchorb/form-with-building-html-forms-in-rails-5-1-f30bd60ef52d, specifically the heading "No more auto-generated ids and classes".

Rails nested attributes array

I am having trouble creating multiple model objects using nested attributes. The form .erb I have:
<%= f.fields_for :comments do |c| %>
<%= c.text_field :text %>
<% end %>
is generating input fields that look like this:
<input type="text" name="ad[comments_attributes][0][text]" />
<input type="text" name="ad[comments_attributes][1][text]" />
<input type="text" name="ad[comments_attributes][2][text]" />
when what I really want is for it to look like this:
<input type="text" name="ad[comments_attributes][][text]" />
<input type="text" name="ad[comments_attributes][][text]" />
<input type="text" name="ad[comments_attributes][][text]" />
Using form helpers, how can I make the form create an array of hashes like I have in the second example, instead of a hash of hashes as it does in the first?
You could use text_field_tag for this particular type requirement.
This FormTagHelper provides a number of methods for creating form tags that doesn’t rely on an Active Record object assigned to the template like FormHelper does. Instead, you provide the names and values manually.
If you give them all the same name and append [] to the end as follows:
<%= text_field_tag "ad[comments_attributes][][text]" %>
<%= text_field_tag "ad[comments_attributes][][text]" %>
<%= text_field_tag "ad[comments_attributes][][text]" %>
You can access these from the controller:
comments_attributes = params[:ad][:comments_attributes] # this is an
array
The above field_tag html output look like this:
<input type="text" name="ad[comments_attributes][][text]" />
<input type="text" name="ad[comments_attributes][][text]" />
<input type="text" name="ad[comments_attributes][][text]" />
If you enter values between the square brackets, rails will view it as a hash:
<%= text_field_tag "ad[comments_attributes][1][text]" %>
<%= text_field_tag "ad[comments_attributes][2][text]" %>
<%= text_field_tag "ad[comments_attributes][3][text]" %>
would be interpreted by the controller as a hash with keys "1", "2" and "3".
I hope i understand correctly what you needed.
Thanks

Rails, label with nested HTML using FormBuilder and Devise, with Bootstrap markup

I am working on the front-end part of a Rails 3.1 application. We are using a Twitter Bootstrap as CSS Framework, Devise as the authentication manager and the I18n gem for localization.
This is the devise syntax for a checkbox with its label
<%= f.label :remember_me %>
<%= f.check_box :remember_me %>
And this of course is the generated HTML
<label for="user_remember_me">Ricordati di me</label>
<input name="user[remember_me]" type="hidden" value="0">
<input id="user_remember_me" name="user[remember_me]" type="checkbox" value="1">
Since Bootstrap adds this rule for the labels display: block, the label and the checkbox are not in the same line. To have the on the same line I need an HTML output like this
<label for="user_remember_me">
Ricordati di me
<input name="user[remember_me]" type="hidden" value="0">
<input id="user_remember_me" name="user[remember_me]" type="checkbox" value="1">
</label>
As shown in the forms markup documentation
You will have noticed that the label text is in Italian, the team member who provided localization for Devised worked hard to find out how to do so, and I do not want to force he to work on it again introducing new localized strings.
I am aware of the nice fact that the FormBuidler label method accepts a block as an argument so I could do
<% f.label :remeber_me do %>
<%= f.check_box :remember_me %>
<% end %>
But this produce an HTML output whitout the label! o.O
To be specific this is what I get:
<input name="user[remember_me]" type="hidden" value="0">
<input id="user_remember_me" name="user[remember_me]" type="checkbox" value="1">
I tried to look in the source code, the f.label method calls the label method, but I can only see that if there is a block no text will be printed and that the label and block will be rendered by the label_tag of the template_object.
Before diving into a source code digging, and a no sleep night, I decided to wait a moment and ask the lifesafer community of StackOverflow for help.
Am I missing something? I am calling f.label with block in the wrong way? Is some parameter missing?
Thanks!!
I don't know if you ever got this working...
Running on Rails 3.2.6 this is what I had to do:
<%= f.label :remember_me do %>
<%= f.check_box :remember_me %>
Remember Me?
<% end %>
I hope that helps you since I came here looking for an answer to the exact same problem and couldn't find it, except through trial and error.
If you want the label and checkbox on the same line, you must include .form-inline in your
<form class="form-inline">
<label for="user_remember_me">Ricordati di me</label>
<input name="user[remember_me]" type="hidden" value="0">
<input id="user_remember_me" name="user[remember_me]" type="checkbox" value="1">
</form>
http://jsfiddle.net/baptme/66TJY/
<%= form_tag( :class => "form-inline") %>

How does rails know what :something is?

I have the following code
form.label :artists
which outputs
<label for="artist_artist_name">Artist name</label>
How did rails find the strings artist_artist_name and Artist name?
In general, how can I track this kind of information down?
I have tried grep -ri artists * in the project root but there is no result (apart from form.label :artists). Same for Artist name...
The form helper is used as in the following snippet:
<%= form_for #person do |f| %>
<%= f.label :first_name %>:
<%= f.text_field :first_name %><br />
<%= f.label :last_name %>:
<%= f.text_field :last_name %><br />
<%= f.submit %>
<% end %>
What follows f.label or f.text_field is the identifier of a property for the object referred by #person.
The CSS ID you notice is simply obtained concatenating the name of the variable with an underscore, and the property name; the label is obtained replacing the underscores in the property with spaces, and rewriting the first word in capital case.
The code I reported would generate the following HTML (I removed the parts that were not important).
<form action="/people" class="new_person" id="new_person" method="post">
<label for="person_first_name">First name</label>:
<input id="person_first_name" name="person[first_name]" size="30" type="text" /><br />
<label for="person_last_name">Last name</label>:
<input id="person_last_name" name="person[last_name]" size="30" type="text" /><br />
<input name="commit" type="submit" value="Create Person" />
</form>

Why is simple_form not creating my fields and creating hidden fields instead?

This is my ruby code:
<%= simple_form_for([#video, #video.comments.new]) do |f| %>
<% f.association :comment_title %>
<% f.input :body %>
<% f.button :submit %>
<% end %>
This is the generated HTML markup:
<form accept-charset="UTF-8" action="/videos/485/comments" class="simple_form comment" id="new_comment" method="post">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="✓">
<input name="authenticity_token" type="hidden" value="55xSU8JUe1SgipjAkAEvCvidFdJY3hv8Qz5VBqUSrdE=">
</div>
<input class="button" id="comment_submit" name="commit" type="submit" value="Create Comment">
</form>
Obviously it's not creating the :body input field and the association select list correctly. Why is this and how can I fix it?
Btw, a video has many comments, and a comment belongs to video. Also, a comment_title has many comments, and a comment belongs to a video. Comment_title is generated with virtual attributes.
Please let me know if there is any other code you would like to see.
Both of these are because of choices in your rails application. The first is that you have selected to configure the application to use utf8 for character encoding. The second is because by default the application is setup to protect against cross site request forgery attacks. The authenticity token ensures that the response coming back to the server when the user submits the form is actually from you and not some other source just watching your traffic and posting away to mess with your database.
Ok so the problem was that I needed to add the "=" to <%= in my form elements.

Resources