Yehuda Katzは2010年1月10日にこのエントリを彼のブログに投稿しました。モノリシックなコンポーネントには、非常に優れたRails 2.3機能が大量に隠されています。 ルーター、ディスパッチャー、ActionControllerの一部のコードを単純化し、ActionPackの機能を部分的に再編成する方法について、すでにいくつかの投稿を投稿しています。 ActiveModelは、便利な機能の再編成後にRails 3で導入された別のモジュールです。
手始めに-ActiveModel API
ActiveModelには2つの主要な要素があります。 最初のAPIは、ActionPackヘルパーとの互換性のためにモデルが準拠する必要があるインターフェイスです。 さらに詳しく説明しますが、最初に重要な詳細を説明します。モデルは、1行のRailsコードなしでActiveModelと同様に作成できます。
モデルがこれに適していることを確認するために、ActiveModelは
ActiveModel::Lint
モジュールを提供し、APIとの互換性をテストします。テストに接続するだけです。
Copy Source | Copy HTML<br/> class LintTest < ActiveModel::TestCase<br/> include ActiveModel::Lint::Tests<br/> <br/> class CompliantModel <br/> extend ActiveModel::Naming<br/> <br/> def to_model <br/> self <br/> end <br/> <br/> def valid ?() true end <br/> def new_record ?() true end <br/> def destroyed ?() true end <br/> <br/> def errors <br/> obj = Object .new<br/> def obj .[](key) [] end <br/> def obj .full_messages() [] end <br/> obj <br/> end <br/> end <br/> <br/> def setup <br/> @model = CompliantModel .new<br/> end <br/> end <br/>
ActiveModel::Lint::Tests
モジュールテストは、
@model
オブジェクトの互換性を検証します。
ActiveModelモジュール
ActiveModelの2番目の興味深い部分は、独自のモデルに標準機能を実装するためのモジュールのセットです。 それらのコードはActiveRecordから削除されており、現在では個別に含まれています。
これらのモジュールを自分で使用するため、モデルに追加するAPI関数はActiveRecordとの互換性を維持し、Railsの将来のリリースでサポートされることを確認できます。
ActiveModelに組み込まれた国際化により、コミュニティはエラーメッセージなどの翻訳に取り組むことができます。
検証システム
検証は、おそらく最も失望するActiveRecordサイトの1つでした。たとえば、CouchDBなどのライブラリを作成したユーザーは、書き換えプロセス中にさまざまな矛盾を引き起こす可能性があるAPIを文字通り書き換えるか、まったく新しいAPIを発明するかを選択する必要があったためです。
検証にはいくつかの新しい要素があります。
まず、検証の宣言自体。 ActiveRecordでの使用方法を覚えていますか:
Copy Source | Copy HTML<br/> class Person < ActiveRecord::Base <br/> validates_presence_of :first_name, :last_name<br/> end <br/> Ruby, :<br/> <br/> class Person <br/> include ActiveModel::Validations<br/> <br/> validates_presence_of :first_name, :last_name<br/> <br/> attr_accessor :first_name, :last_name<br/> def initialize (first_name, last_name)<br/> @first_name, @last_name = first_name, last_name<br/> end <br/> end <br/>
検証システムは
read_attribute_for_validation
を呼び出して属性を取得しますが、デフォルトでは
send
単なるエイリアスで
send
、
attr_accessor
介して標準のRuby属性システムを
attr_accessor
ます。
属性の検索方法を変更するには、
read_attribute_for_validation
をオーバーライドできます。
Copy Source | Copy HTML<br/> class Person <br/> include ActiveModel::Validations<br/> <br/> validates_presence_of :first_name, :last_name<br/> <br/> def initialize (attributes = {})<br/> @attributes = attributes<br/> end <br/> <br/> def read_attribute_for_validation (key)<br/> @attributes[key]<br/> end <br/> end <br/>
バリデーターが本質的に何であるかを見てみましょう。 まず、
validates_presence_of
メソッド:
Copy Source | Copy HTML<br/> def validates_presence_of (*attr_names)<br/> validates_with PresenceValidator, _merge_attributes(attr_names)<br/> end <br/>
ご覧のように、
validates_presence_of
はよりプリミティブな
validates_presence_of
使用し、それをバリデータクラスに渡し、
{:attributes => attribute_names}
キーを
attr_names
追加し
attr_names
。 次に、バリデータクラス自体:
Copy Source | Copy HTML<br/> class PresenceValidator < EachValidator<br/> def validate (record)<br/> record. errors .add_on_blank(attributes, options[:message])<br/> end <br/> end <br/>
EachValidator
クラスの
validate
メソッドは、各属性を検証します。 この場合、上書きされ、属性が空の場合にのみエラーメッセージがオブジェクトに追加されます。
add_on_blank
メソッドは、
value.blank?
場合
add_on_blank
add(attribute, :blank, :default => custom_message)
add_on_blank
add(attribute, :blank, :default => custom_message)
value.blank?
(とりわけ)、ローカライズされた
:blank
メッセージをオブジェクトに追加します。 英語
locale/en.yml
ローカリゼーションファイル
locale/en.yml
次のとおりです。
Copy Source | Copy HTML<br/>en:<br/> errors:<br/> # . <br/> format : "{{attribute}} {{message}}" <br/> <br/> # :model, :attribute :value <br/> # :count . . <br/> messages:<br/> inclusion: "is not included in the list" <br/> exclusion: "is reserved" <br/> invalid: "is invalid" <br/> confirmation: "doesn't match confirmation" <br/> accepted: "must be accepted" <br/> empty: "can't be empty" <br/> blank: "can't be blank" <br/> too_long: "is too long (maximum is {{count}} characters)" <br/> too_short: "is too short (minimum is {{count}} characters)" <br/> wrong_length: "is the wrong length (should be {{count}} characters)" <br/> not_a_number: "is not a number" <br/> greater_than: "must be greater than {{count}}" <br/> greater_than_or_equal_to: "must be greater than or equal to {{count}}" <br/> equal_to: "must be equal to {{count}}" <br/> less_than: "must be less than {{count}}" <br/> less_than_or_equal_to: "must be less than or equal to {{count}}" <br/> odd: "must be odd" <br/> even: "must be even" <br/>
その結果、エラーメッセージは
first_name can't be blank
ように見え
first_name can't be blank
。
ErrorオブジェクトもActiveModelの一部です。
連載
ActiveRecordにはJSONとXMLのシリアル化も組み込まれているため、
@person.to_json(:except => :comment)
ようなことを実行できます。
シリアル化で最も重要なことは、すべてのシリアライザーで受け入れられる共通の属性セットをサポートすることです。 つまり、
@person.to_xml(:except => :comment)
ます。
独自のモデルにシリアル化サポートを追加するには、シリアル化モジュールと
attributes
メソッドの実装を追加(インクルード)する必要があり
attributes
。 参照:
Copy Source | Copy HTML<br/> class Person <br/> include ActiveModel::Serialization<br/> <br/> attr_accessor :attributes<br/> def initialize (attributes)<br/> @attributes = attributes<br/> end <br/> end <br/> <br/> p = Person . new (:first_name => "Yukihiro" , :last_name => "Matsumoto" )<br/> p .to_json #=> %|{"first_name": "Yukihiro", "last_name": "Matsumoto"}| <br/> p .to_json(:only => :first_name) #=> %|{"first_name": "Yukihiro"}| <br/>
特定の属性をいくつかのメソッドで変換するには、オプション
:methods
;を渡すことができ
:methods
。 これらのメソッドは動的に呼び出されます。
検証とシリアル化を備えたPersonモデルは次のとおりです。
Copy Source | Copy HTML<br/> class Person <br/> include ActiveModel::Validations<br/> include ActiveModel::Serialization<br/> <br/> validates_presence_of :first_name, :last_name<br/> <br/> attr_accessor :attributes<br/> def initialize (attributes = {})<br/> @attributes = attributes<br/> end <br/> <br/> def read_attribute_for_validation (key)<br/> @attributes[key]<br/> end <br/> end <br/>
その他のモジュール
ActiveModelモジュールは2つだけです。 残りについて簡単に説明します。
AttributeMethods
:
table_name :foo
などの属性を管理するためのクラスメソッドの追加を簡素化します。
Callbacks
:ActiveRecordスタイルのオブジェクトライフサイクルコールバック。
Dirty
:ダーティオブジェクトのサポート。
Naming
:
model.model_name
で使用されるmodel.model_nameのデフォルトの実装(たとえば、
render :partial => model
)。
Observing
:ActiveRecordのスタイルのオブザーバー。
StateMachine
:シンプルなステートマシンの実装。
Translation
:他の言語への翻訳の基本的なサポート(国際化国際化フレームワークとの統合)。
Josh Peekは、昨年夏のGoogle Summer of Codeのプロジェクトの一環として、ActiveRecordのメソッドを個別のモジュールに再編成しました。これはプロセス全体の最初のステップに過ぎません。 時間が経つにつれて、ActiveRecordから抽出されたものが増え、ActiveModelの抽象化が増えると予想しています。
また、特にActiveRecordだけでなく、MongoMapper、Cassandraオブジェクト、およびActiveModelモジュールを使用する他のORMでも使用できる場合は、コミュニティから新しいバリデーター、翻訳、シリアライザーなどを期待しています。