0

SO に関する関連トピックを簡単に見つけることができなかったので、ここに行きます - 古典的な問題: User または Person モデルがあり、その人の物理的特性/属性 (目の色、髪の色、肌の色、性別、 1 晩の睡眠時間 (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 の異なる身体的およびライフスタイルの特性)。私にとっては、DRY ルールを破っているように思えeye_colorsます。つまり、3 ~ 5 個のレコードを持つ のような小さなテーブルがたくさん残っています。これらの各テーブルには、意味のある列 (値) が 1 つだけあります。

おそらく単一のモデル、つまり次の構造を持つ 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 モデルを 2 つに分割することによって、より正規化される可能性があります。それとも、何か他のことを提案しますか?

4

1 に答える 1

2

この場合、 has_one 関係はお勧めしません。ユーザーは を使用できるbelongs_to :eye_colorため、ユーザー間で目の色をマッピングできます。EyeColor 。特定の EyeColor を持つすべてのユーザーを実行および取得has_many :usersできます。@eye_color.usersそうしないと、すべてのユーザー (または少なくとも目のあるユーザー) に対して 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

これはすべてテストされていないことに注意してください。ここで何をしようとしているのかを理解してください。

ところで、私はクラス名 Person Attribute がおそらく少し不運であることを理解しaccepts_nested_attributes_for :person_attributesattr_accessible :person_attributes_attributesいます。

于 2013-04-08T14:15:54.767 に答える