【问题标题】:How do I create a scope on an associated closure_tree model?如何在关联的closure_tree 模型上创建范围?
【发布时间】:2015-08-19 17:55:41
【问题描述】:

我有两种类型:blogsposts。 Post 使用 closure_tree gem(acts_as_tree 变体)允许帖子嵌套在帖子下。此外,每个博客has_many 发布。

class Post < ActiveRecord::Base
  acts_as_tree
end

给定一组博客(例如,由同一作者撰写),我希望将这些博客中的所有帖子作为一个范围(即,作为 ActiveRecord::Relation 而不是作为数组)。

类似:

Blog.all_posts_by('john')

到目前为止,我已经尝试了两件事:

方法#1,使用数组(不是作用域)如下:

class Blog
  has_many :posts
  def self.all_posts_by author_name
    self.where(author_name: author_name).map(&:posts).flatten.map(&:self_and_descendants).flatten
  end
end

但我想要一个范围,因为数组映射方法可能无法很好地处理大型数据集。

方法 #2:这种方法产生一个真实的范围,但使用 sql 联合和 sql 字符串:

class Blog
  has_many :posts
  def self.all_posts_by author_name 
    post_collections = []
    Blog.where(author_name: author_name).each do |blog|
      post_collections = blog.posts.map(&:self_and_descendants)
    end
    posts_sql = ""
    post_collections.each do |post_collection|
      posts_sql << "( #{post_collection.to_sql} ) union "
    end
    final_sql = posts_sql.chomp('union ')
    result = Post.from("
        (
            #{final_sql}
        ) #{Post.table_name}
    ").distinct
  end
end

这可能有效,但我正在寻找更好的方法,希望能使用一些可用的范围魔法。

【问题讨论】:

  • 所以没有赏金给我? :S
  • 对不起,没有意识到 - 认为接受的答案会自动获得赏金。现已授予。

标签: ruby-on-rails scope rails-activerecord acts-as-tree


【解决方案1】:

如果您也将blog_id 存储在嵌套帖子中,而不仅仅是在根级别帖子中,您可以执行以下操作而无需查询后代:

class Blog
  has_many :posts
  def self.all_posts_by author_name
    self.where(author_name: author_name).includes(:posts).map(&:posts).flatten
  end
end

includes 语句急切地从数据库中加载所有帖子,这比顺序加载要快得多。 http://www.spritle.com/blogs/2011/03/17/eager-loading-and-lazy-loading-in-rails-activerecord/

更新:

如果您想将它们作为范围返回,我认为最好在 Post 模型上实际使用它,因为这更有意义:

class Post
  belongs_to :blog

  def self.all_by author_name
    self.joins(:blog).where(blog: [name: author_name])
  end 
end

请注意,这仅在您为所有嵌套帖子设置 blog_id 时才有效。

如果它真的是一个高性能的应用程序,我还建议你使用像 elasticsearch 这样的搜索索引引擎,因为它在这种类型的场景中表现得非常好,即使你没有任何搜索字符串。这将允许您构建更多这样的过滤器并将它们组合起来,但它也会给应用基础架构带来更多复杂性。

【讨论】:

  • 我想要一个范围,而不是要返回的数组。这里的map...flatten 返回一个数组。
  • 更新了我的答案以反映范围。抱歉第一次看错了。
  • np。是的,这是一种解决方法,但我不能真正将博客 ID 存储在整个树中,因为它会弄乱其他东西。
  • 我想如果没有这个,如果不自己构建 SQL 联合,我就无法想到干净的方法。也许您应该考虑存储blog_id 并更好地解决其他混乱的问题,或者使用像搜索引擎这样的二级索引。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-29
  • 1970-01-01
相关资源
最近更新 更多