在 Rails 中建模可覆盖设置
Modeling overridable settings in Rails
我正在尝试找出对某些东西进行建模的最佳方法,但还没有找到太多有用的方法。
我的应用程序有一种报告层次结构。用户是组织的一部分,而组织又是帐户的一部分。
我正在尝试找出正确的建模方法 "Settings"。因此,给定帐户可以默认设置下所有帐户的设置值。可以在组织级别覆盖这些默认值,用户可以进一步覆盖它们。
到目前为止,我只是通过将每条记录映射到适当的父记录(用户、帐户、组织)来处理这个问题,但是在查询中需要做很多工作才能将它们全部组合起来并获得最终的确定设置列表。
对处理这个问题的正确方法有什么想法吗?
我的主要想法:
- 将设置表示为基于 Ruby 的
Hash
的树
- 使用 JSON 数据库类型存储设置(
jsonb
作为 PostgreSQL 示例)
- 使用 Active Support 的
Hash#deep_merge
覆盖设置
示例:
class User < ApplicationRecord
belongs_to :organization
# settings | jsonb | not null default '{}'::jsonb
# ...
class Organization < ApplicationRecord
belongs_to :account
# settings | jsonb | not null default '{}'::jsonb
# ...
class Account < ApplicationRecord
# settings | jsonb | not null default '{}'::jsonb
# ...
然后
class Settings
cattr_reader :global_settings do
# hash = ... read global settings somehow
hash.freeze # prevent global settings from changes
end
def self.settings_for(user_id)
User
.joins(organization: :account)
.where(id: user_id)
.limit(1)
.pluck(*%w[ accounts.settings organizations.settings users.settings ])
.first
.reduce(global_settings){ |memo, e| memo.deep_merge(e) }
# or
# .each_with_object(global_settings.dup){ |e, memo| memo.deep_merge!(e) }
end
# ...
Settings.settings_for(111)
它需要一个快速的数据库查询(deep_merge
<< 数据库查询),前端喜欢处理JSON。所以它会起作用。至少是开始。
我正在尝试找出对某些东西进行建模的最佳方法,但还没有找到太多有用的方法。
我的应用程序有一种报告层次结构。用户是组织的一部分,而组织又是帐户的一部分。
我正在尝试找出正确的建模方法 "Settings"。因此,给定帐户可以默认设置下所有帐户的设置值。可以在组织级别覆盖这些默认值,用户可以进一步覆盖它们。
到目前为止,我只是通过将每条记录映射到适当的父记录(用户、帐户、组织)来处理这个问题,但是在查询中需要做很多工作才能将它们全部组合起来并获得最终的确定设置列表。
对处理这个问题的正确方法有什么想法吗?
我的主要想法:
- 将设置表示为基于 Ruby 的
Hash
的树
- 使用 JSON 数据库类型存储设置(
jsonb
作为 PostgreSQL 示例) - 使用 Active Support 的
Hash#deep_merge
覆盖设置
示例:
class User < ApplicationRecord
belongs_to :organization
# settings | jsonb | not null default '{}'::jsonb
# ...
class Organization < ApplicationRecord
belongs_to :account
# settings | jsonb | not null default '{}'::jsonb
# ...
class Account < ApplicationRecord
# settings | jsonb | not null default '{}'::jsonb
# ...
然后
class Settings
cattr_reader :global_settings do
# hash = ... read global settings somehow
hash.freeze # prevent global settings from changes
end
def self.settings_for(user_id)
User
.joins(organization: :account)
.where(id: user_id)
.limit(1)
.pluck(*%w[ accounts.settings organizations.settings users.settings ])
.first
.reduce(global_settings){ |memo, e| memo.deep_merge(e) }
# or
# .each_with_object(global_settings.dup){ |e, memo| memo.deep_merge!(e) }
end
# ...
Settings.settings_for(111)
它需要一个快速的数据库查询(deep_merge
<< 数据库查询),前端喜欢处理JSON。所以它会起作用。至少是开始。