Ruby-on-Rails: populate select box based off prior select - ruby-on-rails

I have a set of 3 collection_selects that I would like to filter the next select. Upon selecting an item in the first select box, it should limit the possible values of the second and third select boxes.
A similar data model would be as follows...
Tables, and fields
Lock
lock_id
brand_id
master_id
regular_id
Lock Brand
brand_id
Master Key
master_id
brand_id
Regular Key
regular_id
brand_id
So while filling in the form for adding a new Lock there would be select boxes for brand, master, and regular. Upon selecting a brand, it would then limit the master and regular keys to those that are only of the selected brand.
I've found a couple partial examples of how to do this, however none are complete. I'd appreciate a complete example of how to implement this.

All you need to do is bind the selects with an event listener that fires off an ajax request populating the other 2 partials containing the subsequent selects. i.e.
<%= form_for #thing, :remote => true do, :update => 'second_form' |f| %>
<%= hidden_field_tag 'form_partial', :value => 'form_2' %>
<%= select_tag :some_param, [[a,a],[b,b],[c,c]] :class => 'submittable' %>
<%= f.label :checked %>
<%= thing.name %>
<% end %>
<div id='second_form'>
</div>
<div id='third_form'>
</div>
class ThingController < ApplicationController
def update
checkboxes = some_logic_to_select_checkboxes from params[:some_params]
render :partial => params[:form_partial], :locals => {:select_menu => select_menu}
end
end
$('.submittable').live('change', function() {
$(this).parents('form:first').submit();
return false;
});
Your form partial should contain your forms populated with whatever selects you want enabled. Thought is was redundant to just repeat the form.

Related

pass multiple values using select_tag where only a single value is displayed Ruby on Rails form_tag

I have a hash called #records_hash which consists of 3 arrays: #records_hash["EVENT_DESCR"], #records_hash["EVENT_ID"], and #records_hash["PROCESSS_ID"]
I want the user to be able to select from a dropdown the event they would like to view and pass the corresponding values to the next page.
I want the user to see the EVENT_DESCR when they are using the dropdown, but I would like to pass the EVENT_ID and the PROCESS_ID to the next page.
Currently, I have a form that looks like this:
<%= form_tag({:controller => 'options', :action => 'sort', :type => 'event', :page => 1}, :method => 'get') do %>
<%= select_tag 'event_descr', options_for_select(#records_hash["EVENT_DESCR"]) %>
<%= submit_tag "Submit" %>
<% end %>
This form successfully lists out the EVENT_DESCR's in a dropdown format and sends the EVENT_DESCR to the next page.
How would I go about sending the EVENT_ID and the PROCESS_ID with it?
I think this is what you want:
# the values are whatever you want to pass. I'm just doing an array of arrays with EVENT_ID first.
<% values = #records_hash["EVENT_ID"].zip(#records_hash["PROCESSS_ID"]) %>
<% opts = options_for_select(#records_hash["EVENT_DESCR"].zip(values)) %>
<%= select_tag 'event_descr', opts %>
You can try out options_from_collection_for_select - you may need to modify your hashes to a collection of objects but this will make your code more readable. Probably a class XXEvent with id, descr and process_id as properties.

Display a blank form Rails

I'm newbie in Rails and I'm developing an app that needs to display a patients info in a form to be updated by a doctor if needed. As soon I can select a patient from a list from sidebar I want to display first just an empty form and when a patient is selected all the info will be displayed on it.
The only way I can guess to do it is to first display the form empty and then, once the patient is selected, catch the patient on the controller and reload the page to allow the form to get the patient info.
Does anybody has a better idea? On negative answer: how can I display an empty form?
Thanks in advance for your time.
Best regards.
Update: This is the form I'm trying to present on the page. #patient is an instance variable that once the page is displayed is not defined yet . It will be displayed once the doctor will select one patient from a list on the side.
<div class="row">
<div class="span6">
<%= render 'shared/error_messages' %>
<div>
<%= form_for(#patient) do |p| %>
<%= text_field_tag 'patient[name][]', nil, :placeholder => "name", :style =>height:12px;font-size:10px;" %>
<%= text_field_tag 'patient[name][]', nil, :placeholder => "surname", :style =>"height:12px;font-size:10px;" %>
<%= p.text_field :email, :placeholder => "email", :style => height:12px;font-size:10px;" %>
<%= p.text_field :phone, :placeholder => "phone", :style => height:12px;font-size:10px;" %>
<%= check_box_tag :active %>
<%= check_box_tag :sex, 'male' %>
<%= check_box_tag :sex, 'female' %>
<%= chack_box_tag :dao %>
<%= p.submit "Sumbit", class: "btn btn-small btn-primary pull-right", id: "boton" %>
<% end %>
</div>
</div>
</div>
An here is the problem. As #patient=nil on the controller since on is selected page crashes.
Thanks again.
What you are describing here are basic controller actions on your model:
Empty Form: #new action on Patients controller
Filled Form: #edit action on Patients controller
Edit: New Strategy to Accomplish Your Proposed UX
Component 1: Nav List of Existing Patients
Iterate over collection of patient objects, outputting a link for each patient to its edit view: link_to patient.name, edit_patient_path(patient)
This nav view will be a partial that you will include in the view templates for the PatientsController #new action and #edit action.
Component 2: Empty Form for Nonexistent/New Patient
In controller new action, instantiate a new Patient object, like so #patient = Patient.new.
Render the patient form on that #patient instance variable, as you do in the view code above.
Include the nav list of existing patients as a view partial.
Component 3: Filled Form for Existing Patient
In controller edit action, instantiate the Patient instance variable, like so #patient = Patient.find(params[:id]).
Render the patient form on that #patient instance variable, as you do in the view code above.
Include the nav list of existing patients as a view partial.
Edit: Old Points on Scaffolding
I would strongly suggest using rails generators and scaffolding to set up basic forms and view templates, at least as an educational pursuit. You will, via the command line, be able to automatically generate the proper controller actions and view templates you are describing above for #new and #edit.
Read this article: http://viget.com/extend/rails-3-generators-scaffolding
Then follow this tutorial: http://railscasts.com/episodes/216-generators-in-rails-3
As you become more comfortable with Rails development, generators and scaffolding will likely not satisfy you and needs for customization. They are, however, a great starting point.
See also: http://guides.rubyonrails.org/getting_started.html#getting-up-and-running
I think, one more option is you can Instantiate your object on your form itself:
<%= form_for(Patient.new) do |p| %>
Thanks

Populating jQuery Field Dynamically Depending on Rails Field

In my Rails (3.1) app, I have a shopping cart where I show the sales tax field and total on a page after the person enters their State.
It works correctly, except when there is an error and the person has already entered their State. In that case, the field value doesn't change (since the State field is populated already), so the jQuery (update_sales_tax) isn't triggered again.
Is there a way to render the view again (in case of errors) so the person doesn't need to fill out the entire form again, but have the sales tax calculated still? Or maybe a better approach to showing the user their sales tax on the page dynamically (since it's dependent on the State)?
In other words, my controller does this format.html {render :action => 'new'} if there is an error in Orders#new. It populates the fields in the form that the person already entered, however it doesn't recalculate the sales tax which is triggered onChange of the :state field via jQuery. How do I get this to recalculate if the view renders again and :state is already populated?
In the Orders#new view I have:
<%= form_for(#order, :method => :post) do |f| %>
<%= f.hidden_field :total_sales_tax, :value => #tax_amount %>
<%= f.fields_for :products_shipping do |shipping | %>
<%= shipping.select(:state , Order::STATES ,{:prompt => 'Select State'}, :id => "ship_state",:onchange => "update_sales_tax()") %>
<% end %>
<% end %>
<script>
function update_sales_tax(){
jQuery.ajax({
url: '/orders/order_update',
dataType: 'script',
type:'get',
data:'stateTo='+jQuery("#ship_state").val()
})
}
</script>
In orders/order_update.js.erb:
jQuery('#cart_details').html('<%= escape_javascript(render(:partial => #cart)) %>');
jQuery('#order_amount').val('<%= format("%.2f", #grand_total) %>');
jQuery('#order_total_shipping').val('<%= format("%.2f", #cart.total_shipping) %>');
jQuery('#order_total_sales_tax').val('<%= format("%.2f", #tax_amount) %>');
I figured it out, I just needed to add this line above the function:
window.onload = update_sales_tax();

How to set the elements selected in an autocomplete field

I have users pick genres from an autocomplete field. This field is in the edit view of the profile, so I have accepts_nested_attributes_for :genres in the Profile model. Also, Genre and Profile have a has_and_belongs_to_many association with one another. My question is how do you take the genres that the user picks and set them for that user's profile? What kind of controller code would I need? Would the code go in the profiles or genres controller?
I'm using this for autocomplete: http://loopj.com/jquery-tokeninput/ I've already prepopulated the genres table and hooked up the script to the text field. Right now when a user types, the autocomplete successfully displays suggestions. Now I want to update the database with the selected genres. This database is a join table between genres and profiles. How and where do I do this?
To sum up, I want to save the association between the profile id and the ids of the genres selected into the join table when I click the button in the profile edit view. Right now I get this error:
ActiveRecord::UnknownAttributeError in ProfilesController#update
unknown attribute: genre
Rails.root: /rubyprograms/dreamstill
app/controllers/profiles_controller.rb:18:in `update'
app/controllers/profiles_controller.rb:17:in `update'
Here's my profile edit view:
<%= form_for(:profile, #profile, :url => {:controller => "profiles", :action => "update"}, :html => { :multipart => true, :method => :put }) do |f| %>
...
<%= f.fields_for :genre do |g| %>
<div class="field">
<%= g.label :name, "Genres" %><br />
<%= g.text_field :name, :id => 'genre_field' %>
</div>
<% end %>
...
<div class="action">
<%= f.submit :profile, :value => "Update Profile" %>
</div>
<% end %>
Check this page http://loopj.com/jquery-tokeninput/demo.html
In this page clicking on submit alerts ids of the element, as per my understanding.
The script below in head does it
<script type="text/javascript">
$(document).ready(function() {
$("input[type=button]").click(function () {
alert("Would submit: " + $(this).siblings("input[type=text]").val());
});
});
</script>
This mat help you..
Basically there is an hidden text field which stores ids of the selected elements

Select the properties to an product, like size/color, without creating a model to handle them

I just picked up Agile Web Development with Rails 3rd Ed., and I'm going thru the Depot Application chapters, and I have a question about Product/Item options.
If I wanted to modify the product catalog and store so that products could have options (size, color, whatever), where/how would I do that?
Let's say I'm selling t-shirts, and they come in different sizes. I don't feel like that's something that really needs a model created to handle sizes, so I thought I could just add it as a select box in the html in the store's view.
But, each Add to Cart button is wrapped by a form tag that is automatically generated by button_to, and doesn't seem to give me the ability to pass additional parameters to my cart. How can I get the size of the item added into the POST to add_to_cart?
The helper in my view:
<%= button_to "Add to Cart" , :action => :add_to_cart, :id => product %>
The form that it generates:
<form method="post" action="/store/add_to_cart/3" class="button-to">
Ok, it's 2 days later, and I figured it out. This is what I had to do-
1, in my store view:
<% form_for #product, :url => {:action => "add_to_cart", :id => #product} do |f| %>
<select name="productsize" id="productsize">
<option value="L">L</option>
<option value="XL">XL</option>
</select>
<%= f.submit 'Add to Cart' %>
<% end %>
2, added to my store controller:
productsize = params[:productsize]
#cart.add_product(product, productsize)
Had to get productsize from params, and then pass it with the rest of the product model to the cart model's add_product action.
3, adjusted the cart model to accept the argument, and:
#items << CartItem.new(product, productsize)
Passed it along with the rest of the product model to create a new Cart Item and add it to items.
4, added to the cart_item model:
attr_reader :product, :quantity, :productsize
def initialize(product, productsize)
#product = product
#productsize = productsize
to read in productsize and initialize Cart Item.
5, added to my add_to_cart view:
Size: <%=h item.productsize %>
To display it for the user.
That's it. If there is an easier or DRYer way to go about it, I'm all ears (eyes?).
I'm not sure why you wouldn't store size, unless what you mean is that you'd store size as part of cart_item rather than product, which would be fine. In that case you'd do something like this:
<% form_for(#cart_item) do |f| %>
<%= f.select :size, ['S', 'M', 'L', 'XL', 'XXL'] %>
<%= f.hidden_field :product_id, :value => #product.id %>
# other properties...
<%= f.submit 'Add to Cart' %>
<% end %>
I'd drop the button_to helper and use a proper form, submitting the product properties to the add_to_cart action.
<% form_for(#product) do |f| %>
<%= f.select :size, ['S', 'M', 'L', 'XL', 'XXL'] %>
# other properties...
<%= f.submit 'Add to Cart' %>
<% end %>
You will need to add attributes to your model. For that, you will need to create a migration to update your database table. I only have the 2nd edition of the book, but there's a section called "Iteration A2: Add a missing column" that describes how to do this. I assume a similar section would be in the 3rd edition.
After doing that, you can follow Can Berk Güder's suggestion and replace the button by a form.

Resources