How does rails know what :something is? - ruby-on-rails

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>

Related

Rail 4: Conditionals in a Scaffold

I am still learning RoR but I cant learn by following someone else's code. I have decided to implement by own app.
I have generated a scaffold and in the _form.html.erb I have this:
<div class="field">
<%= f.label :bath_accessories %><br>
<%= f.select :bath_accessories, options_for_select(["Shower", "Extractor Fan", "Lights", "Shaver", "Heat Rail"]) %><br>
</div>
When the user selects "Shower" from the above lists, I want to enable in view:
<div class="field">
<%= f.label :watts %><br>
<%= f.number_field :watts %>
</div>
I am lost where to put the if statement for: <%= f.select :bath_accessories, options_for_select(["Shower", "Extractor Fan", "Lights", "Shaver", "Heat Rail"]) %> But I did this and nothing shows:
<% if :bath_accessories[0] %>
# What to out put here with "<%= code %>?
Generated HTML Tag:
<form class="new_bathroom_accessory" id="new_bathroom_accessory" action="/bathroom_accessories" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓" /><input type="hidden" name="authenticity_token" value="r9M+Q7Np+/i68gwj65JSvV8wi4+4yb5d6tFWBHMw8k9nz1oRHGzh7AZHOTFvlaiS2lmqTch356vVYNlh7Urifw==" />
<div class="field">
<label for="bathroom_accessory_bath_accessories">Bath accessories</label><br>
<select name="bathroom_accessory[bath_accessories]" id="bathroom_accessory_bath_accessories"><option value="Shower">Shower</option>
<option value="Extractor Fan">Extractor Fan</option>
<option value="Lights">Lights</option>
<option value="Shaver">Shaver</option>
<option value="Heat Rail">Heat Rail</option></select><br>
</div>
<div class="field">
<label for="bathroom_accessory_watts">Watts</label><br>
<input type="number" name="bathroom_accessory[watts]" id="bathroom_accessory_watts" />
</div>
<div class="field">
<label for="bathroom_accessory_volts">Volts</label><br>
<input type="number" name="bathroom_accessory[volts]" id="bathroom_accessory_volts" />
</div>
<div class="actions">
<input type="submit" name="commit" value="Create Bathroom accessory" />
</div>
</form>
By adding an id to particular <div>,you can control that <div> as per user selection.
<div class="field" id="shower_id">
<%= f.label :watts %><br>
<%= f.number_field :watts %>
</div>
And you need JavaScript or JQuery code like this
$('#bathroom_accessory_bath_accessories').on('change',function(){
if( $(this).val()==="Shower"){
$("#shower_id").show()
}
else{
$("#shower_id").hide()
}
});
DEMO

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

How do you specify that you do not want the default <br> created after a form tag Ruby on Rails?

Right now when I create a form using a form_for Ruby on Rails creates an extra <br> tag after the form. Is there an option to not have RoR create this for me? Here is the code for creating the form:
<%= form_for(:user, :url => create_user_path) do |f| %>
<div class="field">
<%= f.label :email %>
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :password %>
<%= f.password_field :password %>
</div>
<div class="actions">
<%= f.submit "Submit" %>
</div>
<% end %>
Output:
<form method="post" action="http://localhost:3000/users" accept-charset="UTF-8"><div style="margin:0;padding:0;display:inline"><input type="hidden" value="✓" name="utf8"><input type="hidden" value="fsdfsdf+rgJKoc5sdQvsqvT2s=" name="authenticity_token"></div>
<div class="field">
<input type="text" size="30" name="user[password_clear]" id="user_password_clear" class="text_box">
</div>
<div class="field">
<input type="text" size="30" name="user[password]" id="user_password" class="text_box">
</div>
<div class="actions">
<input type="submit" value="Sign Up" name="commit" class="button button_medium button_green">
</div>
</form>
<br>
Thank you!
As long as you don't plan on creating a new form you could refrain from closing the form until you want a to appear, just don't add the <% end %> tag until you want a br and keep the following code inside the current form.
It's not very ellegant but it will probably work the way you want it to.

Where did the div class=fieldWithError go?

I have the following simple form:
<% form_for(#weight) do |f| %>
<%= f.error_messages %>
<%= f.label :weight %>:
<%= f.text_field :weight, :size => 5 %> kg.
<%= f.submit "Add weight" %>
<%= f.error_message_on :weight %>
<% end %>
which displays a form of only one field: weight.
Normally it renders like this:
<form action="/weights" class="new_weight" id="new_weight" method="post">
<div style="margin:0;padding:0;display:inline"><input name="authenticity_token" type="hidden" value="jYoVJkDnv4a1DMGnelJpGPElbH0XWKPNlESTt9GvzdA=" /></div>
<label for="weight_weight">Weight</label>:
<input id="weight_weight" name="weight[weight]" size="5" type="text" /> kg.
<input id="weight_submit" name="commit" type="submit" value="Add weight" />
</form>
which is fine. When I submit this form without setting any weight I get a validation error. f.error_messages and f.error_messages_on :weight correctly display the error messages, but the label and text field are not surrounded in a div with the class fieldWithError as I normally expect in forms in Rails. I instead get this:
<form action="/weights" class="new_weight" id="new_weight" method="post">
<div style="margin:0;padding:0;display:inline"><input name="authenticity_token" type="hidden" value="jYoVJkDnv4a1DMGnelJpGPElbH0XWKPNlESTt9GvzdA=" /></div>
<div class="errorExplanation" id="errorExplanation">
<h2>1 error prohibited this weight from being saved</h2>
<p>There were problems with the following fields:</p>
<ul><li>Weight can't be blank</li></ul>
</div>
<label for="weight_weight">Weight</label>:
<input id="weight_weight" name="weight[weight]" size="5" type="text" /> kg.
<input id="weight_submit" name="commit" type="submit" value="Add weight" />
<div class="formError">can't be blank</div>
</form>
For reference, what I've should have gotten is this:
<form action="/weights" class="new_weight" id="new_weight" method="post">
<div style="margin:0;padding:0;display:inline"><input name="authenticity_token" type="hidden" value="jYoVJkDnv4a1DMGnelJpGPElbH0XWKPNlESTt9GvzdA=" /></div>
<div class="errorExplanation" id="errorExplanation">
<h2>1 error prohibited this weight from being saved</h2>
<p>There were problems with the following fields:</p>
<ul><li>Weight can't be blank</li></ul>
</div>
<div class="fieldWithErrors"><label for="weight_weight">Weight</label></div>:
<div class="fieldWithErrors"><input id="weight_weight" name="weight[weight]" size="5" type="text" /></div> kg.
<input id="weight_submit" name="commit" type="submit" value="Add weight" />
<div class="formError">can't be blank</div>
</form>
Any ideas why I don't get those divs? I have formtastic installed and it's in use in other forms, but as far as I know that shouldn't interfere with this form.
Update: just to be sure, I printed out debug(#weight), it has the errors:
--- &id002 !ruby/object:Weight
attributes:
created_at:
updated_at:
weight:
measured_on: &id001 !timestamp
at: "2009-11-22 01:30:13.522589 +01:00"
"#marshal_with_utc_coercion": false
user_id: 1
attributes_cache:
measured_on: *id001
changed_attributes:
measured_on:
user_id:
errors: !ruby/object:ActiveRecord::Errors
base: *id002
errors:
weight:
- !ruby/object:ActiveRecord::Error
attribute: :weight
base: *id002
message: :blank
options: {}
type: :blank
new_record: true
Update: the model is
class Weight < ActiveRecord::Base
belongs_to :user
validates_presence_of :weight, :measured_on
attr_accessible :weight, :measured_on
def after_initialize
self.measured_on ||= Time.now
end
end
This is a bug in Formtastic. It was fixed but it seems that at this moment no released version of Formtastic has the fix.
My own bug report is on http://github.com/justinfrench/formtastic/issues/closed/#issue/132
The fix can be seen on http://github.com/grimen/formtastic/commit/2b81d9af385dadf8b37dc14f387afe3d43e4958a
Ultimately the problem was using justinfrench-formtastic from github, which is outdated and abandoned instead of formtastic from gemcutter.
You may need to enclose your label & field in a block tag like p or div.
<p>
<%= f.label :weight %>:
<%= f.text_field :weight, :size => 5 %> kg.
</p>
This way rails has a place to slip the error back into, else it falls back to the form as it is doing now.

Resources