我是 Ruby on Rails 的新手(这可能很快就会变得显而易见),我正在尝试找出适用于以下数据场景的模型。我读过几篇文章并在 Google 上进行了详细搜索,但我仍然很困惑。
我有 5 个不同的表,它们具有相同的列,但 value
列具有不同的数据类型。出于各种充分的原因,他们的数据位于 5 个单独的表中,但可以将其视为跨多个表分片的数据。
logbook_strings (user_id, entry_id, field_id, value)
logbook_booleans (user_id, entry_id, field_id, value)
logbook_integers (user_id, entry_id, field_id, value)
logbook_decimals (user_id, entry_id, field_id, value)
logbook_datetimes (user_id, entry_id, field_id, value)
数据如下所示:
------------------------------------------------
| user_id | entry_id | field_id | value |
------------------------------------------------
| 1 | alpha1 | date | 2012-11-14 |
| 1 | alpha1 | duration | 1.2 |
| 1 | alpha1 | remarks | Nice job. |
------------------------------------------------
| 1 | alpha2 | date | 2012-11-13 |
| 1 | alpha2 | duration | 2.7 |
| 1 | alpha2 | remarks | Bad job. |
------------------------------------------------
条目 alpha1:
2012-11-14, 1.2, 干得好。
条目 alpha2:
2012-11-13, 2.7, 干得不好。
等等
我这样做的原因是为了我可以拥有一个无限灵活的数据库。我可以随时添加新的 field_id
来向我的应用添加新字段/功能,而不是进行架构更新来向宽日志表中添加另一列。
所以我想知道,有没有一种方法可以让我拥有一个可以引用所有 5 个表的 ActiveRecord 模型?
最佳答案
花了几分钟尝试将其硬塞到单个 ActiveRecord 类中后,我认为使用 ActiveRecord 来完成这样的事情并不是一个好主意。我看到几个选项:
- 推出您自己的模型。这种方法的最大缺点是您会失去 ActiveRecord 的许多优秀功能。但如果您的数据相对简单(没有很多关联等),那么这可能是一个可行的选择。
- 重组您的数据。如果此架构/数据是预先存在的或由于某种原因必须与移动应用程序的架构匹配,则这可能不是一个选项。但是,如果您是新手,Rails 的迁移使得随心所欲地添加/删除列变得非常容易且非常安全,因此我可能会考虑使用更传统的方法。虽然这看起来并不理想,但为了获得 ActiveRecord 的诸多好处,需要认真考虑这一点。
如果您必须保留架构,为每个日志表创建单独的模型可能是您的最佳选择。
# Migrations
create_table :logbook do |t|
# Default fields, nothing special
end
create_table :logbook_integers do |t|
t.integer :logbook_id # You'd probably want to index this as well
t.string :name
t.integer :value
end
create_table :logbook_strings do |t|
t.integer :logbook_id # You'd probably want to index this as well
t.string :name
t.string :value
end
# etc...
# Models
class Logbook < ActiveRecord::Base
has_many :logbook_integers
has_many :logbook_strings
# etc...
def remarks
self.logbook_strings.find_by_name("remarks").value
end
def remarks= newValue
remark = self.logbook_strings.find_or_create_by_name("remarks")
remark.value = newValue
remark.save
end
# etc...
end
class LogbookInteger < ActiveRecord::Base
belongs_to :logbook
end
class LogbookString < ActiveRecord::Base
belongs_to :logbook
end
# etc...
# Usage
logbook = Logbook.new
logbook.remarks = "Hi"
logbook.duration = 2
logbook.remarks # => Hi
logbook.duration # => 2
如果您可以稍微更改架构,这里有一个选项:
您可以使用serialize
类方法described here (cmd+f 表示“序列化”)来存储您的条目,因此您只需两个:Logbook
和 LogbookField
,而不是拥有许多模型。它可能看起来像这样:
# Migration for logbook_fields
create_table :logbook_fields do |t|
t.string :name
t.string :value
end
# Models
class Logbook
has_many :logbook_fields
def self.build_with_default_fields
self.logbook_fields.create name: "date"
self.logbook_fields.create name: "duration"
# etc...
end
# You could probably do some cool Ruby metaprogramming to create all these
# accessors/setters for you, btw.
def date
self.logbook_fields.find_by_name "date"
end
def date= newValue
field = self.logbook_fields.find_by_name "date"
field.value = newValue
field.save
end
def duration
self.logbook_fields.find_by_name "duration"
end
def duration= newValue
field = self.logbook_fields.find_by_name "duration"
field.value = newValue
field.save
end
# etc...
end
class LogbookField
serialize :value
belongs_to :logbook
end
# Usage
logbook = Logbook.build_with_default_fields
logbook.date = DateTime.now
logbook.duration = 2.7
有类似的效果。这样,您就可以保留大部分 ActiveRecord 的优点,同时仍然保持模式设计的一些“无限性”。然而,通过迁移在单个表上添加/删除列可能会比这更容易。同样,这取决于您的架构是否灵活。希望这会有所帮助。
关于ruby-on-rails - Rails 中的分片表合并为单个 ActiveRecord 模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13391525/