动态字段的实现取决于以下因素:
- 能够动态添加属性
- 支持新数据类型的能力
- 无需额外查询即可检索动态属性
- 能够访问像常规属性一样的动态属性
- 能力根据动态属性查询对象。(例如:找到有滑雪爱好的用户)
通常,解决方案不能满足所有要求。Mike 的解决方案优雅地解决了 1 和 5。如果 1 和 5 对您很重要,您应该使用他的解决方案。
这是一个解决 1、2、3、4 和 5 的长解决方案
更新users
表格
添加一个text
名为meta
users 表的字段。
更新您的User
模型
class User < ActiveRecord::Base
serialize :meta, Hash
def after_initialize
self.meta ||= {} if new_record?
end
end
添加新的元字段
u = User.first
u.meta[:hobbies] = "skiing"
u.save
访问元字段
puts "hobbies=#{u.meta[:hobbies]}"
迭代元字段
u.meta.each do |k, v|
puts "#{k}=#{v}"
end
要解决第 5 个要求,您需要使用 Solr 或 Sphinx 全文搜索引擎。它们比依赖数据库进行LIKE
查询更有效。
如果您通过 Sunspot gem 使用 Solr,这是一种方法。
class User
searchable do
integer(:user_id, :using => :id)
meta.each do |key, value|
t = solr_type(value)
send(t, key.to_sym) {value} if t
end
end
def solr_type(value)
return nil if value.nil?
return :integer if value.is_a?(Fixnum)
return :float if value.is_a?(Float)
return :string if value.is_a?(String)
return :date if value.is_a?(Date)
return :time if value.is_a?(Time)
end
def similar_users(*args)
keys = args.empty? ? meta.keys : [args].flatten.compact
User.search do
without(:user_id, id)
any_of do
keys.each do |key|
value = meta[key]
with(key, value) if value
end
and
end
end
end
查找相似用户
u = User.first
u.similar_users # matching any one of the meta fields
u.similar_users :hobbies # with matching hobbies
u.similar_users :hobbies, :city # with matching hobbies or the same city
这里的性能提升是显着的。