Rails:如何在模型中使用动态列/属性?

8

我有一个SaaS应用程序,用户想在用户模型上保存不同类型的信息。例如,一个账户可能想保存年龄和出生日期,但另一个账户不会使用这些列,并想要保存头发颜色和身高等信息。

这只是例子,但如何构建我的模型和数据库,以便它能够与“定制、动态”列很好地配合,而不会创建太多空属性呢?


JC,你最终在这个问题上怎么解决了? - Don Cheadle
1
@mmcrae 我最终使用了PostgreSQL的.json数据结构,并将任何自定义列都转储到这个.json数据字段中。 - kibaekr
6个回答

8

以下是两个选项: 1. NoSQL数据库。 2. Rails 4 Store 功能。


1
Rails Store 看起来非常有趣,适用于许多情况,例如您想坚持使用常规数据库和模型,并且“当您不关心能否在单个记录的上下文之外查询该存储” - 引用自文档。对我来说非常完美。 - DannyB

5

对我来说,这似乎是一个完美的例子,你需要使用无模式的NoSQL数据库。

或者(如果您想坚持使用SQL),您可以有一个基本的User模型,带有一个has_many:attributes关联。其中属性只是一个键值对的组合,包括key(如'age','birthday','hair color')和一个值。复杂性在于不同的数据类型和同时覆盖多个属性的查询。


2

2
如果您正在使用Postgresql,可以查看hstore,然后可以将信息序列化保存,并且实际上可以对这些哈希执行一些查询。顺便提一下,Rails 4已经包含了此功能,但如果您使用的是旧版本的Rails,则可以在Gemfile中包含此gem:https://github.com/diogob/activerecord-postgres-hstore,然后就可以开始玩耍了:
user = User.new
user.preferences = {
  email: "p@elh.mx",
  github: "heridev"
}

user.save!
user.reload

# Searching
User.where("preferences @> hstore(:key, :value)", key: "email", value: "p@elh.mx").first

0
我建议使用 NoSQL 数据库,它们专门针对这种情况而设计,因此您不必进行疯狂的操作来使事情正常工作。MongoDBMongoID 结合是一个非常可靠的解决方案。
唯一的缺点可能是托管,因为它往往会稍微更贵一些。

0

你的架构可能是这样的:

create_table "accounts", :force => true do |t|
  t.integer  "user_id"
  t.string   "data_key"
  t.string   "data_value"
end

账户模型

belongs_to :user    
DATA_KEYS = ['age', 'birthdate', 'hair_color', 'height' ] # etc..

用户模型

has_many :accounts
Account::DATA_KEYS.each do |method|
  # getter method
  define_method(method) do
    accounts.find_by_data_key(method).try(:data_value)
  end

  # setter method
  define_method("#{method}=") do |value|
    data = accounts.find_or_initialize_by_data_key(method)
    data.data_value = value.strip
    data.save
  end
end

您可以获取和设置帐户数据值

例如:user.age => 将返回用户的年龄

user.hair_color = 'brown' => 将设置头发颜色


如果用户属于多个账户,这段代码会有所改变吗?而且账户将选择是否支持某个数据键,并且该账户中的用户将在这些数据键上具有数据值。 - kibaekr
我遇到了这个错误:"NoMethodError: undefined method `find_by_data_key' for #User:0x00000109a7da00" - kibaekr
@kibaekr,用户模型有has_many:accounts,而find_by_data_key方法不是针对User对象的,而是针对Account模型的。 - shweta
是的,我稍微修改了你的示例,以便首先在没有帐户的情况下使其工作。这就是我所做的 https://gist.github.com/kibaekr/3225f20dbcb0858a0558 - kibaekr
@kibaekr,data_key列位于accounts表中而不是users表中。 - shweta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接