Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #9862 (new enhancement)

Opened 7 months ago

Last modified 4 months ago

[PATCH] Added support for arbitrary attributes on new ActiveResource Objects

Reported by: trek Assigned to: core
Priority: normal Milestone: 2.x
Component: ActiveResource Version: edge
Severity: normal Keywords: activeresource, attributes, tiny, unverified
Cc:

Description

Attached is a patch that changes how unsaved ActiveResource objects handle method missing for their attributes. Currently, new ActiveResource objects have no attributes in their attributes hash until a save has been attempted and the remote resource's attributes are copied into the ActiveResource object.

This makes it hard to drop ActiveResource objects into forms and other locations that expect there to be attributes on new objects (even if there is no value for each attribute).

The patch alters how ActiveResource checks the attribute's hash. For new (unsaved) ActiveResource objects nil will always be returned if an unknown method is called that does not end in '=' or '?' (those cases are handled differently by ActiveResource.

Saved ActiveResource objects continue to behave as expected.

person = Person.new # Person is an ActiveResource subclass
person.unknown_method
#=> nil
person.save
# 200. Saved
person.unknown_method
# NoMethodError

One major reason for this patch is to allow ActiveResource use with standard form builders. The view code below currently returns a NoMethodError on new person objects because person has no attributes until the Resource has been created and xml returned. The patch allows ActiveResource objects to behave more like ActiveRecord objects when used in forms.

<% form_for :person, :url => people_url do |f| %>
  <p><label>name:</label><br/><%= f.text_field 'name' %></p>
  <p><label>age:</label><br/><%= f.text_field 'age' %></p>

  <p>
    <%= f.submit "Create" %>
  </p>
<% end %>

Attachments

add_arbitrary_attribute_method_names_on_new_active_resource_objects.diff (1.2 kB) - added by trek on 10/13/07 03:09:48.

Change History

10/13/07 03:09:48 changed by trek

  • attachment add_arbitrary_attribute_method_names_on_new_active_resource_objects.diff added.

12/01/07 19:26:48 changed by trek

  • keywords changed from form, activeresource, attributes to activeresource, attributes, tiny, unverified.

(follow-up: ↓ 3 ) 01/17/08 16:48:45 changed by EmmanuelOga

In my opinion, the best way to fix this would be to request a new record to the "server" application via a HTTP request. That way the attributes names of the resource would return it's default values. In my "server" app, requesting http://localhost:3000/articles/new.xml responds the right thing:

<article>

<created-at type="datetime" nil="true"/> <description nil="true"/> <name nil="true"/> <price type="decimal" nil="true"/> <updated-at type="datetime" nil="true"/>

</article>

There's a caveat for this: making a request in every "new" is expensive for both server and client. In the end, I think this is the right solution anyway.

(in reply to: ↑ 2 ) 01/17/08 18:06:50 changed by trek

That was tried initially, but as you mention is costly on both ends of the process. Also, the REST convention of /new/ returning an xml document with nil elements isn't in use. A solution like that will require a change to how Rails REST API's publish xml from /new/ *and* make it less useful (without customizing) for services that are not Rails based.

I think ARes is more interesting as a way of consuming any REST API on the web, not just those based on Rails.

01/17/08 19:24:22 changed by EmmanuelOga

I think your patch is really useful, and should be comited.

But beside commiting that fix, it could be say that there are 3 options here:

1) Leave things as they are: no initialization of attributes by requesting of resource/new.xml to server.
2) Change initialize to request resource/new.xml to server
3) "Manually" configure the attributes of the resource on the class.

I.E.:
self.site="http://bla";
self.attributes=%w|name price etc|
or
self.attributes= {

:attribute => "default",
...

}

But what I think would be even better is

4) Allow any of previous behaviors, leave 1) (current behavior: no attrs) as default.