首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >模型人员(用户)配置文件属性/属性-最佳实践、静态属性与动态属性

模型人员(用户)配置文件属性/属性-最佳实践、静态属性与动态属性
EN

Stack Overflow用户
提问于 2013-04-08 20:45:24
回答 1查看 519关注 0票数 0

我不能很容易地在上面找到相关的主题,所以我们开始-一个经典的问题:我有一个用户或人物模型,我想要模拟这个人的物理属性/属性(眼睛颜色,头发颜色,肤色,性别,一些生活方式属性,如每晚睡眠时间(<8小时,~8小时,>8小时),吸烟,每日日照等。

我通常通过为每个属性创建一个单独的rails模型(数据库表)来解决这个问题,因为这样很容易在以后添加更多选项,编辑它们,用作<select>的源。

代码语言:javascript
复制
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

代码语言:javascript
复制
person_properties[type, value]

因此,前面使用不同模型的解决方案,即eye_color和hair_color,将如下所示(类型/类和值):

代码语言:javascript
复制
# 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模型一分为二,上面的示例可能会更规范化。或者你有其他的建议?

EN

回答 1

Stack Overflow用户

发布于 2013-04-08 22:15:55

在这种情况下,我不建议使用has_one关系。用户可以belongs_to :eye_color,所以你可以在你的用户之间映射眼睛的颜色。一个EyeColor has_many :users,这样您就可以执行@eye_color.users并获得具有特定EyeColor的所有用户。否则,您将不得不为每个用户(或者至少是那些有眼睛的用户)创建一个EyeColor。

相对于您的PersonProperty解决方案,我建议这样做的原因是它更易于维护,而且将这些类型的关系委托给您的数据库会带来性能上的提升。

更新:如果你想要动态属性,我建议你这样设置你的模型:

代码语言:javascript
复制
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

通过这种方式,您可以执行以下操作:

代码语言:javascript
复制
@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')

当然,您可能不会通过命令行填充数据库。您可能会非常好奇这在表单中是如何工作的:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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__,但我希望你能理解我的意思。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15879398

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档