# Polymorphism & REST

**URL:** <https://www.ruby-forum.com/t/polymorphism-rest/86523>\
**Category:** Rails\
**Created:** [February 22, 2007, 11:05pm UTC](https://www.ruby-forum.com/t/polymorphism-rest/86523 "2007-02-22T23:05:59Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![dean](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/3be4f8/32.png) [@dean](https://www.ruby-forum.com/u/dean)\
**Post date:** [February 22, 2007, 11:05pm UTC](https://www.ruby-forum.com/t/polymorphism-rest/86523/1 "2007-02-22T23:05:59Z")

</div>

I have a polymorphic model:

class Note \< ActiveRecord::Base  
belongs\_to :notable, :polymorphic =\> true  
end

And some models that use notes:

class User \< ActiveRecord::Base  
has\_many :notes, :as =\> :notable  
end

class Blog \< ActiveRecord::Base  
has\_many :notes, :as =\> :notable  
end

My routes are set up:

map.resources :users :notes  
map.resources :blogs :notes  
etc

REST says I should GET /users/3/notes or /blogs/243/notes if I want to  
see the notes associated with the objects. All fine and good, but how  
do I implement the index method of the NotesController?

Thanks,  
–Dean

---

<div class="post-metadata">

**Author:** ![dean](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/3be4f8/32.png) [@dean](https://www.ruby-forum.com/u/dean)\
**Post date:** [February 22, 2007, 11:20pm UTC](https://www.ruby-forum.com/t/polymorphism-rest/86523/2 "2007-02-22T23:20:04Z")

</div>

On 2/22/07, Dean [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> has\_many :notes, :as =\> :notable  
> etc
> 
> REST says I should GET /users/3/notes or /blogs/243/notes if I want to  
> see the notes associated with the objects. All fine and good, but how  
> do I implement the index method of the NotesController?

def index  
parent = User.find(params[:user\_id]) if params[:user\_id]  
parent = Blog.find(params[:blog\_id]) if params[:blog\_id]

@notes = parent.notes  
end

---

<div class="post-metadata">

**Author:** ![dean](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/3be4f8/32.png) [@dean](https://www.ruby-forum.com/u/dean)\
**Post date:** [February 23, 2007, 1:33am UTC](https://www.ruby-forum.com/t/polymorphism-rest/86523/3 "2007-02-23T01:33:13Z")

</div>

On Feb 22, 2:19 pm, “Pat M.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> def index  
> parent = User.find(params[:user\_id]) if params[:user\_id]  
> parent = Blog.find(params[:blog\_id]) if params[:blog\_id]
> 
> @notes = parent.notes  
> end

I’d rather have a more general way to find @notes so I can add more  
objects with notes without going back to the notes\_controller every  
time. Is there a good way to inspect params[] for anything\_id?

–Dean

---

<div class="post-metadata">

**Author:** ![dean](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/3be4f8/32.png) [@dean](https://www.ruby-forum.com/u/dean)\
**Post date:** [February 23, 2007, 5:14am UTC](https://www.ruby-forum.com/t/polymorphism-rest/86523/4 "2007-02-23T05:14:32Z")

</div>

On Friday 23 February 2007, Dean wrote:

> time. Is there a good way to inspect params[] for anything\_id?  
> I have a similar setting with audits where all of my resources have an  
> audit log. As this functionality cuts across the resources, I handle  
> display of the audit log by a separate controller. I haven’t come up  
> with a way to do this neatly with map.resources, rather, I add the  
> routes like this

map.with\_options(:controller =\> ‘audits’, :action =\> ‘show’) do |  
audits\_map|  
audits\_map.audits ‘:resources/:id/audits.:format’  
audits\_map.audits ‘:resources/:id/audits’, :format =\> ‘html’  
end

The AuditsController looks (partially) like this

class AuditsController \< ApplicationController  
session :off, :if =\> proc { |req| req.parameters[:format] != ‘html’ }

def show  
respond\_to do |format|  
format.html { show\_html }  
format.atom { show\_atom }  
format.xml { show\_xml }  
end  
end

private

def show\_html  
setup\_objects  
render :action =\> ‘show’  
end

def setup\_objects  
audited\_class = assert\_valid\_resource\_name(params[:resources])  
auditable\_type = audited\_class ?  
audited\_class.singularize.camelize : nil  
auditable\_id = params[:id]  
@audits =  
Audit.find\_all\_by\_auditable\_type\_and\_auditable\_id(auditable\_type,  
auditable\_id)  
end

end

To ensure that audit logs can only be displayed for valid resources,  
I’ve monkey patched resource route registration to collect resource  
names and check against these names. Here, too, I’m all in favor of a  
more elegant solution.

In ApplicationController

def assert\_valid\_resource\_name(name)  
raise ArgumentError, “Resource does not exist: #{name}” unless  
ActionController::Resources.valid\_resource?(name)  
name  
end

loaded on startup from a file in lib

ActionController::Resources.module\_eval do  
mattr\_accessor :valid\_resources  
ActionController::Resources.valid\_resources = []

def self.valid\_resource?(name) #:doc:  
ActionController::Resources.valid\_resources.include?(name.to\_sym)  
end

private

def map\_resource\_with\_collecting(entities, \*args, &block)  
ActionController::Resources.valid\_resources |= [entities]  
map\_resource\_without\_collecting(entities, \*args, &block)  
end  
alias\_method\_chain :map\_resource, :collecting  
end

HTH,  
Michael

–  
Michael S.  
[mailto:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
[http://www.schuerig.de/michael/](http://www.schuerig.de/michael/)

---

<div class="post-metadata">

**Author:** ![dean](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/3be4f8/32.png) [@dean](https://www.ruby-forum.com/u/dean)\
**Post date:** [February 23, 2007, 9:55pm UTC](https://www.ruby-forum.com/t/polymorphism-rest/86523/5 "2007-02-23T21:55:56Z")

</div>

Based on another post here, this is what I’m using for restfull nested  
routing. It’s a work in progress and I’m only a few weeks into  
ruby/rails  
so YMMV. No error checking yet here. That’ll come later.

This routine automatically pulls both the parent/child objects from the  
DB.  
Not sure whether I’ll leave that or not.

This gets called as a global before\_filter, populating an instance  
variable  
chock full of crap that gets consumed downstream. I have another  
helper  
method that generates proper routes for add/edit/show/etc that I might  
roll  
into this as well. I’ve also considered making this a class, but for  
now  
I’m still tweaking it.

My design will only (currently) allow for nesting 1 level deep, as I  
plan to  
have redundant routes, ala:

Customers  
Customers/PO  
PO/  
PO/LineItems

I’ve come up with a way to display nested resources within their  
parents,  
via a (still-in-progress) tabular paging thingymabob.

private  
def find\_type\_and\_id  
sections = request.env[‘REQUEST\_URI’].scan(%r{/(\w+)/_(\d_)})  
@page = {} unless defined?(@page)

@page[:isnested] = false  
if sections.length \> 0  
@page[:base\_class\_name] = sections[0][0].singularize  
@page[:base\_class] = eval(@page[:base\_class\_name].camelize)  
@page[:base\_id] = sections[0][1].blank? ? nil : sections[0][1]  
@page[:base\_object] = @page[:base\_class].find(@page[:base\_id]) if  
!@page[:base\_id].blank?  
end

if sections.length \> 1  
@page[:sub\_class\_name] = sections[1][0].singularize  
@page[:sub\_class] = eval(@page[:sub\_class\_name].camelize)  
@page[:base\_prefix] = @page[:base\_class\_name] + “\_”  
@page[:base\_show\_path] = sections[0][0] + ‘/show’  
@page[:sub\_new\_post\_path] =  
eval("#{@page[:base\_prefix]}#{@page[:sub\_class\_name].pluralize}\_path(#{@page  
[:base\_id]})")  
@page[:isnested] = true

```
if !sections[1][1].blank?
  @page[:sub_id] = sections[1][1]
  @page[:sub_object] = @page[:sub_class].find(@page[:sub_id])
  @page[:sub_edit_post_path] =

```

eval("#{@page[:base\_prefix]}#{@page[:sub\_class\_name]}\_path(#{@page[:base\_id]  
},#{@page[:sub\_id]})")  
end  
end  
logger.debug(“Page-\> #{dumphash(@page)}”)  
end
