我是Ruby on Rails的新手(可能很快就会显而易见),我正在尝试找出以下数据场景的模型。我已经阅读了几篇帖子,并对谷歌进行了长时间的搜索,但我仍感到困惑。
除了value
列有不同的数据类型之外,我有5个不同的列具有相同的列。由于各种原因,他们将数据放在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
来为我的应用添加新字段/功能,而不是进行架构更新,以便将另一列添加到宽日志表中。
所以我想知道,有没有一种方法可以让我有一个ActiveRecord模型,我可以在其中引用所有这5个表?
答案 0 :(得分:1)
在花了几分钟试图将其变成单个ActiveRecord类后,我认为使用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细节,同时仍然保持架构设计的一些“无限”。但是,使用迁移在单个表上添加/删除列可能比这更容易。同样,这取决于您是否可以灵活地使用模式。希望这会有所帮助。
答案 1 :(得分:1)
我认为你应该有一个带有类型列的表。
前:
logbook(user_id, entry_id, field_id, value, value_type)
值类型将是
strings
booleans
integers
decimals
datetimes
示例
-----------------------------------------------------------
| user_id | entry_id | field_id | value |value_type |
-----------------------------------------------------------
| 1 | alpha1 | date | 2012-11-14 | datetime
| 1 | alpha1 | duration | 1.2 | decimal
| 1 | alpha1 | remarks | Nice job. | string
所以基本上值列将是字符串,从模型中你可以决定你想要的值类型,你的模型将是
class Logbook < ActiveRecord::Base
#sample method
#just to give an idea how you could use the same value
#with different times
def multiple_duration_by_two
self.value * 2 if self.value_type == "decimal"
end
end
但是,根据您的要求,此实现可能需要tweek,但我想您明白了
HTH