fc2ブログ

2023.11 «  - - - - - 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 - - - - - - » 2024.01
TOP > CATEGORY > [2.1]active_record

TOP

Rails 2.1・その11(created_at updated_at カラムを自由自在) 

2008年06月04日 ()
今回はちょいネタで。

migration ファイルで、テーブルを作成する場合に t.timestamps なんていう感じに指定すると、created_at カラムや updated_at カラムを追加してくれますが、

これを、後から追加したり削除したりするのに簡単な書き方があります。その名も add_timestampsremove_timestamps

例えば、people テーブルにこいつらを追加し忘れたぁ、なんて時は、次のようなマイグレーションファイルなんていかが?

class Timestamps < ActiveRecord::Migration
  def self.up
    add_timestamps :people # people テーブルに2カラム追加
  end

  def self.down
    remove_timestamps :people # people テーブルから2カラム削除
  end
end



【広告】

スポンサーサイト



[2008.06.04(Wed) 15:09] [2.1]active_recordTrackback(0) | Comments(0) 見る▼
↑TOPへ

Rails 2.1・その7(mysql で整数の型を切り替えてくれる) 

2008年05月30日 ()
mysql のヤカラドモ集合!

:limit に指定する数字により、:integer から変換される DB の型を smallint, int, bigint に自動的に設定してくれマツコDX.

class CreateNumbers < ActiveRecord::Migration
  def self.up
    create_table :numbers do |t|
      t.integer :num # => int(11)
      t.integer :num1, :limit => 1 # => smallint(1)
      t.integer :num3, :limit => 3 # => smallint(3)
      t.integer :num4, :limit => 4 # => int(4)
      t.integer :num8, :limit => 8 # => int(8)
      t.integer :num9, :limit => 9 # => bigint(9)
      t.integer :num10, :limit => 10 # => bigint(10)





postgresql はもともとサポートされてたとよ。

詳しくは activerecord/lib/active_record/connection_adapters/mysql_adapter.rb を自分で見てみよう。

【広告】

[2008.05.30(Fri) 14:47] [2.1]active_recordTrackback(0) | Comments(0) 見る▼
↑TOPへ

Rails 2.1・その6(named_scope がアツい) 

2008年05月29日 ()
Special Thanks to a_matsudaさん
-------------------------------------------
controller とかで、:conditions => { ....
とか書いてソースコードがややぐちゃぐちゃになるのを見事にスッキリさせられるようになりました。

早速例を見てみましょう。model クラスに、named_scope の行を追加します。

class Person < ActiveRecord::Base
  named_scope :young, :conditions => {:age => 0..30}
end



これで、age が 0 ~ 30 の人をゲットできるようになります。

Person.young

SELECT * FROM "people" WHERE ("people"."age" BETWEEN 0 AND 30)



その人数をカウントしてくれたりもします。

Person.young.count

SELECT count(*) AS count_all FROM "people" WHERE ("people"."age" BETWEEN 0 AND 30)



named_scope は、複数指定することもできますよ。

class Person < ActiveRecord::Base
  named_scope :young, :conditions => {:age => 0..30}
  named_scope :recent, lambda { {:conditions => ["updated_at > ?", 1.day.ago]} }
end



この :recent ですが、ちょっとわかりづらいのですが、こういう↓変遷をたどりました。

# これだと、リアルタイムの1.day.agoではなく、モデルがインスタンス化された時の1.day.agoがずーっと同じまま残ってしまう
named_scope :recent, :conditions => ["updated_at > ?", 1.day.ago]
# カッコをつけて
named_scope :recent, {:conditions => ["updated_at > ?", 1.day.ago]}
# これが最終形。これだと、:recent が呼び出されるたびに 1.day.ago の値がリアルタイムに変化する
named_scope :recent, lambda { {:conditions => ["updated_at > ?", 1.day.ago]} }



さて本題にもどりますと、:young と :recent を組み合わせることもできます。そうすると、SQL的にはANDでつながるようです。

Person.young.recent

SELECT * FROM "people" WHERE ((updated_at > '2008-05-28 10:55:27') AND ("people"."age" BETWEEN 0 AND 30))



さらに引数を取ってみることもできますよ。
次の例は、引数を取ることもできるし取らなかったら1.day.agoを使う例です。イキナリ複雑でゴメンくさい。

class Person < ActiveRecord::Base
  named_scope :recent, lambda {|*args| {:conditions => ["updated_at > ?", args.first || 1.day.ago]} }
end



これを使って

Person.recent(6.days.ago).count


とか出来ちゃいまーす


最後に、named_scope を使わないでも似たようなことができるのでご紹介します

young = Person.scoped(:conditions => {:age => 0..30})
young

SELECT * FROM "people" WHERE ("people"."age" BETWEEN 0 AND 30)



きゃべつ太郎ブンダバー

参考ブログ
named_scope
What's New in Edge Rails: Has Finder Functionality


【広告】

[2008.05.29(Thu) 11:47] [2.1]active_recordTrackback(0) | Comments(0) 見る▼
↑TOPへ

Rails 2.1・その5(model の値変更を覚えている) 

2008年05月28日 ()
Special Thanks to a_matsudaさん
-------------------------------------------
モデルの値を変更した後、セーブする前に、実際に変更したかどーだかなどという情報を参照できます。

↓いきなりまとめ

changed? :モデルの値を変更したかどうか
[カラム名]_changed? :モデルの指定したカラム名の値を変更したかどうか
[カラム名]_was :モデルの指定したカラム名の変更前の値
[カラム名]_change :モデルの指定したカラム名の変更前と後の値
changed :モデルの変更したカラム名のリスト
changes :モデルの変更したカラム名のリストと、変更前と後の値
[カラム名]_will_change! :モデルの指定したカラムの値を、= 以外の手段で変える場合に必要



例を使うと分かりやすいですね。

p = Person.first
p.name # => "yasushi"
p.changed? # => false
# もともと入っていた値と同じ値を入れても変更扱いにならない
p.name = "yasushi"
p.changed? # => false
# もともと入っていた値と違う値を入れると変更扱いになる
p.name = "kiyoshi"
p.changed? # => true

p.name_changed? # => true
p.age_changed? # => false

p.name_was # => "kiyoshi"

p.name_change # => ["kiyoshi", "yasushi"]
p.age_change # => nil

# さらに age カラムの値も変える
p.age # => 49
p.age += 1 # => 50

p.changed # => ["name", "age"]
p.changes # => {"name"=>["kiyoshi", "yasushi"], "age"=>[49, 50]}

# 注:↓のやり方だと = で値を代入していないので、変更扱いになりません!!
p = Person.first
p.name # => "kiyoshi"
p.name.replace("yasushi")
p.changed? # => false
p.save # DBの値は更新されない
# なのでこの場合は、[カラム名]_will_change! を使います
p = Person.first
p.name_will_change!
p.name # => "kiyoshi"
p.name.replace("yasushi")
p.changed? # => true
p.save # DBの値が更新される



お・ま・け!

唐突なダンキチ&ナヲミのおまけコーナーですが、↑の例で p.save をすると、変更していないカラムにも update が走りますが、変更したカラムだけ udpate を走らせたい場合

config/initializers ディレクトリにテキトーな名前のファイルを作って

ActiveRecord::Base.partial_updates = true



を書きます。

参考ブログ
Living on the edge (of Rails) #14 - the extreme edition. Extremely late.
What's New in Edge Rails: Dirty Objects
Tracking Attribute Changes

【広告】

[2008.05.28(Wed) 14:38] [2.1]active_recordTrackback(0) | Comments(0) 見る▼
↑TOPへ

Rails 2.1・その4(db migration ファイルのバージョンがUTC日付に) 

2008年05月27日 ()
Special Thanks to a_matsudaさん
-------------------------------------------
db migration ファイルの名前が 001_chomechome.rb から 20080224235011_chomechome.rb になりました。

連番から、年月日時分秒(UTC)にバージョン番号が変わったという訳ですね。

これに伴い、db のテーブル名も、schema_info から schema_migrations に変わりました。

このテーブルのカラムも version(INT) から version(VARCHAR 255) に変わりました。

テーブルに入るデータも、schema_info の時は 1 行だけでしたけど、schema_migrations は、migrate したファイルの数だけの行数を保持します。

つまーり、db/migrate ディレクトリの中のファイルが、
20080224235011_chomechome_one.rb
20080224235012_chomechome_two.rb
20080224235013_chomechome_three.rb

だったとすると、

rake db:migrate

をして、schema_migrations テーブルに入るデータは、
20080224235011
20080224235012
20080224235013

の 3 行になります。

この変更、複数人で違う機能を平行して開発している時とか、1人で開発しているけどブランチ(食事のことではない)ありまくりの時とかに、えーと次のバージョン番号なんだっけ?と隣の人に聞いたりプロジェクト内で調整を計ったりしなくてもよくなりました。わーい


例で言いますと、db/migrate ディレクトリの中のファイルが、
20080224000000_chomechome_one.rb
20080224111111_honyarara_one.rb
20080224222222_chomechome_two.rb
20080224333333_chomechome_three.rb

だったとして、そして、schema_migrations テーブルに入っているデータが
20080224000000
20080224222222
20080224333333

だったとします。この時

rake db:migrate

をすると、20080224111111_honyarara_one.rb の分が実行されます。


さて、ここで注意しなければならないのが、こちらの migration ファイル 4 つを、テスト環境や本番環境へ持っていくときには、この順番↓で実行されますが、
20080224000000_chomechome_one.rb
20080224111111_honyarara_one.rb
20080224222222_chomechome_two.rb
20080224333333_chomechome_three.rb

20080224111111_honyarara_one.rb ファイルの中で、その後に続くファイル 20080224222222_chomechome_two.rb や 20080224333333_chomechome_three.rb の処理とのコンフリクトを起こしてはいかんよ、ということですね。

たとえば、↓の例はいけません
20080224111111_honyarara_one.rb

class HonyararaOne < ActiveRecord::Migration
  def self.up
    change_table :people do |t|
      t.rename :gender, :sex # ここで gender から sex にカラム名を変えてしまった
    end
  end

  def self.down
    change_table :people do |t|
      t.rename :sex, :gender
    end
  end
end



20080224222222_chomechome_two.rb

class ChomechomeTwo < ActiveRecord::Migration
  def self.up
   change_table :people do |t|
     t.change :gender, :string # もう gender というカラム名は存在しない
   end
  end

  def self.down
    t.change :gender, :integer
  end
end



という訳で終了。ちょりーす


参考ブログ
Migrations in Rails 2.1
What's New in Edge Rails: UTC-based Migration Versioning

【広告】

[2008.05.27(Tue) 11:38] [2.1]active_recordTrackback(0) | Comments(0) 見る▼
↑TOPへ

TOP