Hi all,
Here is the setup:
I''m writing an application to model a house. Houses have rooms.  I
need the room to have a name, an id, and then one or more lights. Each
light has wattage, hours_per_day, and quantity. I''d also like the room
to have many small_appliances, but I haven''t gotten that far yet.
The best I''ve been able to figure out is to have a separate table for
Lights so that a room can have many lights. My setup is a Houses table
that has_many Rooms.  I have a Rooms table that has_many Lights.  I
have a page where you can add a Room to a House.
On this page there is a text_field for name, and 3 sets of text_fields
for the lights, since I can''t figure out a way to allow the user to
dynamically add extra lights. The code snippet:
--------------------------
<% # form_for :room, :url => { :action => :add_room, :id => @house }
do |form| %>
   <fieldset>
    <legend>Add a Room</legend>
    <div>
      <%= form.label :name, "Name of room: " %>
      <%= form.text_field :name %>
    </div>
    <p><strong>Lights</strong></p>
    <p class="description tier2">Enter lighting information for
up to
three different types of lights.</p>
    <div id="lights0">
      <%= form.label :number_of_lights, "Number of lights: " %>
      <%= form.text_field :number_of_lights, :size => 2 %><br />
      <%= form.label :wattage, "Wattage of lights: " %>
      <%= form.text_field :wattage, :size => 2 %><br />
      <%= form.label :hours_used_per_day, "Number of hours per day
lights are on: " %>
      <%= form.text_field :hours_used_per_day, :size => 2 %>
    </div><br />
    <div id="lights1">
      <%= form.label :number_of_lights1, "Number of lights: " %>
      <%= form.text_field :number_of_lights1, :size => 2 %><br />
      <%= form.label :wattage1, "Wattage of lights: " %>
      <%= form.text_field :wattage1, :size => 2 %><br />
      <%= form.label :hours_used_per_day1, "Number of hours per day
lights are on: " %>
      <%= form.text_field :hours_used_per_day1, :size => 2 %>
    </div><br />
    <div id="lights2">
      <%= form.label :number_of_lights2, "Number of lights: " %>
      <%= form.text_field :number_of_lights2, :size => 2 %><br />
      <%= form.label :wattage2, "Wattage of lights: " %>
      <%= form.text_field :wattage2, :size => 2 %><br />
      <%= form.label :hours_used_per_day2, "Number of hours per day
lights are on: " %>
      <%= form.text_field :hours_used_per_day2, :size => 2 %>
    </div>
    <%= submit_tag "Add room" %>
  </fieldset>
  <% end %>
--------------------------
And here is the code snippet from the controller.
--------------------------
def add_room
    @house = House.find(params[:id])
    @room = Room.new(params[:room])
    @light = Light.new(params[:light])
    respond_to do |format|
      if @room.save
        @light.save
        @house.add_room(@room)
        @house.save
        flash[:notice] = "Room \"#{@room.name}\" was successfully
added."
        format.html { render :action => ''add_rooms'' }
        format.xml { render :xml => @room, :status
=> :created, :location => @room }
      else
        format.html { render :action => ''add_rooms'' }
        format.xml  { render :xml => @room.errors, :status
=> :unprocessable_entity }
      end
    end
  rescue ActiveRecord::RecordNotFound
    logger.error("Attempt to access invalid house #{params[:id]}")
    flash[:notice] = "You must create a house before adding a room"
    redirect_to :action => ''index''
  end
--------------------------
My problem is that I can''t get this form to save the room and lights
(and later small_appliances).  After reading various sources I was
trying to use <% form_tag({:controller => "calculator", :action
=>
"add_room"} ) %> instead of form_for, but I''m not sure how
to access
the params correctly. How can I save to both tables?
Thanks in advance,
Ryan
Hi Ryan,
Try this out
<% form_for :room, :url => { :action => :add_room, :id => @house }
do
|form| %>
      <%= form.label :name, "Name of room: " %>
      <%= form.text_field :name %>
/* Differentiate lights parameter using following way */
      <%= text_field :light,:number_of_lights, :size => 2 %><br
/>
      <%= text_field :light, :wattage, :size => 2 %><br />
<% end %>
And in your controller do the following
def add_room
    @house = House.find(params[:id])
    @room = Room.new(params[:room])
    @light = Light.new(params[:light])
    respond_to do |format|
      ## Save all the parameter only if they are valid, if any of your 
object is not pass validation then no one of the below get saved.
      if @room.valid? && @light.valid? && @house.valid?
&&  @room.save
&& @light.save && @house.add_room(@room) && @house.save
        flash[:notice] = "Room \"#{@room.name}\" was successfully
added."
        format.html { render :action => ''add_rooms'' }
        format.xml { render :xml => @room, :status
=> :created, :location => @room }
      else
        format.html { render :action => ''add_rooms'' }
        format.xml  { render :xml => @room.errors, :status
=> :unprocessable_entity }
      end
    end
  rescue ActiveRecord::RecordNotFound
    logger.error("Attempt to access invalid house #{params[:id]}")
    flash[:notice] = "You must create a house before adding a room"
    redirect_to :action => ''index''
  end
try it & let me know if u face any problem
Thanks,
Salil Gaikwad
-- 
Posted via http://www.ruby-forum.com/.
This seems to be working nicely. However, the room_id is not being saved into the Lights table. What am I missing. Also, how to I get each set of text boxes to save to a new row in the Lights table? - Ryan On Oct 6, 2:28 am, Salil Gaikwad <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> Hi Ryan, > > Try this out > <% form_for :room, :url => { :action => :add_room, :id => @house } do > |form| %> > <%= form.label :name, "Name of room: " %> > <%= form.text_field :name %> > /* Differentiate lights parameter using following way */ > > <%= text_field :light,:number_of_lights, :size => 2 %><br /> > <%= text_field :light, :wattage, :size => 2 %><br /> > > <% end %> > > And in your controller do the following > > def add_room > @house = House.find(params[:id]) > @room = Room.new(params[:room]) > @light = Light.new(params[:light]) > > respond_to do |format| > ## Save all the parameter only if they are valid, if any of your > object is not pass validation then no one of the below get saved. > if @room.valid? && @light.valid? && @house.valid? && @room.save > && @light.save && @house.add_room(@room) && @house.save > flash[:notice] = "Room \"#...@room.name}\" was successfully > added." > format.html { render :action => ''add_rooms'' } > format.xml { render :xml => @room, :status > => :created, :location => @room } > else > format.html { render :action => ''add_rooms'' } > format.xml { render :xml => @room.errors, :status > => :unprocessable_entity } > end > end > rescue ActiveRecord::RecordNotFound > logger.error("Attempt to access invalid house #{params[:id]}") > flash[:notice] = "You must create a house before adding a room" > redirect_to :action => ''index'' > end > > try it & let me know if u face any problem > > Thanks, > > Salil Gaikwad > > -- > Posted viahttp://www.ruby-forum.com/.
If I''m not wrong, this is what you need: http://media.pragprog.com/titles/fr_arr/multiple_models_one_form.pdf On Oct 6, 10:37 am, ryan8720 <ryan8...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> This seems to be working nicely. However, the room_id is not being > saved into the Lights table. What am I missing. > > Also, how to I get each set of text boxes to save to a new row in the > Lights table? > > - Ryan > > On Oct 6, 2:28 am, Salil Gaikwad <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> > wrote: > > > > > Hi Ryan, > > > Try this out > > <% form_for :room, :url => { :action => :add_room, :id => @house } do > > |form| %> > > <%= form.label :name, "Name of room: " %> > > <%= form.text_field :name %> > > /* Differentiate lights parameter using following way */ > > > <%= text_field :light,:number_of_lights, :size => 2 %><br /> > > <%= text_field :light, :wattage, :size => 2 %><br /> > > > <% end %> > > > And in your controller do the following > > > def add_room > > @house = House.find(params[:id]) > > @room = Room.new(params[:room]) > > @light = Light.new(params[:light]) > > > respond_to do |format| > > ## Save all the parameter only if they are valid, if any of your > > object is not pass validation then no one of the below get saved. > > if @room.valid? && @light.valid? && @house.valid? && @room.save > > && @light.save && @house.add_room(@room) && @house.save > > flash[:notice] = "Room \"#...@room.name}\" was successfully > > added." > > format.html { render :action => ''add_rooms'' } > > format.xml { render :xml => @room, :status > > => :created, :location => @room } > > else > > format.html { render :action => ''add_rooms'' } > > format.xml { render :xml => @room.errors, :status > > => :unprocessable_entity } > > end > > end > > rescue ActiveRecord::RecordNotFound > > logger.error("Attempt to access invalid house #{params[:id]}") > > flash[:notice] = "You must create a house before adding a room" > > redirect_to :action => ''index'' > > end > > > try it & let me know if u face any problem > > > Thanks, > > > Salil Gaikwad > > > -- > > Posted viahttp://www.ruby-forum.com/.
Here is an example of some complex forms by ryanb: http://github.com/ryanb/complex-form-examples You can git the repository and run the app to see how it works and then dig into the code. Note: the javascript library used in the example app is prototype, but it is pretty easy to replace it with another library (JQuery, for example). -- Posted via http://www.ruby-forum.com/.
This example is perfect. However, for some reason, it isn''t working.
When I click the Add Light link it doesn''t add any fields.  Here is
all the relevant code (I think).  Basically, for me, project is room,
and task is light.
----------------------------------------------------
<!-- app/views/rooms/new.html.erb -->
<h1>New room</h1>
<%= render :partial => ''room_form'' %>
<p><%= link_to "Back to List", rooms_path %></p>
----------------------------------------------------
----------------------------------------------------
<!-- app/views/rooms/_room_form.html.erb -->
<% form_for @room do |form| %>
  <%= form.error_messages %>
  <p>
    <%= form.label :name %><br />
    <%= form.text_field :name %>
  </p>
  <h3>Lights</h3>
  <% form.fields_for :lights do |light_form| %>
    <%= render :partial => ''light'', :locals => {
:form => light_form }
%>
  <% end %>
  <p><%= add_child_link "[+] Add new light", form, :lights
%></p>
  <p><%= form.submit "Submit" %></p>
<% end %>
----------------------------------------------------
----------------------------------------------------
<!-- app/views/rooms/_light.html.erb -->
<div class="tier2">
  <%= form.label :wattage, "Wattage of lights: " %>
  <%= form.text_field :wattage, :size => 2 %><br />
  <%= form.label :quantity, "Number of lights: " %>
  <%= form.text_field :quantity, :size => 2 %><br />
  <%= form.label :hours_used_per_day, "Number of hours per day lights
are on: " %>
  <%= form.text_field :hours_used_per_day, :size => 2 %><br />
  <%= remove_child_link "remove", form %>
</div><br />
----------------------------------------------------
----------------------------------------------------
# app/helpers/application_helper.rb
# Methods added to this helper will be available to all templates in
the application.
module ApplicationHelper
  def remove_child_link(wattage, form)
    form.hidden_field(:_delete) + link_to_function(wattage,
"remove_fields(this)")
  end
  def add_child_link(wattage, form, method)
    fields = new_child_fields(form, method)
    link_to_function(wattage, h("insert_fields(this,
\"#{method}\", \"#
{escape_javascript(fields)}\")"))
  end
  def new_child_fields(form_builder, method, options = {})
    options[:object]
||form_builder.object.class.reflect_on_association(method).klass.new
    options[:partial] ||= method.to_s.singularize
    options[:form_builder_local] ||= :form
    form_builder.fields_for(method, options[:object], :child_index =>
"new_#{method}") do |form|
      render(:partial => options[:partial], :locals => { options
[:form_builder_local] => form })
    end
  end
end
----------------------------------------------------
Any idea why add_child_link isn''t working?
Thanks,
Ryan
Can you verify that you are including the default javascripts in your template (application.html.erb, most likely). <% javascript_include_tag :defaults %> -- Posted via http://www.ruby-forum.com/.
Yes, I have them included in the rooms.html.erb and it shows in the source of the page. I don''t have an application.html.erb. I also tried moving the code from application_helper to rooms_helper, which didn''t help. I don''t really understand where application comes from anyway. I didn''t generate anything called application.
I figured it out. I hadn''t put the functions into application.js. On Oct 7, 1:33 am, ryan8720 <ryan8...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Yes, I have them included in the rooms.html.erb and it shows in the > source of the page. I don''t have an application.html.erb. I also > tried moving the code from application_helper to rooms_helper, which > didn''t help. > > I don''t really understand where application comes from anyway. I > didn''t generate anything called application.
ryan8720 wrote:> I figured it out. I hadn''t put the functions into application.js.Cool, good work! -- Posted via http://www.ruby-forum.com/.
Thanks for all the help so far.  I believe I''m starting to understand
things now.  The part above is working great.  However, I have a
controller called calculator which is the only part that will be
accessible to users. From calculator you enter information about the
house, then that information is saved to house and you can then start
adding rooms, have a house_id attribute that needs to be passed from
the house that was just created.
The problem now is that I can''t get the new room stuff to render from
calculator.  It always complains it can''t find the partials (which are
located under app/views/rroms).  If I change the paths for them to be
found, it causes other errors.
Here is the calculator_controller.  save_house is called when the user
submits the form.  The commented line under "if @house.save" is what I
had originally. The line under that is my attempt to fix these
problems.
----------------------------------------
class CalculatorController < ApplicationController
  def index
  end
  def save_house
    @house = House.new(params[:house])
    respond_to do |format|
      if @house.save
        #format.html { render :action => ''add_rooms'', :id
=> @house }
        format.html { render :template => ''/rooms/new'',
:room_id =>
@house.id }
        format.xml { render :xml => @house, :status
=> :created, :location => @house }
      else
        format.html { render :action => ''index'' }
        format.xml  { render :xml => @house.errors, :status
=> :unprocessable_entity }
      end
    end
  end
  def add_rooms
    @house = House.find(params[:id])
    @rooms = Room.find_by_house_id(@house.id)
  rescue ActiveRecord::RecordNotFound
    logger.error("Attempt to access invalid house #{params[:id]}")
    flash[:notice] = "You must create a house before adding rooms"
    redirect_to :action => ''index''
  end
  def add_room
    @house = House.find(params[:id])
    @room = Room.new(params[:room])
    respond_to do |format|
      #if @room.valid? && @light.valid? && @house.valid?
&& @room.save
&& @light.save && @house.add_room(@room) && @house.save
      if @room.save
        @house.add_room(@room)
        @house.save
        flash[:notice] = "Room \"#{@room.name}\" was successfully
added."
        format.html { render :action => ''add_rooms'' }
        format.xml { render :xml => @room, :status
=> :created, :location => @room }
      else
        format.html { render :action => ''add_rooms'' }
        format.xml  { render :xml => @room.errors, :status
=> :unprocessable_entity }
      end
    end
  rescue ActiveRecord::RecordNotFound
    logger.error("Attempt to access invalid house #{params[:id]}")
    flash[:notice] = "You must create a house before adding a room"
    redirect_to :action => ''index''
  end
  def report
    flash[:notice] = nil
    @house = House.find(params[:id])
    @rooms = Room.find_by_house_id(@house.id)
  rescue ActiveRecord::RecordNotFound
    logger.error("Attempt to access invalid house #{params[:id]}")
    flash[:notice] = "You must create a house before generating a
report"
    redirect_to :action => ''index''
  end
end
----------------------------------------
Preferably I''d like to be able to render add_rooms (see below), which
is just the same partial called form room.new with a list of rooms
above and a button to move on below.
----------------------------------------
<div id="addRooms">
  <p>House id is <%= @house.id %></p>
  <h3>Your rooms:</h3>
  <% if @house.rooms %>
  <ul>
    <% for room in @house.rooms %>
    <li>
      <%= h room.name %> has <%= h room.number_of_bulbs %>
      <%= h room.wattage_of_bulbs %> watt bulbs, in use for
      <%= h room.usage_hours %> hours per day.
    </li>
    <% end %>
  </ul>
  <% else %>
  <p>You have not added any rooms yet</p>
  <% end %>
  <%= render :partial => ''rooms/room_form'' %>
  <br />
  <%= button_to "Continue to report", :action =>
"report", :id =>
@house %>
</div>
----------------------------------------
Thanks,
Ryan