Polymorphic Associations in Rails: URL Generation and Parent Model Handling
When having a polymorphic association in Rails model, you want to: 1. generate URL 2. find the parent model in the controller
See below our model structure. Let’s answer those questions the Rails way.
class Company < ActiveRecord::Base has_many :images end class Product < ActiveRecord::Base has_many :images end class Image < ActiveRecord::Base belongs_to :imageable, polymorphic: true end
Generating Image URL
RoR provides a simple way to generate polymorphic URLs: polymorphic_path
So polymorphic_path([parent, Image]) will generate:
company_images_path(parent) # /companies/1/images # or product_images_path(parent) # /products/1/images
Finding the Parent Model in the Controller
If in Image controller, we need to have parent information in order to scope relevant data, we will use ResourceFinder helper.
class ImagesController < ApplicationController include ResourceFinder def index @resources = parentable.images render json: @resources end end
And we will create a app/controllers/concerns/resource_finder.rb helper:
module ResourceFinder def parentable klass, param = parentable_class klass.find(params[param.to_sym]) end private def parentable_class params.each_key do |name| if name.match?(/(.+)_id$/) model = name[/([^\/.]*)_id$/, 1] return model.classify.safe_constantize, name end nil end end end
The parentable_class read the param and define the class associated with the param. In our case, if we have /products/:product_id/images this method will read the product_id params key and will try to create a class from this param. If successful, it will return the key and the class to be used in our scope.
Happy hacking!