Robert Jones
7/17/2005 6:26:00 PM
Kirk Haines wrote:
> On Saturday 16 July 2005 10:00 am, Robert Jones wrote:
>
>> Suppose that object A has many of object B, and object B has some
>> attribute c, and that my Rails app has models that hold these
>> associations.
>>
>> Can Rails then help me to produce an edit form for object A that includes
>> a list of all the related object B's, and allows me to edit each of their
>> attribute c's directly (ie not by simply providing a link to a seperate
>> edit form for each of the object B's)
>
> This doesn't seem to be a matter of "can" Rails do it. The existing
> scaffolding may or may not be able to directly support this, but it should
> be darn simple to write something in any decent framework, with any decent
> ORM, that can.
>
> I use a component in production that could trivially be extended to do
> exactly this, generically.
>
>
> Kirk Haines
I made it happen, pretty easily, but I still think this ought to be built
into Rails. Can't see why it isn't. Maybe it is and I'm missing
something.
I used an example of houses and rooms. Each house has many rooms, and the
rooms have names. In order to produce a form to edit the houses, which
allows direct editing of the names of the rooms in the house, I did the
following:
sql:
-------------------------------------------------------------
CREATE TABLE `houses` (
`id` mediumint(9) NOT NULL auto_increment,
`name` varchar(30) NOT NULL default '',
`description` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
#
# Dumping data for table `houses`
#
INSERT INTO `houses` VALUES (1, 'Briary Bush', 'Lovely little house near a
babbling river');
INSERT INTO `houses` VALUES (2, 'Fawlty Towers', 'A grotty hell hole');
CREATE TABLE `rooms` (
`id` mediumint(9) NOT NULL auto_increment,
`name` varchar(50) NOT NULL default '',
`house_id` mediumint(9) NOT NULL default '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
#
# Dumping data for table `rooms`
#
INSERT INTO `rooms` VALUES (1, 'First Floor Front Room', 1);
INSERT INTO `rooms` VALUES (2, 'Penthouse', 1);
INSERT INTO `rooms` VALUES (3, 'Room 1', 2);
-------------------------------------------------------------
house.rb:
-------------------------------------------------------------
class House < ActiveRecord::Base
has_many :rooms
# This extends update_attributes to allow for the updating of the
associated records.
# The "rooms" hash is in the form {"id"=>{"column"=>"value",.......},
"id"=>{"column"=>"value",.....},....}
def update_attributes(attributes)
attributes["rooms"].each do |key,value|
@room=Room.find(key)
@room.update_attributes(value)
end
attributes.delete("rooms")
super(attributes)
end
end
-------------------------------------------------------------
room.rb:
-------------------------------------------------------------
class Room < ActiveRecord::Base
belongs_to :house
end
-------------------------------------------------------------
_form.html partial in views/houses :
-----------------------------------------------------------
<%= error_messages_for 'house' %>
<!--[form:house]-->
<p><label for="house_name">Name</label><br/>
<%= text_field 'house', 'name' %></p>
<p><label for="house_description">Description</label><br/>
<%= text_area 'house', 'description', "rows"=>"5" %></p>
<% for room in @house.rooms %>
<label for="room_<%=room.id %>_name">Room <%=h room. id%></label>
<input id="house_rooms_<%=h room. id%>_name" name="house[rooms][<%=h room.
id%>][name]" type="text" value="<%=h room. name%>" />
<% end %>
<!--[eoform:house]-->
-------------------------------------------------------------
I look forward to someone showing me a neater way to do it :)
The extension of the update_attributes method seems so simple that I can't
believe it would take much work to generalise this and have
update_attributes deal with associated data automatically. Any takers for
this wee Rails development task ? ;)
--
Robert Jones