Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

finding parent in rails polymorphic association

I am working on implementing polymorphic comments (these can be applied to just about any user content on the site, and is not limited to Article instances. When creating a comment, I need to determine which commentable it belongs to. Most of the writing I have found on this subject suggests that I use the pattern specified in find_commentable in the code below, but this approach does not strike me as very elegant - it would seem there should be a straightforward way to unambiguously specify the commentable a new comment is being created for, without traversing the params set, and without string matching. Is there a better way?

In other words, is there a better way to access the commentable object from the comment controller in the context of a commentablecomment association? Does it still work the create method where we do not yet have a @comment object to work with?

My models are set up as follows:

class Comment < ActiveRecord::Base
  belongs_to :commentable, :polymorphic => true
end

class Article < ActiveRecord::Base
  has_many :comments, :as => :commentable, dependent: :destroy
end

class CommentsController < ApplicationController 
  def create
    @commentable = find_commentable  
    @comment = @commentable.comments.build(comment_params)

    if @comment.save
      redirect_to :back
    else  
      render :action => 'new'
    end  
  end

  def index
    @commentable = find_commentable
    @comments = @commentable.comments
  end

  private
    def comment_params
      params.require(:comment).permit(:body)
    end

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

Thank you!

like image 895
Ilia Lebedev Avatar asked Dec 07 '22 02:12

Ilia Lebedev


1 Answers

I was looking for an answer to this as well and wanted to share Launch Academy's Article on Polymorphic Associations as I felt it provided the most succinct explanation.
For your application two additional options:

1. The "Ryan Bates" Method: (when you use Rails' traditional RESTful URLs)

def find_commentable
    resource, id = request.path.split('/')[1, 2]
    @commentable = resource.singularize.classify.constantize.find(id)
end

2. The Nested Resource:

def find_commentable
    commentable = []
    params.each do |name, value|
      if name =~ /(.+)_id$/
        commentable.push($1.classify.constantize.find(value))
      end
    end
    return commentable[0], commentable[1] if commentable.length > 1
    return commentable[0], nil if commentable.length == 1
    nil
end

3. The Single Resource: (Your implementation but repeated for completion)

def find_commentable
  params.each do |name, value|
    if name =~ /(.+)_id$/
      return $1.classify.constantize.find(value)
    end
  end
  nil
end
like image 182
David Kuhta Avatar answered Dec 21 '22 12:12

David Kuhta