2

私はRubyonRails(すぐに明らかになるかもしれません)に不慣れで、次のデータシナリオのモデルを理解しようとしています。私はいくつかの投稿を読み、Googleを詳細に検索しましたが、それでも混乱しています。

列のデータ型が異なることvalueを除いて、同じ列を持つ5つの異なるテーブルがあります。これらのデータは、さまざまな理由から5つの別々のテーブルにありますが、複数のテーブルに分割されたデータと考えてください。

logbook_strings (user_id, entry_id, field_id, value) 
logbook_booleans (user_id, entry_id, field_id, value)  
logbook_integers (user_id, entry_id, field_id, value)  
logbook_decimals (user_id, entry_id, field_id, value)  
logbook_datetimes (user_id, entry_id, field_id, value)  

したがって、データは次のようになります。

------------------------------------------------
| user_id | entry_id | field_id | value        |
------------------------------------------------
| 1       | alpha1   | date     | 2012-11-14   |
| 1       | alpha1   | duration | 1.2          |
| 1       | alpha1   | remarks  | Nice job.    |
------------------------------------------------
| 1       | alpha2   | date     | 2012-11-13   |
| 1       | alpha2   | duration | 2.7          |
| 1       | alpha2   | remarks  | Bad job.     |
------------------------------------------------

エントリalpha1:
2012-11-14、1.2、いい仕事。

エントリalpha2:
2012-11-13、2.7、悪い仕事。

私がこれを行う理由は、無限に柔軟なデータベースを持つことができるようにするためです。field_idスキーマを更新して幅の広いログブックテーブルにさらに別の列を追加する代わりに、いつでも新しいフィールド/機能を追加してアプリに新しいフィールド/機能を追加できます。

それで、私が疑問に思っているのは、これらの5つのテーブルすべてを参照できる単一のActiveRecordモデルを持つことができる方法はありますか?

4

2 に答える 2

1

おそらく、タイプ列を持つ1つのテーブルが必要だと思います。

元:

logbook(user_id, entry_id, field_id, value, value_type)

値の型は

strings

booleans  

integers 

decimals 

datetimes

例は

-----------------------------------------------------------
| user_id | entry_id | field_id | value        |value_type |
-----------------------------------------------------------
| 1       | alpha1   | date     | 2012-11-14   | datetime 
| 1       | alpha1   | duration | 1.2          | decimal
| 1       | alpha1   | remarks  | Nice job.    | string

したがって、基本的に値列は文字列になり、モデルから、値の型で何をしたいかを決定できます。モデルは次のようになります

class Logbook < ActiveRecord::Base

   #sample method
   #just to give an idea how you could use the same value
   #with different times
   def multiple_duration_by_two
     self.value * 2  if self.value_type == "decimal"
   end

end

ただし、要件によっては、この実装に数週間かかる場合がありますが、アイデアは理解できると思います

HTH

于 2012-11-15T09:32:31.337 に答える
1

これを単一の ActiveRecord クラスにまとめようと数分費やした後、このような目的で ActiveRecord を使用するのは良い考えではないと思います。いくつかのオプションが表示されます。

  • 独自のモデルをロールします。このアプローチの最大の欠点は、ActiveRecord の多くの優れた機能をすべて利用できないことです。ただし、データが比較的単純な場合 (多くの関連付けがない場合など)、これは実行可能なオプションになる可能性があります。
  • データを再構築します。このスキーマ/データが既存のものであるか、何らかの理由でモバイル アプリのスキーマと一致する必要がある場合、これはオプションではない可能性があります。しかし、新しく始めた場合、Rails の移行により、気まぐれに列を追加/削除することが非常に簡単かつ非常に安全になるため、より伝統的なアプローチを使用することを検討してください。これは理想的ではないように思えるかもしれませんが、ActiveRecord の多くの利点を得るために真剣に検討する必要があります。

スキーマを維持する必要がある場合は、ログブック テーブルごとに個別のモデルを作成するのが最善の選択肢です。

# Migrations
create_table :logbook do |t|
  # Default fields, nothing special
end

create_table :logbook_integers do |t|
  t.integer :logbook_id  # You'd probably want to index this as well
  t.string :name
  t.integer :value
end

create_table :logbook_strings do |t|
  t.integer :logbook_id   # You'd probably want to index this as well
  t.string :name
  t.string :value
end

# etc...

# Models
class Logbook < ActiveRecord::Base
  has_many :logbook_integers
  has_many :logbook_strings
  # etc...

  def remarks
    self.logbook_strings.find_by_name("remarks").value
  end

  def remarks= newValue
    remark = self.logbook_strings.find_or_create_by_name("remarks")
    remark.value = newValue
    remark.save
  end

  # etc...
end

class LogbookInteger < ActiveRecord::Base
  belongs_to :logbook
end

class LogbookString < ActiveRecord::Base
  belongs_to :logbook
end

# etc...

# Usage

logbook = Logbook.new
logbook.remarks = "Hi"
logbook.duration = 2

logbook.remarks         # => Hi
logbook.duration        # => 2

スキーマを少し変更できる場合は、次のオプションがあります。

ここで説明されているserializeクラス メソッド('serialize' の cmd+f) を使用してエントリを保存できるため、多数のモデルを使用する代わりに、次の 2 つだけを使用できます:と. 次のようになります。LogbookLogbookField

# Migration for logbook_fields
create_table :logbook_fields do |t|
  t.string :name
  t.string :value
end

# Models
class Logbook
  has_many :logbook_fields

  def self.build_with_default_fields
    self.logbook_fields.create name: "date"
    self.logbook_fields.create name: "duration"
    # etc...
  end

  # You could probably do some cool Ruby metaprogramming to create all these
  # accessors/setters for you, btw.
  def date
    self.logbook_fields.find_by_name "date"
  end

  def date= newValue
    field = self.logbook_fields.find_by_name "date"
    field.value = newValue
    field.save
  end


  def duration
    self.logbook_fields.find_by_name "duration"
  end

  def duration= newValue
    field = self.logbook_fields.find_by_name "duration"
    field.value = newValue
    field.save
  end

  # etc...

end

class LogbookField
  serialize :value

  belongs_to :logbook
end

# Usage

logbook = Logbook.build_with_default_fields
logbook.date = DateTime.now
logbook.duration = 2.7

その趣旨の何か。そうすれば、スキーマ設計の「無限性」の一部を維持しながら、ほとんどすべての ActiveRecord の機能を保持できます。ただし、移行を使用して単一のテーブルで列を追加/削除することは、おそらくこれよりも簡単です。繰り返しになりますが、スキーマに柔軟に対応できるかどうかによって異なります。お役に立てれば。

于 2012-11-15T06:02:29.997 に答える