【问题标题】:finding parent in rails polymorphic association在 Rails 多态关联中查找父级
【发布时间】:2014-04-15 15:54:27
【问题描述】:

我正在努力实现多态 cmets(这些可以应用于站点上的几乎任何用户内容,并且不限于 Article 实例。创建评论时,我需要确定它属于哪个 commentable我在这个主题上找到的大部分文章都建议我在下面的代码中使用find_commentable 中指定的模式,但这种方法并没有让我觉得非常优雅——似乎应该有一种直截了当的方法来明确指定正在为其创建新评论的commentable,无需遍历params 集合,也无需字符串匹配。有更好的方法吗?

换句话说,在commentablecomment 关联的上下文中,是否有更好的方法从comment 控制器访问commentable 对象?在我们还没有 @comment 对象可以使用的情况下,它仍然可以使用 create 方法吗?

我的模型设置如下:

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

谢谢!

【问题讨论】:

  • 你可以重新定义你的 find_commentable 方法:params[:commentable_type].constantize.find_by_id(params[:commentable_id]])

标签: ruby-on-rails activerecord ruby-on-rails-4


【解决方案1】:

我也在寻找这个问题的答案,并想分享Launch Academy's Article on Polymorphic Associations,因为我觉得它提供了最简洁的解释。
对于您的应用程序,有两个附加选项:

1. “Ryan Bates”方法:(当您使用 Rails 的传统 RESTful URL 时)

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

2。嵌套资源:

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.单一资源:(您的实现但重复完成)

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

【讨论】:

    【解决方案2】:

    我会反其道而行之——先发表评论,然后定义可评论。

    @comment = Comment.create(params[:comment]) #this is the standard controller code for create
    @commentable = @comment.commentable
    

    【讨论】:

    • 感谢您花时间回答。此方法似乎不会将新创建的评论与任何特定的commentable 相关联。我错过了什么吗?
    • 我以为你是通过参数来做的。
    【解决方案3】:

    我接受了 Ryan Bates 的想法并对其进行了一些调整。我有一些更深层次的范围和嵌套资源。

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

    这里的想法是你从路径的末端剥离父级。

    因此,如果您的路径是 /scope/resource_a/1234/resource_b/5678/comments 等,无论您嵌套多深,您总是会获得顶级父级。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-12-04
      • 1970-01-01
      • 2010-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多