ActiveModel:RubyオブジェクトにActiveRecordを感じさせます

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単なるエイリアスでsendattr_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つだけです。 残りについて簡単に説明します。

AttributeMethodstable_name :fooなどの属性を管理するためのクラスメソッドの追加を簡素化します。
Callbacks :ActiveRecordスタイルのオブジェクトライフサイクルコールバック。
Dirty :ダーティオブジェクトのサポート。
Namingmodel.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でも使用できる場合は、コミュニティから新しいバリデーター、翻訳、シリアライザーなどを期待しています。

Source: https://habr.com/ru/post/J86938/


All Articles