Birds-Eye.Net
All things broadband and more...
 
Web Birds-Eye.Net

What's New?

Ruby on Rails (RoR)
Programming Reference


Models
External database connections
Passing current_user into model
Passing object into model
Using static lookup tables
Validates IF
Validates MongoMapper

Views
Dynamically delete form element
Edit create nested data
HTML form field check_box
Layout jQuery datatable module
Select array
Select cascading via JS
Text_area Array
Text_area listing submit
Text field format time

Controllers
Dynamic model selection
Including first item from a sorted desc table
Using from_unixtime on epoch dates

Rack
Integrated NTLM/Kerberos Authentication
Pass-through Authentication w/ NTLM

ActionMailer
Broken links in emails

Rails General
Add, Subtract, Multiply, and Divide
Calculate number of weekdays for date range
Date->Epoch & Epoch->Date
Extract first letter of each word
Hash of hashes assignment
Using: variable as hash index

jQuery
jQuery accordion MongoDB


More to come

 

Editing and Creating Views of Nested (Relational) Data

By: Bruce Bahlmann - Contributing Author (your feedback is important to us!)

In rails development, within your view, often you will want to either create a new record or edit that record. Well, generally this is easy. However when you are using nested (relational) data it gets complicated. The following is a solution when creating and editing an array of data (responses to questions) when the actual responses varies with the questions (which also varies by survey). This is a case of a completely dynamic data structure and we use MongoDB as our database.

The above graphic represents a response entry form that is generated dynamically upon a user wanting to complete a survey. Since the questions within a given survey could be any number (there is no limit), there is accordingly no limit to the responses (other than which answer the questions which the responses correspond). As the above entry form is blank, this represents a NEW entry so rails would flow through the new section of the responses_controller.

A problem exists when you want to both provide a create (new) interface as well as an edit interface. That is because when you provide an edit interface which requires the VALUE attribute to be correctly populated (to allow you to view the value of the field as stored in the database), as well as a create new form, and these interfaces access the same form, you will receive unknown method errors when trying to access the create (new) form. In our case, new instances of ANSWER in our response model, haven't been populated yet (because we are in the process of creating it).

[apps/views/responses/_form.html.erb]
...
<span class="step" id="first">
<table border="0">
<% @survey.sorder.split('&').each do |ti| %>
  <% key = ti.sub('s[]=','') %>
  <% value = @survey.question[key] %>
  <% if value["questionText"] == "PageBreak" %>
    </table>
    </span>
    <span id="" class="step">
    <table border="0">
  <% else %>
    <% if value["questionType"] == "0" %> 
      <tr><td><%= value["questionText"] %>:</td>
      <td> <%= text_field("response[answer]", key, :class=> "q"+key, :value=>@response.answer[key], :disabled=>@dfv) %></td></tr>
    <% elsif value["questionType"] == "1" %> 
      <tr><td><%= value["questionText"] %>:</td><td> 
      <%= select("response[answer]", key, value["choices"].split("\r\n") {|k,v| [v,k.to_i]},
              { :selected => @response.answer[key], :include_blank=>0}, :class=>"q"+key, :disabled=>@dfv) %>
      </td></tr>
    <% elsif value["questionType"] == "2" %> 
      <tr><td><%= value["questionText"] %>:</td><td> 
      <% lcv = 1 %>
      <% value["choices"].split(/\r\n/).each do |v| %>
        <input <%= @df %> id="answer_<%= key %>_<%= lcv %>" class="q<%= key %>" type="checkbox" 
             name="response[answer][<%= key %>][]" value="<%= v %>"
        <% if !@response.answer.empty? %>
          <% if @response.answer[key].include?(v) %>
            checked
          <% end %>
        <% end %>
        > <%= v %>
        <% lcv = lcv + 1 %>
      <% end %>
      </td></tr>
    <% elsif value["questionType"] == "3" %> 
      <tr><td style="vertical-align: top"><%= value["questionText"] %>:</td>
      <td> <%= text_area ("response[answer]", key, :class=> "q"+key, :rows=>6, 
               :cols=>60, :value=>@response.answer[key], :disabled=>@dfv) %></td></tr>
    <% end %>
  <% end %>
<% end %>
</table>

A simple, but less elegant way of dealing with this issue is to just NOT use the edit form with the survey recreated like the user once saw with the values they entered. Instead, use the show, which allows you to just dump the values of the response. However, since in our case the response doesn't really understand the questions (rather it is simply just an array of responses to the questions), we need the survey to make sense of the response. So, here is the error we were seeing:

undefined method `answer' for #<Response:0x1185fb6f8>

Also, here was what we had entered into the responses_controller - which is pretty standard. Again, we needed to pass both the survey as well as the response that we were creating for the survey.

[apps/controllers/responses_controller.rb]
## GET /surveys/new
## GET /surveys/new.xml
def new
  @survey = Survey.find(params[:survey_id])
  @response = Response.new

Here was our model for both response and answer:

[apps/models/response.rb]
class Response 
include MongoMapper::Document

key :responder, Integer
key :cdate, Date 

belongs_to :survey
many :answers

end

[apps/models/answer.rb]
class Answer 
include MongoMapper::EmbeddedDocument

belongs_to :response

end

The solution ended up being very simple, we just defined the ANSWER attribute when creating a NEW response and since we were creating a new response, we set the attribute to an empty hash. 

apps/controllers/surveys_controller.rb
## GET /surveys/new
## GET /surveys/new.xml
def new
  @survey = Survey.find(params[:survey_id])
  @response = Response.new(:answer => Hash.new)

As a result, the method error above went away, and now the form can be accessed either via create or edit (see below) elegantly and simply.

This seems too simple, but perhaps its just rails common sense, because finding a good explanation for this proved difficult - which is why I'm wring this post.

.

Can Birds-Eye.Net help you or your Company?
Receive your Birds-Eye.Net articles and white papers hot off the presses by adding our RSS feed to your reader.

 

 

(C) Copyright Birds-Eye.Net, All rights reserved.
It is against the law to reproduce this content or any portion of it in any form without the explicit written permission of Birds-Eye Network Services, LLC. Federal copyright law (17 USC 504) makes it illegal, punishable with fines up to $100,000 per violation plus attorney's fees.