Here's a question I've been meaning to ask for a long time, but have just accepted it as "Rails magic" up to this point. As the title states, why does the Rails form helper look like a do loop? If you check the official Rails documentation, it doesn't seem to explain this, it just jumps right in by giving the below as a basic example:
<%= form_tag do %>
Form contents
<% end %>
So what's going on here exactly? Why does the form appear to be creating a loop as opposed to input forms in other languages that do not have said loop.
<%= form_for #person, url: {action: "create"} do |person_form| %>
<%= person_form.text_field :name %>
<%= fields_for #person.contact_detail do |contact_details_form| %>
<%= contact_details_form.text_field :phone_number %>
<% end %>
<% end %>
That's not "Rails magic", that's completely vanilla Ruby syntax. do/end denote a block in Ruby, not a loop.
Rails' documentation doesn't explain this, because Rails' documentation assumes a knowledge of Ruby. Rails does not introduce any new syntax (nor can it), it's just a framework, written in 100% plain old Ruby.
Because it takes a block argument.
It doesn't have anything to do with looping, e.g., File#open also takes a block.
#open yields the opened file. The form_for helper yields the helper.
Related
I have a form in Rails which uses fields_for to accept nested attributes:
<%= form_with(model: #combat_tracker, url: form_url) do |f| %>
…
<%= f.fields_for :zones do |zone| %>
<div class="zone-field">
<%= zone.text_field :name %>
<%= zone.check_box :_destroy %>
<%= zone.label :_destroy, "Remove zone" %>
</div>
<% end %>
…
<% end %>
Currently this gives me input fields for any existing zones on #combat_tracker. I want to add a button that will dynamically add a new zone-fields div for a new zone to be added when the form is submitted.
I’m using Rails 7 and assume the solution will involve the use of Turbo or possibly Stimulus, but can’t quite figure out the best way to do this. Thanks.
I don't think you need Turbo or Stimulus. Take a look at cocoon gem, it should do exactly what you're looking for.
Explaining all process here is quite complex for me, but try to follow this guide if the gem's one is too long.
Noob question! :)
I have a form, that has basically no point other than call some_action. The reason I use a form for this, is because we have a specific styling for this in our large website.
<%= styled_form_for(#user, :url => some_action_user_path #user)) do |f| %>
<%= f.save_button %>
<% end %>
I thought, since it's a form, I should be able to put a checkbox in there. It should have no other goal than confirming the user wants to do this action indeed. E.g. "Yes, I want to do some_action to the user model".
How would I make a checkbox that does not really change any attribute or affect anything - Other than that it should be checked for the form to submit?
This is probably dead simple, but according to the documentation and various error messages I should provide arguments such an attribute (which I don't want...)
form_for is meant to work on attributes of a model, which is what all the documentation you are reading is telling you. So if your model had a boolean column you could easily attach a check box to it.
If you ever want a form (or specific tag) that does not follow this, you can use the _tag version of these methods. For example, form_tag or, in your particular case, check_box_tag.
Example:
<%= styled_form_for(#user, :url => some_action_user_path #user)) do |f| %>
<%= check_box_tag "do_some_method" %>
<%= f.save_button %>
<% end %>
NOTE: You will only get a param entry for :do_some_method if it is checked off. If you want to get a param regardless, you have to add a hidden_field_tag before it.
<%= hidden_field_tag "do_some_method", "no_dont_do_it" %>
<%= check_box_tag "do_some_method", "yes_do_it" %>
Now if the checkbox is selected you'll get params[:do_some_method] set to "yes_do_it"; if it's not checked off, instead of getting no entry, you'll get params[:do_some_method] set to "no_dont_do_it".
I am very new to rails and having a bit of a problem with a simple page I am putting together for learning and I was hoping someone might have some suggestions on a fix or a better approach.
Essentially, I have the concept of a scratch pad. Each pad has_many tasks and has_many notes. In the pad's show, I want to have two independent forms. One for adding tasks and one for adding notes. The problem is, I build the forms like so:
<%= form_for([#pad, #pad.tasks.build]) do |f| %>
<%= f.text_field :text %> <%= f.submit %>
<% end %>
Now, since I've called .build, when I later call the below code to render the tasks it always renders an additional, empty record in the list.
<ul>
<%= render #pad.tasks %>
</ul>
I thought about using a nested form, but this seems to require me to use PadsController::Update rather than TasksController:Create like I want to.
What would be the appropriate approach in this situation? Being so new to rails (started yesterday), I'm afraid I'm missing something obvious.
Edit: I added the source to a github repository. As I said, this is just a learning project for me. https://github.com/douglinley/scratchpad
If you simply want a new task without it being added to #pad.tasks collection, I believe you can just do #pad.tasks.new instead of #pad.tasks.build (which does add it to the collection).
For more on build vs new, check out
Build vs new in Rails 3
So, this was much easier than I thought. Instead of calling new on the collection, I just created a new object for the form. Example below:
<%= form_for([#pad, Task.new]) do |f| %>
<%= f.text_field :text %> <%= f.submit %>
<% end %>
I've created a contact form using form_tag and other simple non-model-related rails form helpers. The form just submits an email to the site administrator. Anyway, I'd like to validate the fields on the form, but I'm having trouble finding a Rails-friendly way of doing this.
I found this answer to what seems to be the same question, however the accepted answer didn't seem to present a clear solution for Rails 3 (it seemed more oriented toward Rails 2). Could someone provide a concise example of how to easily do client-side validation of a form not related to a model in Rails 3? Extra points for a strategy that utilizes the default Rails validators.
And let's pretend my form looks something like this:
<%= form_tag "/contact" do %>
<%= text_field_tag :name %>
<%= text_field_tag :email %>
<%= text_area_tag :message %>
<%= submit_tag "Submit" %>
<% end %>
Give active_attr a try. Here's a short audio description.
I personally haven't tried it yet, but was thinking I will in the near future.
Also, in Rails 4, you'll kind of have the same functionality of the gem included: http://blog.plataformatec.com.br/2012/03/barebone-models-to-use-with-actionpack-in-rails-4-0/. And audio description :-).
I have been using Django for about a year and thought I would try Ruby on Rails to see how it compares. In Django, you can create a ModelForm that automatically generates a html for based on the types of fields in your model. Is there a class that does something similar in Rails? I know scaffolding will generate a erb file for my model, but is there a way to do this?
<%= auto_form_for #person %>
Or this?
<%= form_for #person do |f| %>
<% for each #person.fields do | field| %>
<%= auto_field f, field %>
<%end%>
<% end %>
I apologize for my poor ruby code.
Formtastic implements the Django pony magic you're looking for, and most variants thereof that might actually be useful. In my opinion, most end-user apps don't find "auto forms" and scaffolds to be very useful (since they so often need to be customized in detail), but Formtastic may output enough semantic HTML for you to style in a way that works for your users.
Rails also allows you to write your own custom form builders; you can also extend the ones Formtastic provide.
I found a gem called simple_form that is similar to formtastic. It allows you to to define forms like this:
<%= simple_form_for #user do |f| %>
<%= f.input :username %>
<%= f.input :password %>
<%= f.button :submit %>
<% end %>
I've used it for a few projects, and it's worked out great. It also has integration with twitter bootstrap, if you are using that library.