views:

827

answers:

4

My app has a select box for users to choose a "venue". This select box is, as you would expect, in a form. I also have an action somewhere on the page that creates a new venue via AJAX. After the new venue is created, I would like to updated the venue select box to reflect this.

My solution was to put the select box in a partial and render the partial from the create action in the controller.

 <div id="venue_select" style="clear: both;">
    <%= render :partial => 'venue/venue_select_box' %>
 </div>

The partial looks like this:

<%= f.collection_select :venue_id, @user_venues, :id, :name, :prompt => 'Select a venue' %>

where f is the form reference:

<% form_for :shows do |f| %>

The problem is that f is undefined in the partial, so I get an error. One solution would be to include the entire form, but I feel like that should not be necessary because I am not updating the entire form. Any ideas on how to go about this?

+4  A: 

You can pass a variable to the partial like this:

  <%= render :partial => 'venue/venue_select_box', :locals => { :f => f } %>

For stuff like this it is always good to look at the documentation.

EDIT: To use the partial with AJAX request you'll need to "recreate" the form in your .rjs template. So in your controller you'll need to find the object again.

 def venue_select
    @venue = Venue.find(params[:id])
    respond_to do |format|
      format.html
      format.js
    end
 end

Then in your venue/venue_select.rjs file:

 form_for @venue do |f|
   page[:element].replace_html :partial => 'venue/venue_select_box', :locals => { :f => f }
 end

Where :element is the id of the select menu you want to replace. Basically you just recreate the form_for and then use that to update the select field.

vrish88
This works from the view, but I will need to render from the controller as well. The select box pulls data that can be updated via AJAX, and therefore that update request will tell the controller to render the partial again...and then "f" is again undefined
Tony
Ah, sorry, I didn't see the AJAX need in your question. I should probably read a bit more carefully next time... I just updated my answer with something that may be able to help you.
vrish88
+1  A: 

It might be easier to add the venue to the selectbox with Javascript, as an onComplete hook on your AJAX add.

Sarah Mei
+1  A: 

I agree with Sarah Mei on this, if anything have your AJAX call return a JSON representation of the venue that was added and then create a new option and add it to the select element.

Some general JS code for adding a select option:

var newOption = new Option("Text", "Value");
selectElement.options[selectElement.options.length] = newOption;
mcfearsome
A: 

These are all great options but I think I found the easiest. Basically, I just hard coded the name in the collection_select so I would not need the "f" variable:

<%= collection_select 'shows[venue_id]', :venue_id, @user_venues, :id, :name, { :prompt => 'Select one of your previous venues' } %>

Then my VenueController is as follows:

class VenueController < ApplicationController
  layout 'main'
  before_filter :login_required, :get_user

  def create
    begin
      venue = @user.venues.create(params[:venue])
      @user_venues = @user.venues
      render :partial => 'venue_select_box', :success => true, :status => :ok
    rescue ActiveRecord::RecordInvalid => invalid
      flash[:errors] = invalid.record.errors
      render :text => '', :success => false, :status => :unprocessable_entity
    end
  end

end

If this method is bad practice for any reason, please let me know and I will happily credit you for the answer.

Tony