Published using Google Docs
Nested Forms & Polymorphic Associations Demonstration
Updated automatically every 5 minutes

Nested Models or Complex Forms and Polymorphic Associations Demonstration.

xssnark@gmail.com

This is a ‘walkthrough’ demonstration of a small Ruby on Rails application that uses both nested models or complex forms and polymorphic associations.

Create rails application:

rails nestedPolyDemo && \

cd nestedPolyDemo && \

script/generate scaffold rfBcCommute description:text && \

script/generate scaffold rfBcExpense amount:float description:text name:string && \

script/generate scaffold rfBcDate bcdate:date description:text

Update models to create associations

  class RfBcDate < ActiveRecord::Base

    belongs_to :eventage, :polymorphic => true

  end

  class RfBcCommute < ActiveRecord::Base

    has_one :rf_bc_date, :as => :eventage

    accepts_nested_attributes_for :rf_bc_date, :allow_destroy => true

  end

  class RfBcExpense < ActiveRecord::Base

    has_one :rf_bc_date, :as => :eventage

    accepts_nested_attributes_for :rf_bc_date, :allow_destroy => true

  end

Add foreign keys for polymorphic relation and run migrations.

Add this to the self.up method in the CreateRfBcDates migration definition

  # Association with an rf_bc_date (ie an event)...

  t.references :eventage, :polymorphic => true

Run the migration

  rake db:migrate

(See note about verifying schema if desired)

Add the 'builder' code into the controllers

In rf_bc_expense.new, add this just after the line that creates the new empty rf_bc_expense

instance. (See the illustrated example controller modification below)

  @rf_bc_expense.build_rf_bc_date

Also do this for rf_bc_commute.new, again, just after the line that creates the new rf_bc_commute instance...

  @rf_bc_commute.build_rf_bc_date

Update views for nested model.

In views/rf_bc_expenses/new.html.erb, within the form_for(@rf_bc_expense) loop, add:

  <% f.fields_for :rf_bc_date do |bcd| %>

    Date:

    <%= bcd.date_select :bcdate %>

  <% end %>

Also add this to views/rf_bc_commutes/new.html.erb, in the equivalent location.

Now add the code that will display the associated records to the 'show' view.

Add the following block at the top of the rf_bc_expenses show.html.erb view...

  <p>

    <b>Date:</b>

    <%=h @rf_bc_expense.rf_bc_date.bcdate %>

  </p>

Add similar code to the rf_bc_commutes show.html.erb view...

  <p>

    <b>Date:</b>

    <%=h @rf_bc_commutes.rf_bc_date.bcdate %>

  </p>

Start the server and Test

Start the webserver as appropriate for your set up so you can connect to the application.

Using your web browser connect to the rf_bc_expenses/new page to create a new rf_bc_expense. If everything's working, you should see a date_select for setting the nested rf_bc_date.

Fill out the form as you like and submit it.

When you submit it, you will be redirected to the show page. This will display the rf_bc_expense and its associated rf_bc_date. If you see the date as well as the expense data, this is the evidence that it’s working. 

This concludes the demo.


Appendix

Verifying Schema after Migrations

You can verify the migration set up the foreign keys for the polymorphic

association if you like by invoking sqlite3 against the development db and

inspecting the schema...

command_prompt$ sqlite3 db/development.sqlite3

sqlite> .schema rf_bc_dates

CREATE TABLE "rf_bc_dates" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "date" date, "description" text, "eventage_id" integer, "eventage_type" varchar(255), "created_at" datetime, "updated_at" datetime);

eventage_id and eventage_type are the fields for the polymorphic association. They are present, so far so good.

Example Controller Modification

For example:

  # GET /rf_bc_expenses/new

  # GET /rf_bc_expenses/new.xml

  def new

    @rf_bc_expense = RfBcExpense.new

    @rf_bc_expense.build_rf_bc_date

                

    respond_to do |format|

      format.html # new.html.erb

      format.xml  { render :xml => @rf_bc_expense }

    end

  end