I am trying to implement something seemingly very simple, and I have been beating my head against it for days at this point.
My desired end result is a Country select drop-down, tied to a State select drop-down, in such a way that when a given country is selected, IF states are known THEN those states are displayed in a select drop down, and if NO states are known for that country, then a text field is displayed instead.
I feel like I am almost there. At this point the interface will actually generate that list of states based on the persons' country, except it is refusing to update the drop-down dynamically.
The portion of my view where country and state location is gathered looks like:
# _person_setup.html.erb
<td>
<%= f.label :country, 'Select your country' %>*<br />
<%= f.select :country, Carmen::country_names, {},
{:style => 'width: 200px',
:id => 'country_select',
:onchange => remote_function(
:url => {:action => 'update_states'},
:with => "'country='+value")} %>
</td><td>
<p>
<div id="states_div">
<%= render :partial => 'states',
:object => Carmen::states(
Carmen::country_code(
#person.country)),
:locals => {:form => f} %>
</div>
</p>
</td>
The partial being referenced in the DIV is as follows:
# _states.html.erb
<% unless states.nil? or states.empty? %>
<%= form.label :state, 'Select your state' %>*<br />
<%= form.select :state, states.collect{|s| [s[0], s[0]]} %>
<% else %>
<%= form.label :state, 'Please enter state or province' %>*<br />
<%= form.text_field :state %>
<% end %>
Finally, the controller code which is intended to update the list of states dynamically:
def update_states
puts "Attempting to update states..."
q = params[:country]
states = Carmen::states(Carmen::country_code(q))
puts "Country = #{q}, states = #{states.collect{|s| s[0]}.join(", ")}."
render :update do |page|
page.replace_html "states_div",
:partial => 'states',
:object => states,
:locals => {:form => form_for(#person)}
end
puts "OK"
end
Now, this code is being called at the proper time and generating the appropriate lists of states. For example, when the user clicks Australia, "Attempting to update states... Country = Australia, states = Australian Capital Territory, New South Wales, Northern Territory, Queensland, South Australia, Tasmania, Victoria, Western Australia" shows up in the server process. However it doesn't update the page, and won't print the "OK" at the end. In short the line which is failing is undoubtedly
page.replace_html "states_div",
:partial => 'states',
:object => states,
:locals => {:form => form_for(#person)}
Note that replacing this line with
page.replace_html 'states_div', "<b>is it working</b>"
properly replaces the div, but of course not with anything useful.
Can someone help me understand what is going on here?
It looks like you're assuming that the #person variable is still available from your original action. This could be set up by a filter for the current person but you don't show that in your question.
If you do need to lookup the #person again you'll have to pass the id through in your remote_function I think.
Ryan Bates has a Railscast that shows how to select a category for a product or create a new category by typing the name. It sounds like a similar scenario to what you have, so you might want to check it out: Create Model Through Text Field.
This took me a full day to figure out something that would at least "work". I am also using Carmen and also messing with the select tag in a form_for model form (actually, fields_for nested within forms_for...which adds additional complications).
I would think there is a better solution but this worked for me. The select needs to be referenced by the form but the options don't. Thus, first time through, I use the Carmen state_select method which populates the select tag correctly and all the nested options tags. The second time through, I just replace the options. Take a look:
In the view, I chose to use an observe_field method since I do other things besides update the states (some other localization changes) but this should work for remote_function and others, too:
<%= address_form.country_select :country, {:prompt => "--Select One--"} %>
Don't be confused by the id (user_address_attributes_country) it is just my silly forms_for/fields_for implementation)
<%= observe_field :user_address_attributes_country, :url => { :action => :changecountry }, :with => 'new_country' %>
<%= address_form.state_select :state, #user.address.country, {:prompt => "--Select One--"}, :style => 'width: 90px' %>
Then in my controller, it just looks like this:
def changecountry
c = params[:new_country]
respond_to do |format|
format.html
format.js {
render :update do |page|
page['user_address_attributes_state'].innerHTML = \
"<option>--Select One--</option>" + state_options_for_select(nil, c)
end
}
end
end
Note: state_options_for_select is also from Carmen. I could not get it to work unless I put it inside the respond_to block where I guess the view helpers are available. Also, I hard code user_address_attributes_state which is my nested id generated from the form_for/fields_for address_form.state_select rendering call in the view.
I hope this helps. If anyone can do it better, believe me, I'm all ears. I'll change the design in time...but needed something that just worked today and this was the best I could figure out in a limited time.
Related
I have my form_tag set up as follows:
<% Rating.find(:all, :conditions => ["recommendation_id = ? and rating_set = ? and product_id = ?", rec.id, params[:rating_set_id], params[:product_id]]).each do |rate| %>
<%= text_field_tag "recommendation_ratings[#{rec.id}][notes]", "#{rate.notes}", :id => "rec_note_text", :placeholder => 'Enter Notes..'%>
<% end %>
This works when the find conditions are met, however before the form is submitted, the recommendation_id is not persisted to the DB, so this find method does not return anything, and this causes my form tag not to render. It only render when all conditions of the find are met. How can I render my form regardless is the find condition is met?
You are using view/controller in a wrong way.
You should define new partial called _rating.html.erb
in there your form_tag (please replace with valid values, I have just put as an example)
<%= text_field_tag "recommendation_ratings[#{id}][notes]", "#{notes}", :id => "rec_note_text", :placeholder => 'Enter Notes..'%>
then, wherever you are rendering that list of Ratings, put for example in ratings/show.html.erb
<%= render #ratings%>
and in Ratings_controller you should put:
define show
#ratings = Ratings.find_all_with_conditions
end
and in model Rating.rb you should put:
define self.find_all_with_conditions
Rating..find(:all, :conditions => []) #put your logics here for finding all
end
I have just wrote just as an example how you should organize it, and I have not looked to put all valid parameters, I have put just for you to see how to organize you view.
I hope it will help.
Intro
I have an object #organization that has_many :quick_facts
Basically, I want to produce a _form for each :quick_fact but with one save button, that saves all of the quick_facts.
My two problems:
First Problem:
My quick_facts are not prepopulated with their information. They only appear as blank for each quick_fact I have.
Second Problem
A save button appears on every single form
My sad sad attempt :
- for quick_fact in #organization.quick_facts
- fields_for :quick_facts do |f|
= f.error_messages :header_message => FORM_ERROR_HEADER_MESSAGE, :message => FORM_ERROR_MESSAGE
= f.label :quick_fact, 'QuickFact'
%br/
= f.select :quick_fact, QUICK_FACTS, {}
%br/
= f.submit 'save', :class => 'button'
You really just want one form here, since you want to submit everything at once.
Here is what I would recommend:
Use a partial to render the label and the text option for the quick fact (if you want it to be text). You want this partial to be rendered once per quick fact, so use the :collection option on the render method to specify the collections of quick facts. Each partial will get its own local copy of whatever quickfact you are on, and a variable called quickfact_counter will also be created.
In addition, you will want to use the :locals option to pass the form to the partial as a local variable, so that you can do f.label, f.text_area
So, in conclusion, your new form will be something like this:
<% form_for #organization do |form| %>
<%= render :partial => "partial_name", :collection => #organization.quick_facts, :locals => {:form => form} %>
<%=form.submit 'save', :class => 'button'%>
<% end %>
Then your partial will just have
<%= form.label :quick_fact, 'QuickFact' %>
<%= form.text_field :quick_fact %>
If you wanted to get even fancier you could use a layout to render the form and have it defer to the partial, but this should be enough to get you started. Being able to pass a collection to a partial is one of my favorite Rails features.
I just started working on a Ruby On Rails project and i got to the point where i need to see the contacts of a company.
They should appear once the company is selected..
<p>
<%= f.label :empresa_id %><br />
<%= f.select(:empresa_id, #empresa.map {|e| [e.nombre, e.id]} )%>
</p>
<%= observe_field :empresa_id, :url=>{:action => "get_contactos",
:controller=> :contactos, :updatewith =>:empresa_id} %>
But nothing happens, i don't see even a error on the script/server.
Can someone point me in the right direction?
http://nealenssle.com/blog/2007/04/12/how-to-dynamically-update-form-elements-in-rails-using-ajax/
I see on the link that a guy did the exact same thing i need but did not post any info.
Cheers.
Kinda got this working.. here's my update..
This is the form were my select boxes are placed:
">
"contacto_id",
:with => "empresa_id", :url => { :controller => "contactos",
:action => "get_contactos" } %>
The function get_contactos on the contactos controller :
def get_contactos
#contacto = Contacto.find_all_by_empresa_id(params[:empresa_id])
render :layout => false
end
And the view get_contactos.rhtml (contactos):
">%>
I just need to bind the form to the correct fields and the job will be finished.
I couldn't get this to work by observing the field :empresa_id but "empresa_id" works..
Edit: Got it to work.
I just binded the field on the form to the proper ones on the model and now i have the data =)
">
"llamada_contacto_id",
:with => "empresa_id", :url => { :controller => "contactos",
:action => "get_contactos" } %>
I'm in need of a more complete example on how to update a select box based on the results of a second select box in Ruby on Rails. I asked about this already here. I've read through the feedback from that posting, but am not having any luck figuring this out, and I've been trying for hours. Anybody know of a better (and more complete) example?
This is generally handled in Javascript. I don't particularly enjoy coding Javascript, so what I do for this in my application is to use a form_observer (a Rails helper which uses the Prototype Javascript library to watch your form for input changes) and have update a DIV in the HTML containing the second select box, based on the results of an AJAX call. Since AJAX talks to my server, I can write arbitrarily complex logic in Ruby to render the new HTML.
Example code:
#goes in view
<%= Code to render the first list box. %>
<%= render :partial => 'second_list_box_partial', :locals => {:selected = insert_magic_here } %>
<%= observe_field(:first_list_box,
:url => { :action => :second_box_ajax }),
:frequency => 0.5,
:update => :second_list_box_div,
:with => %Q| 'value=' + $('first_list_box').value; |
%>
#goes in controller
def second_box_ajax
first_box_value = params[:value]
#magic goes here
#selected = #more magic
render :partial => 'second_list_box_partial', :locals => {:selected => #selected}, :layout => false
end
#goes in partial
<div id="second_list_box_div">
Actual code to render list box goes here.
</div>
I am still kind of fuzzy on controllers in rails, especially so because a lot of things seem to happen magically behind the scenes, and that's not happening in this case.
So say I have a person model, which has many photos (using paperclip) and has many favorite quotes. The quotes can have the text, the attributed author, etc. In both of those models, they are set as belonging to my person model.
Within a new person form, I used some code elsewhere to create a new photo:
<% form.fields_for :screenshots, :html => { :multipart => true } do |screen_form| %>
<%= render :partial => 'screenshot', :locals => { :form => screen_form } %>
<% end %>
The partial for that is very simple, like this (minus some ajax javascript stuff I put in for nested models):
<%= form.label :photo, "Screenshot:" %>
<%= form.file_field :photo %>
This all works fine and magically the ID of the person is associated with a screenshot upon creation in person_id. I don't even have a controller for screenshots and it still works.
However, it's not working for my quotes.
<% remote_form_for :quote, :html => { :method => :put }, :url => {:controller => "quote", :action => "create", :person_id => #person.id} do |quote_form| %>
<%= render :partial => 'quote', :locals => { :form => quote_form } %>
<% end %>
The partial for this is also very simple.
<%= form.label :quote_text %>
<%= form.text_field :quote_text %>
.........
<%= form.submit 'Create' %>
I am not really sure if I can put person ID in there, but it didn't complain. However it didn't work, either. The quotes controller is very simple.
def create
#quote = Quote.create(params[:quote])
end
Currently it gets put in the DB but person_id is not populated so I can't pull up the quotes associated with a particular person. Sorry if this is a silly question, but I'm kind of learning Rails by tweaking tutorials and mashing them together so bear with me :) It's just kind of mysterious how the photo thing works with NO controllers or special stuff and this doesn't.
The first form is a person form mainly that has snapshots fields associated to it, so looking at your HTML you will find something like person[snapshots][photo], this form will be submitted to person controller.
Passing person id to second form the is key to make it work, however it's a bit weird that it's not working, the form will submit to quote controller. Did you make sure(watch the log) that the params hash has person_id attribute?