collection_select does not display dropdown, does any errors - ruby-on-rails

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.

Related

Wrong controller action invoked?

Rails 3.2
This is my second attempt at solving this problem.
I inherited an application for processing customer tickets. The main ticket view, is large and complicated, so it's split up into multiple sections.
I am trying to add a new section to enter customers information.
I have a scaffolding for CustomerInfo, with a controller and a model, in the normal locations:
controllers/customer_infos_controller.rb and models/customer_info.rb.
I put the views under views/tickets/sections
In my views/tickets/show.html.slim, I have:
- #customer_info = customer_info #ticket
h4.form-header Customer Information
.form-section.attachments
- if #customer_info.nil?
= render partial: 'tickets/sections/customer_info', locals: {ticket: #ticket }
In my , views/tickets/sections/_customer_info.html.slim, I have:
= form_for(CustomerInfo.new, url: customer_info_path) do |f|
- f.hidden_field :ticket_id, :value => ticket.id
.form-horizontal-column.customer-info
.form-group
= f.label :first
= f.text_field :first, maxlength: 50
.form-group
= f.label :last
= f.text_field :last, maxlength: 50
.actions = f.submit 'Save'
.clear
In my routes.rb, I have:
post '/customer_infos' => 'customer_infos#create', as: 'customer_info'
When I run the application, the form displays properly. But, when I enter the first name, and last name, the ticket gets updated.
Looking at the log file, I see that when the Save button in the Customer Information section, I see:
Processing by TicketsController#update as HTML
In the log, I also saw the params:
{
"ticket":
{
.......................
},
"customer_info":
{
"first":"John",
"last":"Doe"
},
"commit":"Save"
}
rake routes gives me:
customer_info POST /customer_infos(.:format) customer_infos#create
This is the HTML:
<div class="form-horizontal-column customer-info">
<div class="form-group">
<label for="customer_info_first">First *</label>
<input id="customer_info_first" type="text" size="50" name="customer_info[first]" maxlength="50">
</div>
<div class="form-group">
<label for="customer_info_last">Post tax total *</label>
<input id="customer_info_last" type="text" size="50" name="customer_info[last]" maxlength="50">
</div>
<div class="actions">
<input type="submit" value="Save" name="commit">
</div>
</div>
This is the portion:
<form accept-charset="UTF-8" action="http://xxx.xxxx.xxxx.com/admin/tickets/159384" class="form form-horizontal tickets-form context-form" data-admin="true" enctype="multipart/form-data" id="edit_ticket_159384" method="post">
So, there is no customer_info portion, with the proper action and method.
Why is the tickets controller update method is invoked, instead of the CustomerInfo create method? I also don't see the ticket_id param in the params.

Simple_form bootstrap style inline-form not working properly

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.

Using check boxes with a has_many relationship

I have an invoice with some lines. A line can only belong to one invoice. This is how my schema looks like:
create_table "invoices" do |t|
end
create_table "lines" do |t|
t.integer "invoice_id"
end
And my models:
class Invoice < ActiveRecord::Base
has_many :lines
end
class Line < ActiveRecord::Base
belongs_to :invoice
end
Now, when creating (or editing) an invoice I would like to show a list with all possible lines (the lines already exist in the database) and have a check box for each line to link it with the invoice.
I had a look at the HABTM problem but I don't think that's what I need here, the problem isn't as complex. I think the problem is me wanting to update the Unit#invoice_id while I am working on the invoice. Can I do this with a nested form or do I need a before_save callback here?
Thanks!
Have a look at Iain's answer. It's definitely the right way to go but... I prefer not to use simple_form or formtastic for this example to keep it as simple as possible.
I used Iain's HTML output to extract the HTML I need. This snippet is the same as Iain's answer without the need of an extra library:
<% Line.all.each do |line| %>
<%= hidden_field_tag "invoice[line_ids][]" %>
<%= check_box_tag "invoice[line_ids][]", line.id, #invoice.lines.include?(line), :id => "invoice_line_ids_#{line.id}" %>
<% end %>
PS: The Line.all and #invoice.lines... should be extracted to the controller and invoice model, they don't belong in the view. They are only used for brevity's sake.
A has_many association also adds the accessor line_ids, which you can create check boxes for.
If you're using simple_form or formtastic it's incredibly easy:
<%= f.input :line_ids, :as => :check_boxes %>
Which will create something like this:
<span>
<input name="invoice[line_ids][]" type="hidden" value="" />
<input checked="checked" class="check_boxes optional" id="invoice_line_ids_1" name="invoice[line_ids][]" type="checkbox" value="1" />
<label class="collection_check_boxes" for="invoice_line_ids_1">Line Name 1</label>
</span>
<span>
<input name="invoice[line_ids][]" type="hidden" value="" />
<input checked="checked" class="check_boxes optional" id="invoice_line_ids_2" name="invoice[line_ids][]" type="checkbox" value="2" />
<label class="collection_check_boxes" for="invoice_line_ids_2">Line Name 2</label>
</span>
And that is all there is to it. No nested forms or anything else needed.
I recommend using the collection_check_boxes helper method:
<%= collection_check_boxes :invoice, :lines, #lines, :id, :name %>
or Haml:
= collection_check_boxes :invoice, :lines, #lines, :id, :name

How to create a multi-edit form in rails

I need to create a multi-edit form in rails, like so:
<form>
<input type='text' name='input1'></input>
<input type='text' name='input2'></input>
<input type='text' name='input3'></input>
<input type='text' name='input4'></input>
<input type='text' name='input5'></input>
<br>
<input type='text' name='input1'></input>
<input type='text' name='input2'></input>
<input type='text' name='input3'></input>
<input type='text' name='input4'></input>
<input type='text' name='input5'></input>
<br>
<input type='text' name='input1'></input>
<input type='text' name='input2'></input>
<input type='text' name='input3'></input>
<input type='text' name='input4'></input>
<input type='text' name='input5'></input>
<br>
... and so on, then the "<submit>" button will be at the very end. One click of the submit button at the end should collect all the values and parse them in the controller.
I just need to know how to generate the multi-edit form in the view. Also, each row is unique; I'd also need to know how to assign a unique identifier to each of the input tags I guess; I do have a unique ID value I could use.
This is trivial to accomplish, but we need more information. How are these fields related to your models? Is this one model with many fields, many instances of a model or something else?
What you want to do in this situation is use a form builder. It will generate input fields according to a naming convention that will be parsed into a much more useful format when it gets to the controller. Since I have no information about your models, I will use a hypothetical example:
class Post < ActiveRecord::Base
attr_accessible :title, :body, :author, :published_at
end
Create the form using the form_for helper. It will give you a formbuilder object to create the input fields.
<% form_for :post do |f| -%>
<p>
<%= f.label :title %>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :body %>
<%= f.text_area :body %>
</p>
<p>
<%= f.label :author %>
<%= f.text_field :author %>
</p>
<p>
<%= f.label :published_at %>
<%= f.datetime_select :published_at %>
</p>
<% end -%>
The key benefit of using helpers is the name attribute of the inputs it generates. Since body belongs to a form for post it will be given the name attribute post[body]. These attributes will be parsed into the following hash:
:post => {
:title => "This is the title",
:body => "this is the body",
:author => "John Doe",
:published_at => "Mon Nov 15 2010 19:23:40 GMT-0600 (CST)"
}
This means you don't need to manually copy fields into a model. You can just pass it directly to the Model#new method:
#post = Post.new(params[:post])
and then do your validation checks. This convention becomes indispensable when you start nesting models inside one another.
See here for a more thorough guide to form helpers.

fieldWithErrors not wrapping every error field

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.

Resources