module InheritedResources::PolymorphicHelpers
polymorphic associations¶ ↑
In some cases you have a resource that belongs to two different resources but not at the same time. For example, let’s suppose you have File, Message and Task as resources and they are all commentable.
Polymorphic associations allows you to create just one controller that will deal with each case.
class Comment < InheritedResources::Base belongs_to :file, :message, :task, :polymorphic => true end
Your routes should be something like:
resources :files do resources :comments #=> /files/13/comments end resources :tasks do resources :comments #=> /tasks/17/comments end resources :messages do resources :comments #=> /messages/11/comments end
When using polymorphic associations, you get some free helpers:
parent? #=> true parent_type #=> :task parent_class #=> Task parent #=> @task
This polymorphic controllers thing is a great idea by James Golick and he built it in resource_controller. Here is just a re-implementation.
optional polymorphic associations¶ ↑
Let’s take another break from ProjectsController. Let’s suppose we are building a store, which sell products.
On the website, we can show all products, but also products scoped to categories, brands, users. In this case case, the association is optional, and we deal with it in the following way:
class ProductsController < InheritedResources::Base belongs_to :category, :brand, :user, :polymorphic => true, :optional => true end
This will handle all those urls properly:
/products/1 /categories/2/products/5 /brands/10/products/3 /user/13/products/11
nested polymorphic associations¶ ↑
You can have polymorphic associations with nested resources. Let’s suppose that our File, Task and Message resources in the previous example belongs to a project.
This way we can have:
class CommentsController < InheritedResources::Base belongs_to :project { belongs_to :file, :message, :task, :polymorphic => true } end
Or:
class CommentsController < InheritedResources::Base nested_belongs_to :project nested_belongs_to :file, :message, :task, :polymorphic => true end
Choose the syntax that makes more sense to you. :)
Finally your routes should be something like:
resources :projects do resources :files do resources :comments #=> /projects/1/files/13/comments end resources :tasks do resources :comments #=> /projects/1/tasks/17/comments end resources :messages do resources :comments #=> /projects/1/messages/11/comments end end
The helpers work in the same way as above.
Protected Instance Methods
Returns the parent object. They are also available with the instance variable name: @task, @file, @note…
# File lib/inherited_resources/polymorphic_helpers.rb, line 123 def parent if parent_type p = instance_variable_defined?(:"@#{parent_type}") && instance_variable_get(:"@#{parent_type}") p || instance_variable_set(:"@#{parent_type}", association_chain[-1]) end end
If the polymorphic association is optional, we might not have a parent.
# File lib/inherited_resources/polymorphic_helpers.rb, line 132 def parent? if resources_configuration[:polymorphic][:optional] parents_symbols.size > 1 || !parent_type.nil? else true end end
# File lib/inherited_resources/polymorphic_helpers.rb, line 116 def parent_class parent.class if parent_type end
Returns the parent type. A Comments class can have :task, :file, :note as parent types.
# File lib/inherited_resources/polymorphic_helpers.rb, line 106 def parent_type unless instance_variable_defined?(:@parent_type) symbols_for_association_chain end if instance_variable_defined?(:@parent_type) @parent_type end end