在Rails中,在模型中存储多个布尔属性的最佳方法是什么?

时间:2010-09-09 23:03:45

标签: ruby-on-rails

我有一个模型House,它有许多布尔属性,例如has_fireplacehas_basementhas_garage等等。 House有大约30个这样的布尔属性。构建此模型以实现高效数据库存储和搜索的最佳方法是什么?

我想最终搜索所有有壁炉和车库的Houses

我想,天真的方法是在模型中添加30个布尔属性,每个属性对应一个数据库中的一列,但我很好奇是否有一个我不知道的Rails最佳实践。

8 个答案:

答案 0 :(得分:16)

您的'天真'假设是正确的 - 从查询速度和生产力角度来看,最有效的方法是为每个标志添加一列。

你可能会像其他人所描述的那样获得幻想,但除非你解决一些非常具体的性能问题,否则不值得付出努力。你最终会得到一个难以维护,灵活性降低且开发时间更长的系统。

答案 1 :(得分:7)

对于单个模型中的许多布尔值,您可以考虑使用单个整数和按位运算来表示,存储和检索值。例如:

class Model < ActveRecord::Base
  HAS_FIREPLACE = (1 << 0)
  HAS_BASEMENT  = (1 << 1)
  HAS_GARAGE    = (1 << 2)

  ...
end

然后,一些名为flags的模型属性将设置如下:

flags |= HAS_FIREPLACE
flags |= (HAS_BASEMENT | HAS_GARAGE)

并进行了如下测试:

flags & HAS_FIREPLACE
flags & (HAS_BASEMENT | HAS_GARAGE)

你可以抽象成方法。应该在时间和空间上非常有效地作为实现

答案 2 :(得分:5)

我建议the flag_shih_tzu gem。它可以帮助您在一个整数列中存储许多布尔属性。它为每个属性提供了命名范围,并将它们链接在一起作为活动记录关系。

答案 3 :(得分:4)

这是另一种解决方案。

您可以制作HouseAttributes模型并设置双向has_and_belongs_to_many关联

# house.rb
class House
  has_and_belongs_to_many :house_attributes
end

# house_attribute.rb
class HouseAttribute
  has_and_belongs_to_many :houses
end

然后房子的每个属性都是数据库条目。

不要忘记在数据库上设置连接表。

答案 4 :(得分:3)

如果您想要查询这些属性,那么很遗憾,如果考虑性能,您可能会遇到一流的字段。位域和标志字符串是解决问题的简单方法,但它们不能很好地适应生产数据集。

如果你不打算担心性能,那么我会使用一个实现,其中每个属性由一个字符(“a”=“车库”,“b”=“壁炉”等)表示,并且你只需要构建一个表示记录所有标志的字符串。这比bitfield的主要优点是:a)人类更容易调试,b)你不必担心数据类型的大小。

如果表现是一个问题,那么你可能需要将它们推广到一流的领域。

答案 5 :(得分:2)

通常我同意你天真的假设是正确的。

如果布尔字段的数量不断增长和增长(has_fusion_reactor?),您也可以考虑serializing一个标志数组

# house.rb
class House
  serialize :flags
  …
end

# Setting flags
@house.flags = [:fireplace, :pool, :doghouse]
# Appending
@house.flags << :sauna
#Querying
@house.flags.has_key? :porch
#Searching
House.where "flags LIKE ?", "pool"

答案 6 :(得分:1)

我正在考虑这样的事情

你有一张房子表(有关房子的详细信息)

你有另一个名为Features的主表(它具有'壁炉','地下室'等功能。)

你有一个像Houses_Features这样的连接表 它有house_id和feature_id

通过这种方式,您可以为给定的房屋分配功能。不知道这是否符合你的需要,但只要想一想:D

感谢和问候

sameera

答案 7 :(得分:0)

你总是可以拥有一个包含JSON的TEXT列(比如data),然后你的查询可以使用SQL的LIKE。

例如:house.data#=&gt; '{ “has_fireplace”:真 “has_basement”:假 “has_garage”:真}'

因此,使用LIKE '%"has_fireplace":true%'进行查找会返回任何带壁炉的内容。

在这种情况下,使用模型关系(例如,除了House之外的Fireplace,Basement和Garage的模型)会非常麻烦,因为你有这么多模型。