ruby 3.1.1, Rails 6.1.4
I am having problems with a rails form. I'm using 'form_for' with a couple of radio button form elements. The form submits, but values for the radio button elements come across as "0". I'm not sure what I'm doing wrong.
This part of my app is named spaced: root/living_muay_thai/
Migration:
class CreateLivingMuayThaiSummitSurveys < ActiveRecord::Migration[6.1]
def change
create_table :living_muay_thai_summit_surveys do |t|
t.string :question_1 # radio button
t.string :question_2 # radio button
t.text :question_3
t.text :question_4
t.text :question_5
t.timestamps
end
end
end
Controller
class LivingMuayThai::SummitSurveysController < ApplicationController
...
def new
#summit_survey = LivingMuayThai::SummitSurvey.new
end
def create
survey = LivingMuayThai::SummitSurvey.new(summit_survey_params)
if survey.save
flash[:notice]="Your survey has been submitted"
redirect_to(living_muay_thai_summit_surveys_thank_you_url)
else
flash[:notice]="Sorry, your survey could not be saved. Try Again?"
redirect_to( new_living_muay_thai_summit_survey_url)
end
end
...
def summit_survey_params
params.require(:living_muay_thai_summit_survey).permit(:question_1, :question_2, :question_3,:question_4, :question_5)
end
end
Form
<%= form_for(#summit_survey) do |f| %>
<div class="grid-x">
<div class="cell medium-12">
<label for="problem"><strong>
1) How likely are you to attend a future LMT Summit?
</strong></label>
</div>
</div>
<div class="grid-x">
<div class="medium-5">
<%= f.radio_button :question_1, 'One' %> <label>One</label><br />
<%= f.radio_button :question_1, 'Two' %> <label>Two</label><br />
<%= f.radio_button :question_1, 'Three' %> <label>Three</label><br />
<%= f.radio_button :question_1, 'Four' %> <label>Four</label><br />
<%= f.radio_button :question_1, 'Five' %> <label>Five</label>
</div>
When I view-source or Inspect the radio_button elements in the browser, it all seems correct:
<input type="radio" value="One" name="living_muay_thai_summit_survey[question_1]" id="living_muay_thai_summit_survey_question_1_one" /> <label>One</label><br />
<input type="radio" value="Two" name="living_muay_thai_summit_survey[question_1]" id="living_muay_thai_summit_survey_question_1_two" /> <label>Two</label><br />
<input type="radio" value="Three" name="living_muay_thai_summit_survey[question_1]" id="living_muay_thai_summit_survey_question_1_three" /> <label>Three</label><br />
<input type="radio" value="Four" name="living_muay_thai_summit_survey[question_1]" id="living_muay_thai_summit_survey_question_1_four" /> <label>Four</label><br />
<input type="radio" value="Five" name="living_muay_thai_summit_survey[question_1]" id="living_muay_thai_summit_survey_question_1_five" /> <label>Five</label>
When I submit a record, I get no errors. But when I view the record in the console, I see "0" and "0" for 'question_1' and 'question_2', not the "one" and "two" I entered.
s=LivingMuayThai::SummitSurvey.last
:010 > s
#<LivingMuayThai::SummitSurvey:0x00007f66b66a4c20
id: 7,
question_1: "0",
question_2: "0",
question_3: "test 3",
question_4: "test 4",
question_5: "test 5",
created_at: Mon, 17 Oct 2022 16:12:17.047229000 EDT -04:00,
updated_at: Mon, 17 Oct 2022 16:12:17.047229000 EDT -04:00>
Any ideas what I'm doing wrong? My "guess" is it is something in the radio_button code on the form, but as I noted, it seems to be correct.
I have this working. I rewrote the radio buttons on my form, from scratch, and viola! it started working. I compared the old and new code and cannot see what is different, but it works.
Shrugging my shoulders.
Thanks for looking!
Related
Consider these simple, Reminder & event models:
class Event < ActiveRecord::Base
has_many :reminders
end
class Reminder < ActiveRecord::Base
belongs_to :event
accepts_nested_attributes_for :event
end
now, I have build reminders/new.html.haml view in following way:
%h2 Reminders
= form_for(#reminder, html: {class: "form-horizontal"}) do |f|
= f.fields_for :event do |event|
= event.collection_select :id, Event.all, :id, :name
= f.text_field(:issue_date, class: "datepicker", data: {"date-format" =>"dd/mm/yyyy"}, 'date' => "#{Time.new.strftime("%d/%m/%Y")}")
= f.text_field(:renewal_date, label:"Due Date", class: "datepicker", data: {'date-format' => 'dd/mm/yyyy', 'date' => "#{Time.new.strftime("%d/%m/%Y")}"})
= f.submit
This view doesn't throw any errors & reminders minus the <options> tag.
View http://screencloud.net/img/screenshots/f990e124f356330a10839b00cd92f75a.png
What I want to do is to display Event.name in the <options>. So what am I missing here?
[Update]
Changed to form_for & it generates following html markup
<form method="post" id="new_reminder" class="form-horizontal" action="/reminders" accept-charset="UTF-8"><div style="margin:0;padding:0;display:inline"><input type="hidden" value="✓" name="utf8"><input type="hidden" value="Yu7Qj4SW+GAMXx9dEL/ohjsqryEkxUXXGy+SHpN97hc=" name="authenticity_token"></div>
<input type="text" size="30" name="reminder[issue_date]" id="reminder_issue_date" date="20/09/2012" data-date-format="dd/mm/yyyy" class="datepicker">
<input type="text" size="30" name="reminder[renewal_date]" label="Due Date" id="reminder_renewal_date" data-date="20/09/2012" data-date-format="dd/mm/yyyy" class="datepicker">
<input type="submit" value="Create Reminder" name="commit">
</form>
as you may notice <option> tag is missing for some reason.
Try this:
collection_select(:event, :id, Event.all, :id, :name)
I was doing it wrong, this solution doesn't require accepts_nested_attributes_for. removed it & problem solved.
I have a working twitter bootstrap install and simple form generates the following:
<form accept-charset="UTF-8" action="/find_map" class="simple_form form-inline" id="new_location" method="post" novalidate="novalidate"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="p5CSoidWaoGMfHY0/3ElWi0XJVg6Cqi9GqWRNlJLBQg=" /></div>
<div class="control-group string required"><div class="controls"><input class="string required" id="location_address" name="location[address]" placeholder="Address" size="50" type="text" /></div></div><input class="btn" name="commit" type="submit" value="Find!" />
</form>
Somehow the "Find!" button won't appear on the same line as the search box. Any ideas?
Thanks!
UPDATE:
Sorry I should have mentioned that all the markup is generated by simple_form based on the following:
<%= simple_form_for #location, :url => find_map_path, :html => { :class => 'form-inline' } do |f| %>
<%= f.input :address, :label => false, :placeholder => "Address" %>
<%= f.submit "Find!", :class => 'btn' %>
<% end %>
So, really, there seems to be an issue with the generated markup, even though I have run the bootstrap install for simple_form, etc.
The above image shows a straight html form
<form class="form-inline">
<input type="text" class="input-small" placeholder="Email">
<button type="submit" class="btn">Sign in</button>
</form>
...above the one generated by simple_form.
I think there are a couple issues here. One is the formatting, and the way simple_form adds a <div> around the input field. #Ron's suggestion of using input_field works for me with simple_form 2.0.1. My example is searching for name in a Contacts table. The following makes the text box and button appear side by side:
<%= simple_form_for :contact, :method => 'get',
:html => { :class => 'form-search' } do |f| %>
<%= f.input_field :search, :placeholder => "Name",
:class => "input-medium search-query" %>
<%= f.submit "Find!", :class => "btn" %>
<% end %>
The other issue is that it seems simple_form usually assumes you want to work with model and field names. The example above uses a :symbol instead of a #model as the first argument as suggested here. But that still generates an input field named contact[search] so you'd have to tell your controller how to deal with that.
I think in this case it may be simpler to not use simple_form and instead use something like the form near the beginning of Ryan Bates' Railscast #240, Search, Sort, Paginate with AJAX:
<%= form_tag contacts_path, :method => 'get', :class => "form-search" do %>
<%= text_field_tag :search, nil, :placeholder => "Name",
:class => "input-medium search-query" %>
<%= submit_tag "Find!", :name => nil, :class => "btn" %>
<% end %>
Now the field is just named "search" and I can consume it in my controller's #index method something like this:
#contacts = #contacts.search(params[:search])
assuming I have this in my model:
def self.search(search)
if search
where('lower(name) LIKE ?', "%#{search.downcase}%")
else
scoped
end
end
It's creating subforms because you're passing input to simple_form. Use input_field instead. (BTW, this also works with simple_fields_for).
You need to customize the control-group and controls div classes to display as inline-block when they are under a form-inline form:
form.form-inline div.control-group { display: inline-block; }
form.form-inline div.control-group div.controls { display: inline-block; }
Adding to Mark's reply:
So, input_field exists to create the input component only, it won't give you any sort of label/error/wrapper. That means you won't get any or tag wrapping the field, you should do that manually in case you want to.
Now about using the form with an object, SimpleForm is a FormBuilder, which means it was created to work with a namespace, either an object or a symbol. SimpleForm's simple_form_for == Rails' form_for, you always need an object namespace to work with.
For such a simple case as a search form, you're better off with simple form helpers such as form_tag, as you've pointed out. There's no need to rely on simple_form_for or form_for for that, I agree and I usually go down that path.
I hope that helps, let me know if you still have doubts.
Change the :html => { :class => 'form-inline' } to :html => { :class => 'form-horizontal' }
can't you move the input button next to input address? I think it will solve the problem
<form accept-charset="UTF-8" action="/find_map" class="simple_form form-inline" id="new_location" method="post" novalidate="novalidate">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden" value="p5CSoidWaoGMfHY0/3ElWi0XJVg6Cqi9GqWRNlJLBQg=" />
</div>
<div class="control-group string required">
<div class="controls">
<input class="string required" id="location_address" name="location[address]" placeholder="Address" size="50" type="text" />
<!-- move the button to here -->
<input class="btn" name="commit" type="submit" value="Find!" />
</div>
</div>
</form>
Please, all people with this problem, don't use fluid layout and be sure you are specifying the HTML5 doctype to the documents.
While registering for openstreetmap, on the terms page, I noticed that clicking the labels didn't check the radio buttons associated with them. Here is the html:
<!-- legale is GB -->
<form action="/user/terms" method="post">
<p>
Please select your country of residence:
<input id="legale_fr" name="legale"
onchange="Element.update("contributorTerms", "<img alt=\"Searching\" src=\"/images/searching.gif?1313181320\" />");; new Ajax.Request('/user/terms?legale=FR', {asynchronous:true, evalScripts:true})"
type="radio" value="FR" />
<label for="legale_FR">France</label>
<input id="legale_it" name="legale" ... type="radio" value="IT" />
<label for="legale_IT">Italy</label>
<input checked="checked"
id="legale_gb" name="legale" ... type="radio" value="GB" />
<label for="legale_GB">Rest of the world</label>
</p>
</form>
As you can see the checkbox id="legale_gb" doesn't match the label for="legale_GB".
Now openstreetmap's website is actually open source so we can read the terms.html.erb:
<!-- legale is <%= #legale %> -->
<% form_tag :action => 'terms' do %>
<p>
<%= t 'user.terms.legale_select' %>
<% [['france', 'FR'], ['italy', 'IT'], ['rest_of_world', 'GB']].each do |name,legale| %>
<%=
radio_button_tag 'legale', legale, #legale == legale,
:onchange => remote_function(
:before => update_page do |page|
page.replace_html 'contributorTerms', image_tag('searching.gif')
end,
:url => {:legale => legale}
)
%>
<%= label_tag "legale_#{legale}", t('user.terms.legale_names.' + name) %>
<% end %>
</p>
<% end %>
I'm a rails newbie, but I can't see anything there that lowercases the id of the radio button tag. What's more, even when I look at the source of radio_button_tag, sanitize_to_id I can't see where this is coming from.
Anyone got any idea what's causing this?
Edit Swapped out label for radio in my description according to answer from
2 things:
Wrong tag, the offender is radio_button_tag (it's capped as expected in the label).
Seems like you're linking to the wrong Rails. According to this project's environment.rb, it's using Rails 2.3.14. If you look at radio_button_tag for that release, you'll see the culprit.
# our pretty tag value is downcased on line 318
pretty_tag_value = value.to_s.gsub(/\s/, "_").gsub(/(?!-)\W/, "").downcase
# although the pretty name is not, oddly
pretty_name = name.to_s.gsub(/\[/, "_").gsub(/\]/, "")
# then the two are combined into the HTML id
html_options = { ..., "id" => "#{pretty_name}_#{pretty_tag_value}", ... }
I'm using fields_for in my form like so
<%= form_for #user %>
...
<%= f.fields_for :photos do |f2| %>
<%= f2.radio_button :public, 'true' %>
<% end %>
...
<% end %>
Here are the radio buttons it generates:
<input id="user_photos_attributes_0_public_true" name="user[photos_attributes][0][public]" type="radio" value="true" />
<input id="user_photos_attributes_0_id" name="user[photos_attributes][0][id]" type="hidden" value="1" />
<input id="user_photos_attributes_1_public_true" name="user[photos_attributes][1][public]" type="radio" value="true" />
<input id="user_photos_attributes_1_id" name="user[photos_attributes][1][id]" type="hidden" value="4" />
<input id="user_photos_attributes_2_public_true" name="user[photos_attributes][2][public]" type="radio" value="true" />
<input id="user_photos_attributes_2_id" name="user[photos_attributes][2][id]" type="hidden" value="5" />
...
I have this in user.rb
has_many :photos
accepts_nested_attributes_for :photos
When form is submitted I get this error:
Error during failsafe response: ActionView::Template::Error
TypeError (expected Hash (got Array) for param `photos_attributes'):
Does anyone know why this is happening?
Btw, I'm using Rails 3.0.0.rc2
How are you saving your model?
If you inspect the params hash, you will get something like:
{ :user => {:photo_attributes => [{:id => 1, :public => true}, {:id => 4, :public => false}] }, :your_other_params => ... }}
So a User.new(params[:user]).save should work. Unless you are passing each hash of attributes instead of the array. See this article if you need a more in-depth detail.
What is in your params hash? That'd help you to trace the problem.
BTW, if you want a "true/false" behavior (I assume that because of the is_public property), rather than "present/non-present", a checkbox should be used. Radio buttons are for mutually exclusive options.
I recently had the same problem. Instead of trying to get the params through the controller, we used the Chrome tools to see what was being passed in the params and found that we were passing an empty hash/array e.g. params[] versus params[:something]
Notice the following result when I submit blank :title and :description fields
Error div tags only wraps the title text field and not the description text area. http://www.freeimagehosting.net/uploads/c14b4a2d74.png
The validations are in the controller:
class Question < ActiveRecord::Base
validates_presence_of :title
validates_presence_of :description
And, the form is generated with those names:
-form_for(#question) do |f|
= f.error_messages
= f.label :title
= f.text_field :title, :size => 50, :onchange => remote_function(:url => {:action => :display_tag_suggestions}, :with => 'Form.Element.serialize(this)')
#suggestions
= f.label :description
= f.text_area :description
...
But, for some reason, only :title gets wrapped in the error div tags:
<form action="/questions" class="new_question" id="new_question" method="post">
<div style="margin:0;padding:0"><input name="authenticity_token" type="hidden" value="6HQaiu1D0gBQcKw2pLeZP6Jvn0FSClPD5Sk9HwegzPg=" /></div>
<div class="errorExplanation" id="errorExplanation">
<h2>2 errors prohibited this question from being saved</h2>
<p>There were problems with the following fields:</p>
<ul>
<li>Title can't be blank</li>
<li>Description can't be blank</li>
</ul>
</div>
<label for="question_title">Title</label>
<div class="fieldWithErrors"><input id="question_title" name="question[title]" onchange="new Ajax.Request('/questions/display_tag_suggestions', {asynchronous:true, evalScripts:true, parameters:Form.Element.serialize(this) + '&authenticity_token=' + encodeURIComponent('6HQaiu1D0gBQcKw2pLeZP6Jvn0FSClPD5Sk9HwegzPg=')})" size="50" type="text" value="" /></div>
<label for="question_description">Description</label>
<textarea cols="40" id="question_description" name="question[description]" rows="20"></textarea>
...
I don't think that behavior is expected. The problem most people have is that it's wrapping things with divs, which won't display properly. My problem is that fields aren't being wrapped with divs to begin with!
I haven't made any (conscious) changes to how errors are handled, so I'm not sure why it's not working properly.
What version of Haml are you using? Some older versions had compatibility trouble with error wrapping.