Isnor Creative
Isnor Creative Blog
Ruby, Ruby on Rails, Ember, Elm, Phoenix, Elixir, React, Vue

Apr 27, 2008

Rails Faux Nested Forms

For adding an item via Ajax to related models then updating an existing select…

Here’s the situation:

For this example we have a New Product form. Products belong to Companies so we have a select menu of Companies.

You want to add a product and you have a select menu of companies, but in this case you have a product from a company you have not dealt with in the past. So directly below your select we are going to create a text field from which you can add a new company. You fill in your company name, press the faux-submit button, your company gets added via the companies controller, then the select menu will automatically be updated, with your new company selected…

*DISCLAIMER

There is probably a better, safer, simpler, more DRY, more best-practice, more concise, more Railsy, and more Ruby ways of doing this. Personally, I had a hard time finding an answer to this problem on any Rails forums or tutorials, but I had previously done it with ease in PHP. So I applied those same principles here and it seems to work fine. Hopefully it helps you, and if you know of a better way to handle this situation I would be thrilled to hear it.

First let’s start with the main form for adding a product:

First you have your original select wrapped in a div. The contents of the div (the select) are we will be updating with your new select….

<div id='companySelect'>    <%= collection_select("company", "company_id" , @companies, "id", "name", {:prompt => 'Choose company...'}) %> </div>

Now you have a script that identifies the div to update, gets the input value, then does an AjaxUpdate passing the new company value in the url.

`

`

Here’s your ‘internal form’ for submission of the new company. First a text field: ` <%= text_field ‘newCompany’, ‘name’ %>

`

Then a faux submit button

<a href='#' onmouseover="this.style.cursor='pointer'" onclick='return addCompany();'> Add New Company </a>

Now our main form view is done so let’s move on….

ADD YOUR ROUTE to routes.rb:

map.connect 'companies/afterAjax', :controller=>'companies', :action=>'afterAjax'

Beef up your Companies Controller:

` class CompaniesController < ApplicationController

  protectfromforgery :only => [:create, :destroy, :update] `

the protect_from_forgery line seems to solve token error problems for Ajax - makes me nervous though - is this creating security risks? If you know how better to deal with this - let me know….

`

Add The Company

def createForAjax    @company = Company.new()

   @company.name = params[‘compay’]    respondto do |format|      if @company.save        format.html { redirectto :action=>‘afterAjax’, :params=>{:id=>@company.id.to_s} }
     end

   end end

Generate A New Select With The Company You Created Selected

def afterAjax    @companies = Company.select (or find :all – whatever your method to get all companies)    @company = Company.find(params[:id]) (this is the one you just created)    respond_to do |format|

     format.html    end end `

Finally, this Is The View For The New Select:

afterAjax.html.erb view in companiesController:

` <%= selecttag ‘product[companyid]’, optionsfromcollectionforselect(@companies, :id, :name, @company.id) %>

`

That’s It

Like I said, I imagine there are better and more concise ways of doing this and if you know them I would be happy to hear about it.


I am available for Ruby on Rails consulting work – get in touch to learn more.

Gordon B. Isnor

Gordon B. Isnor writes about Ruby on Rails, Ember.js, Elm, Elixir, Phoenix, React, Vue and the web.
If you enjoyed this article, you may be interested in the occasional newsletter.

I am now available for project work. I have availability to build greenfield sites and applications, to maintain and update/upgrade existing applications, team augmentation. I offer website/web application assessment packages that can help with SEO/security/performance/accessibility and best practices. Let’s talk

comments powered by Disqus