[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Can Rails deal with related attributes in forms?

Robert Jones

7/16/2005 3:57:00 PM

Hi! I'm exploring whether or not to move to Rails, and the solution to the
following problem would be a big step in the right direction for me:

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)

I've made this happen using PHP/MySql - I'm hoping that Rails can do it 10
times faster!
--
Robert Jones
4 Answers

Michael Schuerig

7/16/2005 10:59:00 PM

0

Robert Jones wrote:

> 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)

Yes, that's entirely possible.

http://wiki.rubyonrails.com/rails/show/HowToEditObjectArrays...

That still looks more complicated than it should, IMHO, but I think for
the time being there's no easier solution.

Michael

--
Michael Schuerig They tell you that the darkness
mailto:michael@schuerig.de Is a blessing in disguise
http://www.schuerig.d... --Janis Ian, From Me To You

khaines

7/16/2005 11:05:00 PM

0

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


khaines

7/17/2005 12:05:00 AM

0

On Saturday 16 July 2005 5:00 pm, Michael Schuerig wrote:

> Yes, that's entirely possible.
>
> http://wiki.rubyonrails.com/rails/show/HowToEditObjectArrays...
>
> That still looks more complicated than it should, IMHO, but I think for
> the time being there's no easier solution.

Interesting little article.

For comparison, here's the equivalent in my current IOWA version, with
assumption that the list of items comes from somewhere useful, such as a
database query, and is just passed to the List component when the list is
called:

Views:

List.html
-----
<h1>Item#list</h1>

<table border="1" cellspacing="0" cellpadding="0" width="10%">
<repeat oid="item_list"><tr><td>@item.name</td></tr>
</repeat>
</table>
<br />
<a oid="goto_edit">Edit</a>
-----

Edit.html
-----
<h1>Edit itemlist</h1>

<form oid="save_items">
<table border="1" cellspacing="0" cellpadding="0">
<repeat oid="item_list">
<tr><td><input type="text" oid="item.name" size="20">)</td></tr></repeat>
</table>
<br />
<input type='submit' oid="save_items" value='Save' />
</form>
<br />
<a oid="go_back">List</a>
-----

Controllers:

List.iwa
-----
class List < Iowa::Component
attr_accessor :item, :items

def goto_edit
edit_page = page_named('Edit')
edit_page.items = @items
yield edit_page
end
end

<?
item_list {
item = item
list = items
}
?>
-----

Edit.iwa
-----
class Edit < Iowa::Component
attr_accessor :item. :items

def go_back
yield prev_page
end

def save_items
# This really isn't needed unless something special needs to be done; the
# changes automatically get saved.
end
end

<?
item_list {
item = item
list = items
}
?>


Note that this example above doesn't sound like it quite does what the OP was
asking for, which is to have a master record with it's fields, and each of
the associated records with their fields, all displayed in one big form for
editing.

Using my CRUDForm component to do that, the view would end up being something
like this:

-----
<h1>Edit itemlist</h1>

<crudform oid="item_record" />

<br />
<a oid="go_back">List</a>
-----

And the controller something like so:
-----
import 'CRUDForm'
class Edit < Iowa::Component
attr_accessor :item

def go_back
yield prev_page
end
end

<?
item_record {
record = item
cascade = true
}
?>
-----


I'm sure one can do something similarly simple to use with Rails and Nitro, as
well.


Kirk Haines


Robert Jones

7/17/2005 6:26:00 PM

0

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