I’m 100% sure that there is an elegant, rails-tastic way to do this, but I’m short on time and want to remember this approach, because all things considered, it doesn’t seem that bad.
I’m trying to create a set of objects that can nest. These MonitorGroup objects can contain other MonitorGroup objects, so I can create a hierarchy of things I want to monitor. The model definition for MonitorGroup is:
class MonitorGroup < ActiveRecord::Base
has_many :monitor_instances
has_many :monitor_groups
belongs_to :monitor_group belongs_to :status
validates_presence_of :name, :status
validates_uniqueness_of :name
end
Note that the ‘nesting’ is indicated in the highlighted belongs_to method.
In order to actually get this to happen, I need to have a way to add child MonitorGroup objects to a parent. I do this in the parent’s edit page as follows:
<%=link_to “Add Child Monitor Group”, {:action=>”new”,:parent_monitor_group_id=>@monitor_group.id} %>
The parent_monitor_group_id gets put into the params of the new page: basically this link_to builds a link like this:
http://localhost:3000/monitor_groups/new?parent_monitor_group_id=10
So if the user is editing the parent monitor group, they have the option to add a child monitor group. This request gets routed to the new method of the MonitorGroupsController, where I unpack the parameter and look up the associated Monitor:
def new
# this is needed so that the form can access model properties.
@monitor_group = MonitorGroup.new
parent_monitor_group_id = params[:parent_monitor_group_id]
if(parent_monitor_group_id != nil)
@monitor_group.monitor_group = MonitorGroup.find(parent_monitor_group_id)
logger.debug(“parent monitor name = #{@monitor_group.monitor_group.name}, id = #{@monitor_group.monitor_group.id}”)
end
respond_to do |format|
format.html # new.html.erb
format.xml { render
ml => @monitor_group }
end
end
So far, so good. I’ve now created the MonitorGroup object that is going to be used to drive the form_for block I use in the new MonitorGroup page, if the parent_monitor_group_id is passed in the params hash.
In order to access this value in the form that I was going to submit, I needed to embed it using fields_for, this process is described quite well here. The main difference between the standard use of fields_for and the way I’m using it is that I want to pass this variable as a hidden field variable, instead of one that requires input.
Long story short: I was able to embed the id of the parent MonitorGroup in the MonitorGroup new page like this:
<% form_for(@monitor_group) do |f|
fields_for(:monitor) do | mon |
if(@monitor_group.monitor_group != nil) %>
<%=hidden_field “parent_monitor”,:id,{:value=>@monitor_group.monitor_group.id} %>
<% end
end
%>
…
A couple of things to note: the hidden field gets translated to the following html:
<input id=”parent_monitor_id” name=”parent_monitor[id]” type=”hidden” value=”9″ />,
which in turn means that the params passed to the create method of the MonitorsGroupController look like this:
Parameters: {“commit”=>”Create”, “authenticity_token”=>”xxx”, “action”=>”create”, “controller”=>”monitor_groups”, “monitor_group”=>{“name”=>”child_mon”, “description”=>”child monitor”}, “parent_monitor”=>{“id”=>”9″}}
and I access the monitor ID in the create method as follows:
parent_id = params[:parent_monitor][:id]
if(id != nil)
@monitor_group.monitor_group = MonitorGroup.find(parent_id)
end
This seems kind of klugey, but it works, and I’ve got a deadline. Any Rails Gods lurking out there, please show me the elegant concise way of doing this?!?