AWDwR "Chapter14 Active Record Basics"

いよいよActive Recordですよ。

テーブルとクラス

DHHの趣味でテーブル名はモデルのクラス名の複数形と仮定しているけど、嫌な場合は

ActiveRecord::Base.pluralize_table_name=false

とすればモデルのクラス名とテーブル名を一緒にできる。また自分でテーブル名を指定したい場合は

class Sheep < ActiveRecord::Base
  set_table_name "sheep"
end

というような感じでOK。

SQLのdecimal型はRubyのfloat型にマップされるので注意。またbooleanの属性は0と1で格納されるので以下の点に注意。

if user.superuser  × 常にtrueと判定されてしまう
if user.superuser? ○ こうしましょう

プライマリキーとID

デフォルトではidという名前のintegerのカラムをプライマリキーとするんだけど、他のカラムをプライマリキーにしたい場合は以下のようにする。その場合プライマリキーの値は自分で設定しなければいけないので注意。

class BadBook < ActiveRecord::Base
  set_primary_key :isbn
end

データベースへの接続

データベースへの接続の設定はestablish_connectionメソッドでできるけど、普通は設定ファイルのdatabase.ymlでしましょう。

CRUD

レコードの作成

新しく作成するレコードの初期化方法

Order.new do |o|
  o.name = "enkimi"
  o.save
end

order = Order.new(
  :name => "enkimi"
)
oreder.save

createメソッドを使えばダイレクトにDBに書き込んでくれる。saveメソッド不要。

order = Order.create(
  :name => "enkimi"
)
レコードの読み込み

こんな感じ。

Order.find(1)
Order.find([1,3,5,7,9])
Order.find(:all, :conditions => ["name=? and pay_type=?", name, pay_type])
Order.find(:all, :conditions => ["name=:name and pay_type=:pay_type", params])
Order.find(:all, :order => "id", :limit => page_size, :offset => page_number*page_size)
Order.find_by_sql("select * from orders")
Order.count
Order.count(["name=?", name])

ダイナミックファインダはおもしろい。

Order.find_by_name(name)
Order.find_all_by_name(name)
User.find_by_name_and_password(name, password)

レコードの更新

こんな感じ。

Order.update_attribute(:name, "enkimi")
Order.update_attributes(:name => "enkimi", :email => "enkimi@foo.com")
Order.update(12, :name => "enkimi")
Order.update_all("price=1.1*price", "title like '%Java'")

save()は保存できた場合はtrue、保存に失敗した場合はfalseを返す。一方save!()は保存に失敗した場合はRecordInvalid例外を上げる。

楽観的ロック

楽観的ロックを使用したい場合はテーブルにlock_versionという名前のintegerのカラムを作りましょう。初期値は0とすること。

レコードの削除

こんな感じ。

Order.delete(1)
Order.delete([1,2,3,4,5])
Order.delete_all(["price < ?", price)

インスタンスメソッドのdestroy()はそのインスタンスに該当するDBのレコードを削除し、そのインスタンスを変更不可にする。一方クラスメソッドのdestroy(),destroy_all()はDBからレコードを読み込んでインスタンスを生成しインスタンスメソッドのdestroy()を呼び出す。destroy()はdelete()と違ってコールバックやバリデーションを実行する。普通はdestroyを使いましょう。


続きはまた。