Create  Edit  Diff  FrontPage  Index  Search  Changes  History  Source  RSS  Note  wikifarm  Login

Rails' Wiki - ActiveRecord Diff

  • Added parts are displayed like this.
  • Deleted parts are displayed like this.

! Active Record -- railsにおけるO/Rマッピング

:転載元:http://funk.exblog.jp/m2005-02-01#2082044

vendor/activerecord/README

Active Recordは、ビジネスオブジェクトとデータベーステーブルとを接続し、ロジックとデータをひとまとまりとして表現する永続的なドメインモデル(振る舞いとデータをカプセル化した、ドメインのオブジェクトモデル)を生成する。これは、Martin Fowlerによって記述された同名のO/Rマッピング(ORM)パターンの実装である:

""「データベースのテーブルやビューの列をラップし、データベースアクセスをカプセル化し、ドメインロジックを追加するオブジェクト」

アソシエーション(関連付け)とインヘリタンス(継承)の欠如という大きな問題を取り除いたことが、Active Recordsのオリジナルパターンへの大きな貢献である。Active Recordは、アソシエーションの欠如に対してはマクロのセットといったシンプルなドメイン言語を追加、インヘリタンスの欠如に対してはSingle Table Inheritance(クラスの継承ヒエラルキーを、様々なクラスの全てのフィールドのためのカラムを持つ1個のテーブルとして表現する)patternを統合し、data mapper(オブジェクト、データベース、mapper自身、それぞれの独立性を維持しながら、オブジェクト-データベース間でのデータの受け渡しをおこなうMappers層)とactive recordアプローチ間の機能ギャップを小さくする。

主要機能の簡単な紹介:

クラス-テーブル間、属性-コラム間の自動マッピング

  class Product < ActiveRecord::Base; end

とすると、以下のようなテーブル"products"に自動的にマッピングされる。

  CREATE TABLE products (
    id int(11) NOT NULL auto_increment,
    name varchar(255),
    PRIMARY KEY (id)
  );

これにより、Product#nameとProduct#name=(new_name)が利用可能になる。


シンプルなメタプログラミングマクロでコントロールされるオブジェクト間アソシエーション

  class Firm < ActiveRecord::Base
    has_many :clients
    has_one :account
    belongs_to :conglomorate
  end


シンプルなメタプログラミングマクロでコントロールされるvalue objectsのアグリゲーション

  class Account < ActiveRecord::Base
    composed_of :balance, :class_name => "Money",
                :mapping => %w(balance amount)
    composed_of :address,
                :mapping => [%w(address_street street), %w(address_city city)]
  end


オブジェクトが新規であるのか既存であるのかに応じて変更可能な妥当性確認ルール

  class Account < ActiveRecord::Base
    validates_presence_of :subdomain, :name, :email_address, :password
    validates_uniqueness_of :subdomain
    validates_acceptance_of :terms_of_service, :on => :create
    validates_confirmation_of :password, :email_address, :on => :create
  end


レコードをリストやツリーのように動作させる機能

  class Item < ActiveRecord::Base
    belongs_to :list
    acts_as_list :scope => :list
  end
  
  item.move_higher
  item.move_to_bottom


全ライフサイクルにおいて、メソッドやキューとして機能するコールバック(インスタンス化、保存、破壊、認証、等など)

  class Person < ActiveRecord::Base
    def before_destroy # is called just before Person#destroy
      CreditCard.find(credit_card_id).destroy
    end
  end
  
  class Account < ActiveRecord::Base
    after_find :eager_load, 'self.class.announce(#{id})'
  end


全ライフサイクルに対するオブザーバ

  class CommentObserver < ActiveRecord::Observer
    def after_create(comment) # is called just after Comment#save
      NotificationService.send_email("david@loudthinking.com", comment)
    end
  end


継承階層

  class Company < ActiveRecord::Base; end
  class Firm < Company; end
  class Client < Company; end
  class PriorityClient < Client; end


データベースレベルおよびオブジェクトレベルでのトランザクションのサポート。オブジェクトレベルのトランザクションサポートは、Transaction::Simpleを使って実装されている。

  # Just database transaction
  Account.transaction do
    david.withdrawal(100)
    mary.deposit(100)
  end
  
  # Database and object transaction
  Account.transaction(david, mary) do
    david.withdrawal(100)
    mary.deposit(100)
  end


コラムへのリフレクション、アソシエーション、アグリゲーション

  reflection = Firm.reflect_on_association(:clients)
  reflection.klass # => Client (class)
  Firm.columns # Returns an array of column descriptors for the firms table


直接操作(サービスを呼ぶかわりに)

So instead of ([[Hibernate|http://www.hibernate.org/]] example):

  long pkId = 1234;
  DomesticCat pk = (DomesticCat) sess.load( Cat.class, new Long(pkId) );
  // something interesting involving a cat...
  sess.save(cat);
  sess.flush(); // force the SQL INSERT

Active Recordを使えば、次のようにできる。

  pkId = 1234
  cat = Cat.find(pkId)
  # something even more interesting involving a the same cat...
  cat.save


共有コネクタを使った、シンプルなアダプタ(100行以下)経由のデータベース抽象

  ActiveRecord::Base.establish_connection(:adapter => "sqlite", :dbfile => "dbfile")
  
  ActiveRecord::Base.establish_connection(
    :adapter => "mysql",
    :host => "localhost",
    :username => "me",
    :password => "secret",
    :database => "activerecord"
  )


Log4rとLoggerでのロギングのサポート

  ActiveRecord::Base.logger = Logger.new(STDOUT)
  ActiveRecord::Base.logger = Log4r::Logger.new("Application Log")

! ActiveRecord::Base
lib/active_record/base.rb:
!! Creation
!! Conditions
!! Overwriting default accessors
!! Accessing attributes before they have been type casted
!! Dynamic attribute-based finders
!! Saving arrays, hashes, and other non-mappable objects in text columns
!! Single table inheritance

* ひとつの table で継承関係を作る
Reply < Topic みたいなの。

!! Connection to multiple databases in different models
!! Exceptions

lib/active_record/associations.rb:
!!! One-to-one associations
!!! Collections
!!! Type safety with ActiveRecord::AssociationTypeMismatch
!!! Options

* belongs_to
* has_one
* has_many
* has_and_belongs_to_many