我不能很容易地在上面找到相关的主题,所以我们开始-一个经典的问题:我有一个用户或人物模型,我想要模拟这个人的物理属性/属性(眼睛颜色,头发颜色,肤色,性别,一些生活方式属性,如每晚睡眠时间(<8小时,~8小时,>8小时),吸烟,每日日照等。
我通常通过为每个属性创建一个单独的rails模型(数据库表)来解决这个问题,因为这样很容易在以后添加更多选项,编辑它们,用作<select>的源。
class Person
belongs_to :eye_color
belongs_to :skin_color
belongs_to :hair_color
belongs_to :sleep_per_night
belongs_to :sun_exposure
attr_accessible :gender # boolean, m/f
end
class HairColor
has_many :people
attr_accessible :value
end
class EyeColor
has_many :people
attr_accessible :value
end
Person.last.eye_color
...
EyeColor.first.people但是,如果有很多这样的属性(即10-15种不同的生理和生活方式属性),该怎么办?对我来说,这似乎打破了规则,也就是说,我剩下了许多小表,比如eye_colors,它有3-5条记录。这些表中的每个表只有一个有意义的列值。
我在想你们是如何解决这些问题的,可能是通过创建一个单一的模型,即具有以下结构的PersonProperty
person_properties[type, value]因此,前面使用不同模型的解决方案,即eye_color和hair_color,将如下所示(类型/类和值):
# PersonProperty/person_properties:
1. type: 'HairColor', value: 'red'
2. type: 'HairColor', value: 'blond'
3. type: 'SkinColor', value: 'white'
4. type: 'EyeColor', value: 'green'
5. type: 'HairColor', value: 'black'
6. type: 'SkinColor', value: 'yellow'
7. type: 'SleepPerNight', value: 'less than 8h'
8. type: 'SleepPerNight', value: 'more than 8h'
9. type: 'DailySunExposure', value: 'more than 1h'
...
19. type: 'EyeColor', value: 'blue'
...通过将PersonProperty模型一分为二,上面的示例可能会更规范化。或者你有其他的建议?
发布于 2013-04-08 22:15:55
在这种情况下,我不建议使用has_one关系。用户可以belongs_to :eye_color,所以你可以在你的用户之间映射眼睛的颜色。一个EyeColor has_many :users,这样您就可以执行@eye_color.users并获得具有特定EyeColor的所有用户。否则,您将不得不为每个用户(或者至少是那些有眼睛的用户)创建一个EyeColor。
相对于您的PersonProperty解决方案,我建议这样做的原因是它更易于维护,而且将这些类型的关系委托给您的数据库会带来性能上的提升。
更新:如果你想要动态属性,我建议你这样设置你的模型:
class Person < ActiveRecord::Base
has_many :person_attributes
attr_accessible :gender
accepts_nested_attributes_for :person_attributes
end
class PersonAttribute < ActiveRecord::Base
belongs_to :person_attribute_type
belongs_to :person_attribute_value
belongs_to :person
attr_accessible :person_id, :person_attribute_value_id
end
class PersonAttributeValue < ActiveRecord::Base
has_many :person_attributes
belongs_to :person_attribute_type
attr_accessible :value, :person_attribute_type_id
end
class PersonAttributeType < ActiveRecord::Base
has_many :person_attribute_values
attr_accessible :name, :type
end通过这种方式,您可以执行以下操作:
@person_attribute_type = PersonAttributeType.create(:name => 'Eye color', :type => 'string')
['green', 'blue', 'brown'].each do |color|
@person_attribute_type.person_attribute.values.build(:value => color)
end
@person_attribute_type.save
@person = Person.new
@person_attribute = @person.person_attributes.build
@person_attribute.person_attribute_value = @person_attribute_type.person_attribute_values.find(:value => 'green')当然,您可能不会通过命令行填充数据库。您可能会非常好奇这在表单中是如何工作的:
class PersonController
# ...
def new
@person = Person.new
PersonAttributeType.all.each do |type|
@person.person_attributes.build(:person_attribute_type = type)
end
end
def create
@person = Person.new(params[:person])
if @person.save
# ...
else
# ...
end
end
def edit
@person = Person.find(params[:id])
PersonAttributeType.where('id NOT IN (?)', @person.person_attributes.map(&:person_attribute_type_id)).each do |type|
@person.person_attributes.build(:person_attribute_type = type)
end
end
# ...现在,表单基于Formtastic:
semantic_form_for @person do |f|
f.input :gender, :as => :select, :collection => ['Male', 'Female']
f.semantic_fields_for :person_attributes do |paf|
f.input :person_attribute_value, :as => :select, :collection => paf.object.person_attribute_type.person_attributes_values, :label => paf.object.person_attribute_type.name
end
f.buttons
end请注意,这一切都是未经测试的,所以请尝试理解我在这里试图做的事情。
顺便说一句,我现在意识到类名PersonAttribute可能有点不走运,因为你必须accepts_nested_attributes_for :person_attributes,这意味着你将不得不attr_accessible :person_attributes_attributes__,但我希望你能理解我的意思。
https://stackoverflow.com/questions/15879398
复制相似问题