読者です 読者をやめる 読者になる 読者になる

おもしろwebサービス開発日記

Ruby や Rails を中心に、web技術について書いています

ActiveRecord復習

リレーション関連がうまく使いこなせていないので、railsによるアジャイルwebアプリケーション開発を読み返してみた。勉強になったことをメモメモ。

テーブル情報の取得

下記のようなマイグレーションでpeopleテーブルが定義されているとして、

create_table :people do |t|
  t.string :name
  t.integer :age
  t.boolean :auth
end
  • Person.columun_namesでカラムの名前を配列で取得できる。(クラスメソッド)
  • Person.column_hash["name"]のようにすると、Personのname列の情報(デフォルト値とか)を取得できる。*1
  • person.attribute_namesで属性の名前の配列が取得できる。(オブジェクトメソッド)
person.age_before_type_cast

のように、属性名に_before_type_castをつけるとデータベースの値をそのまま取得する。(この場合は結果は特に変わらない)

データベースの値を条件判定に使用するときに気をつけること

下記のように、booleanの列を直接条件判定に使うのはよくないらしい。

if person.auth
  # 処理
end

理由は、DBに入っている値を直接使うと、falseのつもりで設定した値がtrueと解釈されることがあるから。*2このように、列の名前の後ろに?を付けてあげると良いらしい。

if person.auth?
  # 処理
end

このようにすると、DBに下記の値が格納されていればfalseとするみたい。

  • 0
  • "0"
  • "f"
  • "false"
  • ""
  • nil
  • false

create

createの引数に、属性ハッシュの配列を渡すことで、複数のオブジェクトを保存できる。

Person.create([{:name => "willnet"}, {:name => "netwillnet"}])

findメソッドプレースホルダ指定方法4つ。

その1

一番ベーシック(だと個人的に思っている)やり方。

Person.find(:all, :conditions => ["name = ?", name])
その2

プレースホルダに名前をつけるやり方。

Person.find(:all, :conditions => ["name = :name", :name => name])
その3

その2改良版。paramsを条件に渡すやり方。

Person.find(:all, :conditions => ["name = :name", params[:person])
その4

究極版?paramsだけで条件文を作ってくれる。

Person.find(:all, :conditions => params[:person])

これまで、その1しか使ってなかった><その3が使えそうかな。その4はすごく簡潔な表現だけど、使いどころを気をつけないといけないからあんまり使いたくないな。

動的ファインダ

People.find_by_nameのようなものを動的ファインダというらしい。よく使うけど名前は知らなかった。

変わり種な動的ファインダ

下記のような動的ファインダもあるみたい。

Person.find_or_initialize_by_name("willnet")

動作はこれと一緒

Person.find_by_name("willnet") || Person.new(:name => "willnet")

createもある

Person.find_or_create_by_name("willnet)

動作は一緒

Person.find_by_name("willnet") || Person.create(:name => "willnet")

うーん。確かに短くなるけど使うかなあ?

既存の行の更新

基本的にはsaveメソッドだけ使えれば事足りるのだけど、コードを短くする手法がいくつかある。

save

ノーマルバージョン。

willnet = People.find(1)
willnet.name = "netwillnet"
willnet.save
update_attributes

値の変更とsaveを同時に。

willnet = People.find(1)
willnet.update_attributes(:name => "netwillnet")
update

値の取得と変更とsaveを同時に

People.update(1, :name => "netwillnet")
update_all

条件に合致する複数業を一括でupdate。sql文のupdateな感じ。

People.update_all("auth = 0", "name like '%will%'")

行の削除

delete系とdestroy系の2つのメソッドがある。違いはコールバックや検証機能を経由するかしないか。
deleteは検証やコールバックをせずにいきなり削除する。なので普通はdestroyを使うのがよい。

delete例
Person.delete(1)
Person.delete_all(["age > ?", 20])
destroy例
willnet = Person.find(1)
willnet.destroy
Person.destroy(1)
Person.destroy_all(["age > ?", 20])

今日はここまで

思ったより時間がかかってしまった。リレーションまでたどり着けてない><

参考

RailsによるアジャイルWebアプリケーション開発 第2版

RailsによるアジャイルWebアプリケーション開発 第2版

*1:これは使いどころがない気がする

*2:今のところそれでハマったことはないので、最近のrailsmysqlだったら問題なさげ。