0

一連の標準メタデータ属性を持ち、通常どおりデータベースに永続化されるメディア モデルがあります。ここでやりたいことは、構成可能なメタデータ属性をこのモデルに既存の属性の上に追加することです。これらの属性のリストは構成ファイルで定義され、実行時にロードされます。これらは、メイン モデルに関連付けられた一連のプロパティと値のペアとして、データベースの別のテーブルに格納されます。

だから、私のコードは現在、

class Media < ActiveRecord::Base
  has_many :custom_metadata

  attr_accessible :title, :language, :copyright, :description
end

class CustomMetadata < ActiveRecord::Base
  belongs_to :media

  attr_accessible :name, :value
end

私がやりたいことは、標準のメタデータ属性と同じ方法で Media モデルのカスタム メタデータ属性にアクセスして更新できるようにすることです。たとえば、カスタム メタデータ属性がpublisherおよびcontributorと呼ばれる場合、Media モデルでそれらにアクセスしたいと考えて@media.publisher@media.contributorます@media.custom_metadata[{:name => 'publisher', :value => 'Fred'}, {:name => 'contributor', :value => 'Bill'}]

仮想属性がこれを達成するための最良の方法であるように思われますが、仮想属性を使用している人々について私が見つけることができるすべての例は、属性の名前が実行時の構成から動的ではなく静的で既知のものであるため、関連するプロパティ値レコードに書き込むコードを含むpublisherやなどのメソッドを定義できます。publisher=

( returnとattr_accessor *Settings.custom_metadata_fields仮定して) を使用してクラスの属性を定義し、同様の手法を使用して.Settings.custom_metadata_fields[:publisher, :contributor]attr_accessible

私が立ち往生している部分は、レコードからデータをロードするときにアソシエーションから仮想属性を設定する方法と、逆に、レコードが保存される前に仮想属性のデータをアソシエーションに戻す方法です。

現在、これが機能していると思われる 2 つの方法は、 または を使用するか、またはコールバックを使用することmethod_missingですattribute_missingか? どちらの場合も、モデルに通常の属性と仮想属性が混在しているため、どのように定義すればよいかわかりません。initializebefore_save

助言がありますか?

4

2 に答える 2

1

コールバックの使用は理にかなっているように思えます。どのデータベースを使用していますか? PostgreSQL の場合は、HStore 拡張機能 ( http://www.postgresql.org/docs/9.2/static/hstore.html ) を確認する必要があります。パフォーマンスが向上し、簡単に使用できるようにする gem がいくつかあります。

于 2013-05-23T11:31:44.213 に答える
0

コールバックをさらに調べた後、コールバックを発見しました。これは、最初に計画after_initializeしたメソッドを使用するよりもはるかに優れています。initialize

最終的に、これは Media モデルの最終的なコードであり、CustomMetadata モデルでは質問で定義したものから何も変更しませんでした。

class Media < ActiveRecord::Base
  has_many :custom_metadata

  attr_accessor *Settings.custom_metadata_fields

  attr_accessible :title, :language, :copyright, :description
  attr_accessible *Settings.custom_metadata_fields

  validates_presence_of *Settings.required_custom_fields

  before_save :save_custom_metadata
  after_initialize :load_custom_metadata

  def load_custom_metadata
    MediaMetadata.custom_all_fields.each do |field|
      custom_record = custom_metadata.where(:name => field.to_s).first_or_initialize()
      send("#{field}=", custom_record.value)
    end
  end

  def save_custom_metadata
    MediaMetadata.custom_all_fields.each do |field|
      custom_record = custom_metadata.where(:name => field.to_s).first_or_initialize()
      custom_record.value = send(field)
      if custom_record.value.blank?
        custom_record.destroy
      else
        custom_record.save
      end
    end
  end
end

このソリューションには、いくつかの優れた利点がありました。まず、Media モデルの通常の属性には影響しません。次に、実際の値を持つカスタム メタデータのみがカスタム メタデータ テーブルに格納されます。値が空白の場合、レコードは完全に削除されます。最後に、必須のカスタム メタデータ属性について示されているように、モデル属性に対して標準の検証を使用できます。

于 2013-05-24T00:16:54.470 に答える