【问题标题】:Rails 5: Best way to iterate through a polymorphic model and find the top level parent?Rails 5:遍历多态模型并找到顶级父级的最佳方法?
【发布时间】:2017-04-01 16:58:24
【问题描述】:

编辑:为了尽可能保持透明并为将来的人们提供可行的解决方案,我想解释一下我如何使用@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

结束编辑

我正在尝试在用户的控制面板中为用户实施“最新的 cmets”。可以在Post 或另一个comment 上留下评论。

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

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

我有一个方法,我将在下面输入该方法,该方法适用于留在帖子中的 comments,但在尝试查找 commentcommentable_type: "Comment" 时会中断。

我唯一的解决方案是有一个if 声明,上面写着if commentable_type == "Comment",找到那个评论父母,抓住帖子,然后把帖子拿回给那个孩子评论并以这种方式将其推送到哈希中。

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

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

架构:

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>

【问题讨论】:

    标签: ruby-on-rails ruby postgresql activerecord ruby-on-rails-5


    【解决方案1】:

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

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

    如果您想将 cmets 嵌套得更深,这也将成为未来的证明。

    【讨论】:

    • 这对我来说是一个更好的解决方案——它将逻辑包含在它所属的模型中——但我只是喜欢三元运算符 XD
    • @John Hayes-Reed。我喜欢你面向未来的解决方案。我将如何最好地在我拥有的模型中实现它?
    • 没关系。我能够让它工作@John Hayes-Reed,谢谢!
    • @Antonio 我目前无法测试它,但我认为如果您将上述方法添加到您的评论模型中,然后在您的 self.find_all_user_cmets 方法中将 post = Post.find(co.commentable_id) 更改为post = co.find_parent_post 应该准备好了?或类似的东西!
    • 太棒了!这样我们可以:@commentable.find_parent_post if @commentable.is_a?(Comment) & @commentable unless @commentable.is_a?(Comment)
    【解决方案2】:

    嗯,一个可以找到该帖子的班轮可能是:

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

    【讨论】:

    • 感谢您的意见,我喜欢这个想法,而且我没有尽可能多地使用三元。我最终选择了其他解决方案,但感谢您的帮助!
    猜你喜欢
    • 2017-06-20
    • 1970-01-01
    • 2021-07-15
    • 1970-01-01
    • 2020-10-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-25
    • 2015-10-08
    相关资源
    最近更新 更多