3

如果我们有一个包含相对静态数据的小表,是否可以让 Active Record 在应用程序启动时加载它,而不必为这些数据访问数据库?

请注意,理想情况下,我希望这些数据可以与与其有关系的其他模型连接。

一个示例可能是带有电话号码前缀的国家/地区列表 - 此列表不太可能更改,如果更改,管理员将更改它。其他表可能与此有关系(例如,给定一个引用国家/地区的用户,我们可能想要查找国家/地区电话前缀)。

我在这里看到了一个类似的问题,但它已有 6 年历史,指的是 Rails 2,而我正在使用 Rails 5,也许从那时起就引入了一些东西。

首选的解决方案是:

  1. 内置 Rails / ActiveRecord 功能可在启动时加载表一次,如果随后加载与缓存表有关系的其他记录,则自动链接到缓存对象(即在某处手动缓存 MyModel.all 是不够的,因为仍然会通过查询数据库来加载关系)。
  2. 维护的库执行上述操作。
  3. 如果两者都不可用,我想另一种方法是将静态数据集定义为内存中的枚举/哈希或类似的,并将哈希键保留在与该数据有关系的记录上,并在这些模型上定义方法以使用数据库中持久化的键使用散列中的对象进行查找。虽然这似乎很手动......

[编辑] 潜在解决方案要考虑的另一件事 - 手动解决方案 (3) 还需要自定义控制器和路由,以便可以通过 API 访问此类数据。理想情况下,最好有一个解决方案,如果需要,可以通过 RESTful API(只读 - 只是 GET)提供此类数据,使用标准 Rails 机制(如 Scaffolding),而无需太多人工干预。

4

1 回答 1

2

我认为您可能过快地低估了“简单”/“手动”方法。

将数据写入红宝石散列/数组并不是一个坏主意。

如果你想使用 CRUD 脚手架,为什么不直接使用标准的 Rails 模型/控制器生成器呢?在数据库中存储一些静态数据真的有那么糟糕吗?

第三种选择是将您的数据以某种序列化格式存储到文件中,然后在您的应用程序加载时读取它并构造 ActiveRecord 对象。让我举个例子:

数据.yml

---
- a: "1"
  b: "1"
- a: "2"
  b: "2"

这是一个包含哈希数组的 YAML 文件;您可以使用以下命令构建这样的文件:

require 'yaml'
File.open("path.yml", "w") do |f|
  data = [
    { "a" => "1", "b" => 1 },
    { "a" => "2", "b" => 2 }
  ]
  f.write(YAML.dump(data))
end

然后要加载数据,您可以在其中创建一个文件config/initializers/(这里的所有内容都将由 rails 自动加载):

配置/初始化程序/static_data.rb

require 'yaml'

# define a constant that can be used by the rest of the app
StaticData = YAML.load(File.read("data.yml")).map do |object|
  MyObjectClass.new(object)
end

为了避免必须为MyObjectClass(当它实际上没有存储在数据库中时)编写数据库迁移,您可以使用attr_accessor属性的定义:

class MyObjectClass < ActiveRecord::Base
  # say these are your two columns
  attr_accessor :a, :b
end

只需确保不要在此模型上运行 , 或 之类的东西savedelete除非update您对这些方法进行猴子补丁)。

如果您想拥有 REST / CRUD 端点,则需要从头开始编写它们,因为现在更改数据的方式不同。您基本上需要在 3 步过程中进行任何更新:

  1. 将 YAML 中的数据加载到 Ruby 对象列表中
  2. 更改 Ruby 对象列表
  3. 将所有内容序列化为 YAML 并保存。

所以你可以看到你在这里并没有真正做增量更新。你可以使用 JSON 而不是 YAML,你也会遇到同样的问题。使用 Ruby 的内置存储系统 PStore,您将能够逐个更新对象,但是将 SQL 用于生产 Web 应用程序是一个更好的主意,并且老实说会使事情变得更简单。

除了这些“序列化数据”选项之外,还有 key-val 存储服务器将数据存储在内存中。像 Memcached 和 Redis 这样的东西。

但回到我之前的观点,除非你有充分的理由不使用 SQL,否则只会让事情变得更加困难。

于 2016-09-16T22:07:23.070 回答