如何使用 "as_json" Active Record 方法限制 rails 控制台中的关联集合?

How to limit an association collection in rails console with "as_json" Active Record methods?

我想在 rails 控制台中显示父实体“文章”的限制集合(4 级),这将是其自身与示例之间的关系:

# article.rb

class Article < ActiveRecord::Base
 belongs_to :parent, :class_name => 'Article', optional: true
 has_many :sub_articles, :class_name => 'Article', :foreign_key => 'parent_id'
end

def as_json(options={})
  super(methods: [:subarticles])
end

其中 as_json (ActiveRecord) 方法被覆盖以显示关系中的递归,例如:

 # rails console
 
  Article.first.as_json
  =>
  id: 1,
    name: "king article"
    created_at: Fri, 13 Aug 2021 13:14:26.463429000 UTC +00:00,
    updated_at: Fri, 13 Aug 2021 13:14:26.463429000 UTC +00:00,
    parent_id: nil
    sub_articles:
    [ Article:0x0000641428defb71
    id: 2,
      name: "pencils article"
      created_at: Fri, 13 Aug 2021 13:14:26.463429000 UTC +00:00,
      updated_at: Fri, 13 Aug 2021 13:14:26.463429000 UTC +00:00,
      parent_id: 1
      sub_articles:
        [ Article:0x0000621438defb71
        id: 3,
        name: "pencil child 1"
        created_at: Fri, 13 Aug 2021 13:14:26.463429000 UTC +00:00,
        updated_at: Fri, 13 Aug 2021 13:14:26.463429000 UTC +00:00,
        parent_id: 2
        sub_articles: [],

这还可以进一步扩展,但我想将子文章扩展到 4 个级别...到这样的程度,如果父亲有一个曾曾孙子 (sub_articles) 无法显示

# in article.rb

def as_json(options={})
  super(methods: [:limited_hierarchy])
end

def level_in_hierarchy
  return 0 if parent_id.nil?
  return 1 if parent.parent_id.nil?
  return 2 if parent.parent.parent_id.nil?
  return 3 if parent.parent.parent.parent_id.nil?
  # ... etc
end

def limited_hierarchy
  return sub_articles if level_in_hierarchy < 4
  []
end

应该可以工作,可以重构 level_in_hierarchy 方法以提高其性能,但为了便于阅读,我保留了这种方式。我们只对 level_in_hierarchy 是否 < 4 感兴趣,因此没有必要计算所有级别的值。

根据应用程序中的文章数量,在创建模型时将 level_in_hierarchy 的值设置为 Article 模型中的属性可能是更好的选择。这将提高性能。

我认为稍微调整 Les Nightingill 的答案就可以达到你想要的效果。 添加 attr_accesstor :level_in_hierarchy:

# in article.rb
attr_accesstor :level_in_hierarchy

def as_json(options={})
  super(methods: [:limited_hierarchy])
end

def limited_hierarchy
  level_in_hierarchy ||= 0
  if level_in_hierarchy < 4
    sub_articles.each { |sub_a| sub_a.level_in_hierarchy = level_in_hierarchy + 1 }
    sub_articles 
  else
    []
  end
end