Rails 5:迭代多态模型并找到顶级父级的最佳方法?

Rails 5: Best way to iterate through a polymorphic model and find the top level parent?

编辑:为了尽可能保持透明并为将来的人们提供可行的解决方案,我想解释一下我是如何使用@John Hayes-Reed 的回答来解决我的问题的。我将在下面更新方法和模型。

更新方法:

#User.rb
def self.find_all_user_comments(user)
  @comment_hash = []
  @user_comments = Comment.where(user_id: user.id)
  @user_comments.all.each do |co|
     post = co.find_parent_post
    @comment_hash.push( { comment: co, post: post} )
  end
  @comment_hash
end

我从下面的答案中得到的新方法:

#comment.rb
def find_parent_post
  return self.commentable if self.commentable.is_a?(Post)
  self.commentable.find_parent_post
end

我调用方法的控制器:

#users_controller.rb
def control_panel
  @comments = User.find_all_user_comments(current_user)
end

结束编辑

我正在尝试在他们的控制面板中为用户实施 "most recent comments"。可以在 Post 或另一个 comment.

上留下评论

在我看来,我想显示 comment:body 以及通过哈希创建的 post。这也适用于 comments comment。幸运的是,评论只能像这样深入两层

Post
  Comment
    Child Comment # Would like to find the parent post.
    Child Comment
  Comment

我有一个方法,我将在下面输入,它适用于留在 post 上的 comment,但在尝试找到 comment 时会中断有一个 commentable_type: "Comment".

我唯一的解决办法是有一个 if 声明说 if commentable_type == "Comment",找到 那个 评论父,抓住 Post,然后取 Post` 并将其带回那个子评论,然后以这种方式将其推入哈希。

我想知道是否有更有效的方法(AR 或 SQL)来做这样的事情,以便最终我可以找到 comment 的父级 Post 即使它是 commentcomment

以下是我认为有帮助的所有信息:

架构:

create_table "comments", force: :cascade do |t|
  t.text     "body"
  t.datetime "created_at",       null: false
  t.datetime "updated_at",       null: false
  t.integer  "commentable_id"
  t.string   "commentable_type"
  t.integer  "user_id"
end

create_table "forums", force: :cascade do |t|
  t.string   "name"
  t.text     "description"
  t.integer  "user_id"
  t.datetime "created_at",  null: false
  t.datetime "updated_at",  null: false
  t.index ["user_id"], name: "index_forums_on_user_id", using: :btree
end

create_table "posts", force: :cascade do |t|
  t.string   "title"
  t.text     "description"
  t.integer  "user_id"
  t.integer  "forum_id"
  t.datetime "created_at",  null: false
  t.datetime "updated_at",  null: false
  t.index ["forum_id"], name: "index_posts_on_forum_id", using: :btree
  t.index ["user_id"], name: "index_posts_on_user_id", using: :btree
end

...User table omitted for brevity...

型号:

#post model
belongs_to :user
belongs_to :forum

has_many :comments, as: :commentable

#comment model
belongs_to :user
belongs_to :commentable, polymorphic: true
has_many :comments, as: :commentable

现在的方法。当它找到 commentable_type: "Comment":

的评论时不会工作
  def self.find_all_user_comments(user)
    @comment_hash = []
    @user_comments = Comment.where(user_id: user.id)
    @user_comments.all.each do |co|
      post = Post.find(co.commentable_id)
      @comment_hash.push( { comment: co, post: post} )
    end
    @comment_hash
  end

查看:

<div class="col-md-10 col-md-offset-1">
<h3>Recent comments:</h3>
  <% if @comments.any? %>
  <table class="table">
    <thead>
      <tr>
        <th>Comment</th>
        <th>Post</th>
        <th>Actions</th>
      </tr>
    </thead>
    <tbody>
        <% @comments.each do |co| %>
        <tr class="comment-<%= co[:comment].id %>">
          <td><%= truncate(co[:comment].body, length: 50) %></td>
          <td><%= truncate(co[:post].title, length: 50) %></td>
          <td><%= link_to "destroy", comment_path(co[:comment]), remote: true, method: :delete, data: {confirm: "Are you sure you want to delete this comment?"} %></td>
        </tr>
        <% end %>
    </tbody>
  </table>
  <% end %>
</div>

嗯,找到 post 的一个可能的班轮可能是:

post = (comment.commentable.is_a? Post) ? comment.commentable : comment.commentable.commentable

您可以在您的评论中添加一个方法 class,并使用一些递归来完成工作(从技术上讲不是真正的递归,因为它在第二个实例上调用该方法,但我们可以使用一个类似的概念),大致如下:

def find_parent_post
    return self.commentable if self.commentable.is_a?(Post)
    self.commentable.find_parent_post
end

如果您想更深入地嵌套评论,这也将成为未来的证明。