【问题标题】:Ruby on Rails API: computed attribute pattern best practiceRuby on Rails API:计算属性模式最佳实践
【发布时间】:2020-10-09 17:59:53
【问题描述】:

当我需要一个需要调用数据库的计算属性时,我想知道最佳实践。

如果我有一个Parent 有很多Child,我将如何在ParentController#index 中渲染children_count 属性,因为我不想渲染孩子,只是计数?最好的方法是什么?

谢谢!

型号:

class Parent < ApplicationRecord
  has_many :children

  def children_count
    children.count # Wouldn't it ask the database when I call this method?
  end
end

控制器:

class ParentsController < ApplicationController
  def index
    parents = Parent.all

    render json: parents, only: %i[attr1, attr2] # How do I pass children_count?
  end
end

【问题讨论】:

  • 也许你想调整这个问题,如果它真的是关于计数器缓存的。否则,适用其他解决方案。

标签: ruby-on-rails design-patterns ruby-on-rails-6


【解决方案1】:

在这种情况下避免额外数据库查询的 Rails 方法是实现counter cache

为此改变

belongs_to :parent

child.rb

belongs_to :parent, counter_cache: true

然后将一个名为 children_count 的整数列添加到您的 parents 数据库表中。当您的数据库中已经有记录时,您应该运行类似

Parent.ids.each { |id| Parent.reset_counters(id) }

用正确数量的现有记录填充children_count(例如在您添加新列的迁移中)。

完成这些准备后,Rails 会在您添加或删除子项时自动增加和减少计数。

因为children_count 数据库列的处理方式与所有其他属性一样,您必须从Parent 类中删除自定义children_count 方法,并且仍然可以简单调用

<%= parent.children_count %> 

在你看来。或者,您可以将其添加到要以 JSON 形式返回的属性列表中:

render json: parents, only: %i[attr1 attr2 children_count]

【讨论】:

    【解决方案2】:

    children.count 会调用数据库,是的;但是,它将作为 SQL 计数来执行:

    SELECT COUNT(*) FROM "children" WHERE "children"."parent_id" = $1
    
    

    它实际上并没有加载所有子记录。一种更有效的方法是针对这种特定情况使用 Rails counter_cache:https://guides.rubyonrails.org/association_basics.html#options-for-belongs-to-counter-cache

    【讨论】:

      猜你喜欢
      • 2010-09-08
      • 2011-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多