Rails-1.1.6 に find_or_initialize_by_* を追加するプラグイン

書いた人: noriaki 2007,06月27日(水) 01:27

RailsのActiveRecordにはfinderというデータベースのデータを検索するメソッドがあります.その中で最もなじみの深いのがfindです.

Article.find(:first, :conditions => ["title = ?", params[:q]])

Railsを使ったことのある人なら,上のようなコードを1度は見たことがあると思います.

しかし,Railsでは以下のようにメソッド名をカラムの名前を使って動的に呼び出せる方法が存在します.以下のコードは上記のfindメソッドを利用したのと同じ結果になります.

Article.find_by_title(params[:q])

また,findでデータを探して,あればそのオブジェクトを返し,無ければ新しくオブジェクトを作って返したいということがわりとよくあると思うのですが,そんなときに重宝するのがfind_or_create_by_*というメソッドです.(*のところのにはfind_by_titleのようにカラム名が入ります)

article = Article.find_or_create_by_title("Ruby on Rails")
article.new_record? # => false

上記コードは,articlesテーブルに"Ruby on Rails"というタイトルのデータがあれば,それをselectしてきて返し,なければ新しくオブジェクトを作成してデータベースに保存します.

さらに,Railsはバージョン1.2.3が公開されて久しいですが,Rails-1.2.3にはfind_or_initialize_by_*というメソッドが使えるようになっています. これは,find_or_create_by_*が文字通りテーブル内にデータが無かったときにはオブジェクトをcreateしているのに対し,find_or_initialize_by_*はオブジェクトをnewして返します.

article = Article.find_or_initialize_by_title("Ruby on Rails")
article.new_record? # => true

つまり,新しく作られたオブジェクトはまだデータベースに保存されておらず,後にarticle.saveを実行したときに初めてデータベースにデータが保存されることになります.

私は,このfind_or_initialize_by_*メソッドをRails-1.1.6の環境で使いたかったのですが,Rials-1.1.6にはこのメソッドがなく,むりやりfind_or_new_by_*などといったメソッドをActiveRecordに追加したりしていました. 今回,他のプラグインの関係でActiveRecord内の動的なfinderの実装を見る機会があったので,ついでにこちらのfind_or_initialize_by_*メソッドをRails-1.1.6の環境で使えるようにプラグインにしました.

acts_as_find_or_initialize_by

acts_as_find_or_initialize_byはActiveRecord::Baseにクラスメソッドとしてfind_or_initialize_by_*メソッドを追加するプラグインです.このプラグインを利用することによって,Rails-1.1.6の環境でもfind_or_initialize_by_*メソッドを使用することができるようになります.

Install

rubyforgeのSVNリポジトリからダウンロードしてRailsプラグインディレクトリに配置するだけです.

$ cd #{RAILS_ROOT}
$ ./script/plugin install svn://rubyforge.org/var/svn/findorinit

Example

db/migrate/001_create_articles.rb
class CreateArticles < ActiveRecord::Migration
  def self.up
    create_table :articles do |t|
      t.column :title, :string
      t.column :url, :string
      t.column :body, :text
      t.column :created_on, :datetime
      t.column :updated_on, :datetime
    end
    add_index :articles, :title
  end

  def self.down
    drop_table :articles
  end
end
./script/console
>> Article.count
=> 0
>> article = Article.find_or_initialize_by_title("Ruby on Rails")
=> #<Article:0xb71400c0 @attributes={"created_on"=>nil, "body"=>nil,
 "title"=>"Ruby on Rails", "updated_on"=>nil, "url"=>nil}, new_recordtrue
>> article.body = "Rails is a full-stack, open-source web framework."
=> "Rails is a full-stack, open-source web framework."
>> article.url = "http://www.rubyonrails.org/"
=> "http://www.rubyonrails.org/"
>> article.new_record?
=> true
>> Article.count
=> 0
>> article.save
=> true
>> Article.count
=> 1
>> article = Article.find_or_initialize_by_title("Ruby on Rails")
=> #<Article:0xb7122228 @attributes={"created_on"=>"2007-06-27 02:05:06",
 "body"=>"Rails is a full-stack, open-source web framework.",
 "title"=>"Ruby on Rails", "updated_on"=>"2007-06-27 02:05:06",
 "url"=>"http://www.rubyonrails.org/", "id"=>"1"}
>> article.new_record?
=> nil

ご意見・ご感想

ありましたら,お気軽にコメントやトラックバック,ブクマコメントなどでどうぞよろしくお願いします.

このエントリをdel.icio.usにブックマークしているユーザ数このエントリをdel.icio.usに追加する
このエントリをはてなブックマークしているユーザ数このエントリをはてなブックマークに追加する
 | Tags ,

コメント

このエントリはアーカイブされています。
コメントする場合は、お手数ですが「このページのURL」を記載した上で、新しいエントリにお願いします。