SinatraからActiveRecord 3を使う(2) CRUD操作

前回のマイグレーションからの続きで、今回はSinatraからActiveRecord 3を使ってCRUD操作をしてみる。といっても、おそらくCRUD操作についてはRailsで使う場合とSinatraとではほとんど違いはないと思われる。前回同様、ActiveRecord 3自体の使い方はこの記事がとてもわかりやすかったので全面的に参考にしている。

モデル

ActiveRecordを使ってDBのCRUD操作をする場合、ActiveRecord::Baseを派生させた1つのクラスがDBの1テーブルに対応し、そのクラスの属性がテーブルの各カラムに対応することになる。このクラスのことを一般的に「モデル」と呼ぶ。Railsでは、Railsアプリを生成した段階でMVC別にフォルダが用意されているので、modelフォルダにこのActiveRecord::Base派生クラスを作るんだけど、Sinatraではそういうフォルダ構造が決まっているわけではないので、アプリの本体となる前回作ったapp.rbファイルに直接書く。

class Count < ActiveRecord::Base
end

get '/' do
  'hoge'
end

こんな感じ。Countのクラス名は、前回のcreate_tableした時の引数:countsによって生成されたテーブル名countsに対応している。対応しているというか、ここの名前をちゃんと揃えないと使えないので注意。例のCoCってやつ。DRYじゃないほう。この空っぽのActiveRecord::Base派生クラスを記述するだけで、countsテーブルをCRUD操作できるようになる。

Create(生成)

新しくレコードを生成するには、普通にRubyでオブジェクトを生成する方法のnewでおk。引数として属性と値をハッシュ形式で指定できる。

get '/create1' do
  count = Count.new(:user => 'ruedap', :count => 1)
  count.save  #=> saveするまでDBには書き込まれない
end

また、生成時の引数ではなく、オブジェクトを生成したあとに、属性値(=フィールド値)を指定することも可能。

get '/create2' do
  count = Count.new
  count.user = 'ruedap'
  count.count = 1
  count.save  #=> saveするまでDBには書き込まれない
end

saveメソッドを実行するまでは、DBへの書き込みは行われない。

Read(読み取り)

読み取りは、idの値を読み取る場合と、それ以外のカラムの値を読み取る場合でメソッドが違うので注意。自分は最初、findで全部読み取れると勘違いしてちょっとハマった。idの値を読み取る場合はfindメソッドを使う。

get '/read1' do
  count = Count.find(1)
  count.class.to_s #=> ヒットすればCountクラス、しなければActiveRecord::RecordNotFoundの例外が発生する
end

それ以外のカラムの値を読み取る場合はwhereメソッドを使う。

get '/read2' do
  count = Count.where(:user => 'ruedap')
  count.class.to_s  #=> 必ずActiveRecord::Relationオブジェクトが返ってくる
end

なぜメソッドが違うのか、ちょっと考えてみたところ、戻り値が違ったのでわかった気がした。findidの値を検索するので、検索結果はヒットするとしたら必ず1件しか引っかからない。一方、whereはいろいろなカラムの値を検索するので、時には検索結果が複数ヒットする場合があり、その場合は配列的なものを使わなければならない。この違いを明確にするためにメソッドが分けてあるのかなぁと。

今回のサンプルプログラムの場合は、findの戻り値はCountオブジェクト、whereの戻り値はActiveRecord::Relationオブジェクトとなる。前者は引っかからなかった場合はActiveRecord::RecordNotFoundの例外が発生する。また、後者は検索結果が0件でも1件でも複数件でも、必ず同じActiveRecord::Relationオブジェクトが戻り値となる。

Update(更新)

更新するのは簡単で、CreateやReadしたオブジェクトに属性経由で値をつっこんでsaveするだけ。以下のサンプルコードではwhereを使っていて、配列のようなActiveRecord::Relationオブジェクトで返ってくるので、その配列の1個目を取り出すためにfirstメソッドを使っている。

get '/update' do
  count = Count.where(:user => 'ruedap').first  #=> whereの場合、戻り値はActiveRecord::Relationオブジェクトなので1個取り出す必要がある
  count.user = 'chaplin'
  count.count = 100000000
  count.save  #=> saveするまでDBには書き込まれない
end

ちなみに、最初のCreateのところで説明した/create2の方法は、まさにこのUpdateを使っていたということになる。

Delete(削除)

削除も簡単で、findwhereで削除したいレコードを探してきて、1件取り出してdestroyメソッドを実行すれば削除される。これはsaveしなくても、destroyを実行した時点で削除される。

get '/delete1' do
  count = Count.find(1)
  count.destroy  #=> これはsaveしなくても、destroyメソッドを実行した時点でDBから削除される
end

また、複数削除する場合は、whereでヒットさせてActiveRecord::Relationオブジェクトを生成し、そのActiveRecord::Relationオブジェクトに対してdestroy_allメソッドを実行すれば全部削除できる。

get '/delete2' do
  count = Count.where(:user => 'ruedap')
  count.destroy_all
end

以上で、ActiveRecord 3を使ったCRUD操作をひと通りできるようになったので、前回のマイグレーションとあわせることで、とりあえず基本的なDB操作を使えるようになった。次回はバリデーションについて書く予定。


「ActiveRecord」の基本とデータの参照 - @IT 第2回 Active Recordの使い方 | Think IT