Form within a form with rails - ruby-on-rails

I've got a form for an order and with this, the user have to choose a category then associated product. As I want it to be dynamic, I wrote this :
_form.html.erb
<%= form_for(#order) do |f| %>
<%= f.collection_select :category_id, #categories_list, :id, :name, :prompt => "Selectionner" %>
<%= render :partial => 'products' %>
<%= f.submit 'Enregistrer', :class=>'button add'%>
<% end %>
_products.html.erb :
<%= form_for(Order.new, :remote => true) do |f| %>
<% if !#products.blank? %>
<%= f.label 'Produit :' %><br />
<%= f.select :product_id, #products.collect{ |s| [s.name,s.id]}, :prompt => "Selectionner" %>
<% else %>
<%= f.label 'Produit :' %><br />
<%= f.select :product_id, '' %>
<% end %>
<% end %>
in the controller :
def update_product_select
#products = Product.where(:category_id=>params[:id]).order(:name) unless params[:id].blank?
render :partial => "products", :layout => false, :locals => { :products => #products }
end
For the dynamic part, it works.
But when I click on the submit button, the product ID is not sent !
Can you tell me how is it possible for me to combine dynamic menu and form submitting please ?
Thanks.

I don't understand why you need two forms. Something is wrong here.
Explain a bit more on the workflow if possible.
I see you should either make use of fields_for if you are trying to edit other associated instances of #order.
For a dynamic menu, have a javascript event binding on the category that updates the products list based on the category. Let me know if you need an example.

I think you are looking for this: http://railscasts.com/episodes/88-dynamic-select-menus-revised
It needs a subscription, but you can also see the previous episode to get an idea if you dont want to subscribe.

Related

belongs_to association in nested form does not post data correctly

I am having some difficulty to figure out why the post data from the form is not posted correctly.
I have to models: Child and Parent
in the form of Child i am nesting a form of Parent in this way:
<%
parent = (child.parent) ? parent : Parent.new
%>
<%=f.fields_for :parent, parent do |builder| %>
<%= render 'parent_fields', :fp => builder %>
<% end %>
The parent_fields form is as follows:
<% #all_parents = Parent.all %>
<% parent = fp.object %>
<%= fp.fields_for :parent do |builder| %>
<%= builder.input :parent_id, :as => :select, :label => 'Parent: ', :required => false,
:collection => options_from_collection_for_select(#all_parents, "id", "name", parent.id), :include_blank => '- Select -' %>
<% end %>
The posted data hash shows as follows:
"parent_attributes"=>{"parent"=>{"parent_id"=>"6"}, "id"=>"36"}
where 36 is the old parent id and 6 is the new one.
When i do update_attributes it does not work which is normal because it would work if the hash would be like this way:
...
"parent_id" => 6
"parent_attributes"=>{"id"=>"36", ....}
...
I am working on a legacy code. It is also possible that data was modified by javascript. The purpose of this post is to make sure that the way I am writing the form is the right way because I am new to nested forms.
Thank you
There are two possibly scenarios you want to consider:
1. A child needs to select an existing parent it belongs to.
2. A child needs to create a brand new parent that it belongs to.
It appears that you want to do #1, select an existing parent. If so, you do not need fields_for. Fields for is for creating new relations.
I'll show you some example code from an application I'm working on about schools, where a student belongs_to a grade level.
app/views/students/_form.html.erb
<%= form_for #student do |student_form| %>
<%= student_form.text_field :first %>
<%= student_form.text_field :last %>
<%= student_form.collection_select :grade_level_id, GradeLevel.all, :id, :name %>
<%= student_form.submit "Save" %>
<% end %>
Now, using your models (Child and Parent):
app/views/children/_form.html.erb
<%= form_for #child do |form| %>
<%= form.text_field :child_name %>
<%= form.number_field :age %>
<%= form.collection_select :parent_id, Parent.all, :id, :name %>
<%= form.submit "Save" %>
<% end %>
Note that I just put Parent.all straight into the collection_select. Creating #all_parents above isn't necessary.
EDIT
If you want to create new parents every time...
app/views/children/_form.html.erb
<%= form_for #child do |form| %>
<%= form.text_field :child_name %>
<%= form.number_field :age %>
<% form.fields_for :parent, #child.parent do |parent_fields| %>
<%= parent_fields.text_field :parent_name %>
<%= form.submit "Save" %>
<% end %>

Can't get check box options to change depending on value of collection_select in a rails 3.2 form

I have a form in rails 3.2 for creating users in a company. Each company has sites. A site is assigned to a user via a collection_select, and then each site has a number of departments which are selected using check boxes. A user belongs to a site and can belong to many departments from that site.
I need the department check box options to change dependant on the selected value in the sites collection_select.
I have been trying to do this by using :onchange of the collection_select to call a partial containing the departments. I've managed to get this to work but only displaying all departments for the company. Not departments for each individual site. I don't understand how to pass the selected site to the partial so it can return the correct departments (if this is even possible).
My code so far is:
Form:
<%= form_for #user, :url => front_admin_users_path do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<%= f.collection_select :role, User::ROLES, :to_s, :humanize %>
<%= f.collection_select :site_id, current_user.company.sites.all, :id, :name, {}, :onchange => "jQuery.get('/load_department')", :remote => true %>
<div id="department_frame"></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.submit "Sign up" %></div>
<% end %>
users_controller.rb:
def load_department
respond_to do | format |
format.js {render :layout => false}
end
end
load_department.js.erb:
$("#department_frame").html( "<%=j render(:partial =>"department") %>" );
_department.html.erb:
<% current_user.company.sites.each do |site| %>
<% for department in site.departments %>
<%= check_box_tag "user[department_ids][]", department.id, current_user.department_ids.include?(department.id) %>
<%= department.name %>
<% end %>
I have googled for days trying to find the solution but can't find exactly what I need. The nearest thing I've found is Ryan Bate's dynamic collection selects revised using the grouped_collection_select method (which I've used in another part of the project), but this doesn't seem to deal with select boxes. Any help would be appreciated. Thanks.
You could try passing the site_id as a parameter in the URL to the AJAX call and then read that value off in the controller. In the controller method, you can also then get the list of departments for that particular site and then pass that off to the view that is being rendered.
I have edited the relevant parts of the code to explain what I mean better. Hopefully this makes sense :)
Form
<%= f.collection_select :site_id, current_user.company.sites.all, :id, :name, {}, :onchange => "jQuery.get('/load_department?site=' + $('#user_site_id').val())", :remote => true %>
users_controller.rb:
def load_department
site = params[:site]
#departments = Site.find(site).departments
respond_to do | format |
format.js {render :layout => false}
end
end
_department.html.erb:
<% for department in #departments %>
<%= check_box_tag "user[department_ids][]", department.id, current_user.department_ids.include?(department.id) %>
<%= department.name %>
<% end %>

select helper selected value and nested forms

I have a nested form, like:
<% form_for #invoice do |f| %>
<%= render :partial => "invoice_item_fields", :locals => {:f => f} %>
<% end %>
and _invoice_items_fields:
<% f.fields_for :invoice_items do |builder| %>
<%= link_to_remove_fields "remove", builder %>
<%= builder.collection_select(:product_id, Product.all, :id, :name) %>
<%= builder.text_field :quantity, :size => 4,%>
<% end %>
When i submit the form and it not pass the validations it render the new action again. The thing is the selected value for :product_id is no remembered, but the :quantity is ok.
I read that i should setup an instance variable in the controller with the value of the selected option and then do something like:
<%= builder.collection_select(:product_id, Product.all, :id, :name, :selected => #selected_product) %>
but the thing is the application could have many :invoice_items, so i don't know what to do for the select field "remember" the values.
Thanks.
Can you post your controller code? I'd like to see where you're setting the invoice & invoice_item fields and how you're processing the form. I recently built an invoice & line_item application and might have some ideas... [Sorry I can't comment, but haven't hit that permission level.]
I solved this on another post. The thing was that my product_id was and string and not and integer at db level.

Order confirmation page in rails

I've been trying to create an order confirmation page for my rails app, and am not quite sure how to go about it in a restful way.
There were a few answers on this question that got me halfway there, but the problem was that I wasn't quite sure how to set up the form in the rails view so that it would take the user to a confirmation page with all their details instead of a create action.
Right now my view is simple:
<% form_for :order do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :first_name %><br />
<%= f.text_field :first_name, :size => 15 %>
</p>
<p>
<%= f.label :last_name %><br />
<%= f.text_field :last_name, :size => 15 %>
</p>
(Be sure to enter your name as it appears on your card)
<p>
<%= f.label :card_type %><br />
<%= f.select :card_type, [["Visa", "visa"], ["MasterCard", "master"], ["Discover", "discover"], ["American Express", "american_express"]] %>
</p>
<p>
<%= f.label :card_number %><br />
<%= f.text_field :card_number %>
</p>
<p>
<%= f.label :card_verification, "Card Verification Value (CVV)" %><br />
<%= f.text_field :card_verification, :size => 3 %>
</p>
<p>
<%= f.label :card_expires_on %><br />
<%= f.date_select :card_expires_on, :discard_day => true, :start_year => Date.today.year, :end_year => (Date.today.year+10), :add_month_numbers => true %>
</p>
<p><%= f.submit "Submit" %></p>
What things should I be doing to direct the user to a confirmation page that shows all the order details?
Thanks!
Kenji
There were a few answers on this
question that got me halfway there,
but the problem was that I wasn't
quite sure how to set up the form in
the rails view so that it would take
the user to a confirmation page with
all their details instead of a create
action.
Directing a form to a non standard page is pretty simple.
Add a url option form_for.
Such that
<% form_for :order do |f| %>
becomes
<% form_for :order :url => {:action => "confirm"} do |f| %>
You'll need to crate the confirm action in your routes, but that only involves this:
map.resources :orders, :collection => {:confirm => :get}
All you need now is a basic controller action and a view:
def confirm
#order = Order.new(params[:order])
unless #order.valid?
render :action => :new
else
end
end
Your view should look almost identical to the show view, with the addition of a form submitting #order to the create action.
Why don't you pull the confirmation via ajax for example, pull the result and put it as an overlay div, upon confirmation submit the original values in the form.
If you still need to do it your way then check wizardly, it's exactly designed for such uses.
I would like to update the answer for more elegant Rails 4 or up.
I hope it will help newbies like me. Ruby is awesome! :)
routes.rb
resources :orders do
collection do
post 'confirm'
end
end
orders_controller.rb
def confirm
#order = Order.new(order_params) # GET THE POST parameters
render :new if #order.invalid? # Return if false
end
form.html.erb
<%= form_for #order, url: {action: 'confirm'} do |f| %>

Ruby on Rails: Drop down menu

I'm trying to create a drop down menu to allow a user to change an entry's field in my table. The user has one of three options -- hot, medium and cold.
I already have text_fields that do essentially the same thing for other fields, that all update when the user clicks on a submit_tag.
Is there an easy way to implement a drop-down box and have the result saved with the submit_tag ?
thanks,
-Chris
Here's the basic answer. The array of two element arrays is the critical part.
<% form_for #entry do |f| %>
<%= f.text_field :name %>
<%= f.select :temperature, [['Hot','hot'],['Medium','medium'],['Cold','cold']] %>
<%= f.submit %>
<% end %>
I'll assume 2 things:
That you are the <%= form_for #model_instance idiom (explained on section 2.2 of this guide).
That you want to store the "hot", "medium" and "cold" values as strings (not as numbers 1,2 and 3 or something similar) on your database.
Let's say that you have two fields, called :name and :temperature, controlled by two text_fields:
<% form_for #article do |f| %>
<%= f.text_field :name %>
<%= f.text_field :temperature %>
<%= f.submit "Create" %> <% end %>
<% end %>
Now you want to change the :temperature control to a dropdown list, accepting hot, medium and cold as values. Then you can do that this way:
<% form_for #article do |f| %>
<%= f.text_field :name %>
<%= f.collection_select :temperature, Article::TEMPERATURES, :to_s, :to_s,
:include_blank => true
%>
<%= f.submit "Create" %> <% end %>
<% end %>
You will now have to define the Article::TEMPERATURES constant in your Article model. It shouldn't be very difficult:
class Article < Activerecord::Base
TEMPERATURES = ['hot', 'medium', 'cold']
You may be wondering why I added the :include_blank part on the collection_select. This will add an "empty" option on your dropdown list. You will need that empty option when creating new objects, unless you want a "default" value to temperature.
http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#M001730
I was working on something similar. I got this to work by simply adding either an enum or a constant(similar to what kikito said previously) in my model and then calling the select in my form.
Here's how it can work.
using the constant:
class ClassName < ActiveRecord::Base
TEMPERATURES = ['Hot', 'Medium', 'Cold']
end
bin/rails g migration add_column_to_table temperatures:string
_form.html.erb
<%= f.label :temperature %>
<%= f.select :temperature, ClassName::TEMPERATURE %>
or
using the enum:
class ClassName < ActiveRecord::Base
enum temperature: [:hot, :medium, :cold]
end
bin/rails g migration add_column_to_table temperatures:integer
_form.html.erb
<%= f.label :temperature %>
<%= f.select :temperature, ClassName.temperatures.keys %>
Hope that helps you!
You might want to consider formtastic gem which is lot less code.
<% semantic_form_for #stuff do |f| %>
<% f.inputs do %>
<%= f.input :name %>
<%= f.input :temperature, :as => :select,
:label => "Degree", :include_blank => false,
:collection => [["Hot", 1], ["Medium", 2], ["Cold", 3]] %>
<% end %>
<%= f.buttons %>
<% end %>
In accordance with all of the above answers, remember to do this last, important step:
Restart your server!
As a newbie, I was wondering why my array was not working even though I followed all the steps correctly.

Resources