Forum: Ruby on Rails polymorphism & REST

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Dean (Guest)
on 2007-02-23 00:05
(Received via mailing list)
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
Pat M. (Guest)
on 2007-02-23 00:20
(Received via mailing list)
On 2/22/07, Dean <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
Dean (Guest)
on 2007-02-23 02:33
(Received via mailing list)
On Feb 22, 2:19 pm, "Pat M." <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
Michael S. (Guest)
on 2007-02-23 06:14
(Received via mailing list)
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
http://www.schuerig.de/michael/
Meech (Guest)
on 2007-02-23 22:55
(Received via mailing list)
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
This topic is locked and can not be replied to.