Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 3: Find parent of polymorphic model in controller?

I'm trying to find an elegant (standard) way to pass the parent of a polymorphic model on to the view. For example:

class Picture < ActiveRecord::Base
  belongs_to :imageable, :polymorphic => true
end

class Employee < ActiveRecord::Base
  has_many :pictures, :as => :imageable
end 

class Product < ActiveRecord::Base
  has_many :pictures, :as => :imageable
end

The following way (find_imageable) works, but it seems "hackish".

#PictureController (updated to include full listing)

class PictureController < ApplicationController
  #/employees/:id/picture/new
  #/products/:id/picture/new
  def new
    @picture = imageable.pictures.new
    respond_with [imageable, @picture]
  end

  private
  def imageable
    @imageable ||= find_imageable
  end

  def find_imageable 
    params.each do |name, value|
      if name =~ /(.+)_id$/  
        return $1.classify.constantize.find(value)  
      end  
    end  
    nil
  end
end

Is there a better way?

EDIT

I'm doing a new action. The path takes the form of parent_model/:id/picture/new and params include the parent id (employee_id or product_id).

like image 258
Nav Avatar asked Sep 06 '11 21:09

Nav


1 Answers

I'm not sure exactly what you're trying to do but if you're trying to find the object that 'owns' the picture you should be able to use the imageable_type field to get the class name. You don't even need a helper method for this, just

def show
  @picture = Picture.find(params[:id])
  @parent = @picture.imagable
  #=> so on and so forth
end

Update For an index action you could do

def index
  @pictures = Picture.includes(:imagable).all
end

That will instantiate all 'imagables' for you.

Update II: The Wrath of Poly For your new method you could just pass the id to your constructor, but if you want to instantiate the parent you could get it from the url like

def parent
  @parent ||= %w(employee product).find {|p| request.path.split('/').include? p }
end

def parent_class
  parent.classify.constantize
end

def imageable
  @imageable ||= parent_class.find(params["#{parent}_id"])
end

You could of course define a constant in your controller that contained the possible parents and use that instead of listing them in the method explicitly. Using the request path object feels a little more 'Rails-y' to me.

like image 194
dogenpunk Avatar answered Sep 21 '22 06:09

dogenpunk