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!