只今Ruby勉強中

プログラミングRuby―達人プログラマーガイド

うさぎさんと一緒にRubyの勉強をしているオレの記録。

間違ってる所とかいっぱいあると思いますけど、誰でもコメント出来るので気軽に教えて下さい。

普段は 鷹の島 って所で書いてます。

現在のハマリポイント - yield, succ?, Proc & 後で

2007-05-29 (Tue)

Rails でデータに連番を振る 00:00  Rails でデータに連番を振る - 只今Ruby勉強中 を含むブックマーク

各プロジェクト毎にチケットを登録するとして、プロジェクト毎にチケットの番号は1から順に振っていきたいわけなんだけど、テーブルは一緒のままがいい。 そんな場合は acts_as_sequenced っていうのを使うと良いらしい。

上記のサイトに書いてあるコードを lib ディレクトリに acts_as_sequenced.rb と言う名前で配置して、environment.rb で require 'acts_as_sequenced.rb' するだけ。 多分 require File.join(File.dirname(__FILE__), 'boot') よりも下に書けば良い。

使い方も簡単。 今回の例の場合は、こんな風になった。

まずモデルを書く。 no カラムがチケットの番号になるようにした。

class Project < ActiveRecord::Base
  has_many :tickets
end

class Ticket < ActiveRecord::Base
  acts_as_sequenced :column => :no, :scope => 'project_id = #{project_id}'
  belongs_to :project
end

:scope はもっと簡潔にかけるっぽいんだけど、良くわかんない。 書き方を失敗すると、わけわからんエラーになる。

SyntaxError: (eval):21:in `acts_as_sequenced': compile error
(eval):17: syntax error, unexpected kEND
(eval):21: syntax error, unexpected $end, expecting '}'
        from ./script/../config/../config/../lib/acts_as_sequenced.rb:38:in `acts_as_sequenced'
        from ./script/../config/../config/../app/models/ticket.rb:2
        from /var/lib/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:203:in `load_without_new_constant_marking'
        from /var/lib/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:203:in `load_file'
        from /var/lib/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:342:in `new_constants_in'
        from /var/lib/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:202:in `load_file'
        from /var/lib/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:94:in `require_or_load'
        from /var/lib/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:248:in `load_missing_constant'
        from /var/lib/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:452:in `const_missing'
        from /var/lib/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:464:in `const_missing'
        from (irb):1

これで migrate をこんな感じか。

create_table :projects do |t|
  t.column :name, :string
end

create_table :tickets do |t|
  t.column :project_id, :integer
  t.column :no, :integer
  t.column :name, :string
end

実行

$ ./script/console
Loading development environment.
>> Project.create :name => 'new Project'
=> #<Project:0x412e9e24 @new_record_before_save=true, @new_record=false, @errors=#<ActiveRecord::Errors:0x412720b8 @errors={}, @base=#<Project:0x412e9e24 ...>>, @attributes={"name"=>"new Project", "id"=>1}>
>> Project.create :name => 'second Project'
=> #<Project:0x4126dce8 @new_record_before_save=true, @new_record=false, @errors=#<ActiveRecord::Errors:0x4126d5cc @errors={}, @base=#<Project:0x4126dce8 ...>>, @attributes={"name"=>"second Project", "id"=>2}>
>> Ticket.create :name => 'new Ticket #1', :project_id => 1
=> #<Ticket:0x4126145c @new_record=false, @errors=#<ActiveRecord::Errors:0x4125e2c0 @errors={}, @base=#<Ticket:0x4126145c ...>>, @attributes={"name"=>"new Ticket #1", "no"=>1, "project_id"=>1, "id"=>1}>
>> Ticket.create :name => 'Ticket #2', :project_id => 1
=> #<Ticket:0x41254310 @new_record=false, @errors=#<ActiveRecord::Errors:0x41253960 @errors={}, @base=#<Ticket:0x41254310 ...>>, @attributes={"name"=>"Ticket #2", "no"=>2, "project_id"=>1, "id"=>2}>
>> Ticket.create :name => 'new Ticket for second #1', :project_id => 2
=> #<Ticket:0x4124ac84 @new_record=false, @errors=#<ActiveRecord::Errors:0x4124a2d4 @errors={}, @base=#<Ticket:0x4124ac84 ...>>, @attributes={"name"=>"new Ticket for second #1", "no"=>1, "project_id"=>2, "id"=>3}>
>> Ticket.create :name => 'Ticket for second #2', :project_id => 2
=> #<Ticket:0x41241760 @new_record=false, @errors=#<ActiveRecord::Errors:0x41240db0 @errors={}, @base=#<Ticket:0x41241760 ...>>, @attributes={"name"=>"Ticket for second #2", "no"=>2, "project_id"=>2, "id"=>4}>
>> Ticket.create :name => 'Ticket #3', :project_id => 1
=> #<Ticket:0x41238688 @new_record=false, @errors=#<ActiveRecord::Errors:0x41237cd8 @errors={}, @base=#<Ticket:0x41238688 ...>>, @attributes={"name"=>"Ticket #3", "no"=>3, "project_id"=>1, "id"=>5}>
>> Ticket.create :name => 'Ticket for second #3', :project_id => 2
=> #<Ticket:0x4122f18c @new_record=false, @errors=#<ActiveRecord::Errors:0x4122e7dc @errors={}, @base=#<Ticket:0x4122f18c ...>>, @attributes={"name"=>"Ticket for second #3", "no"=>3, "project_id"=>2, "id"=>6}>
>> Ticket.create :name => 'Ticket #4', :project_id => 1
=> #<Ticket:0x412260b4 @new_record=false, @errors=#<ActiveRecord::Errors:0x41225704 @errors={}, @base=#<Ticket:0x412260b4 ...>>, @attributes={"name"=>"Ticket #4", "no"=>4, "project_id"=>1, "id"=>7}>
>> Ticket.create :name => 'Ticket for second #4', :project_id => 2
=> #<Ticket:0x4121cbb8 @new_record=false, @errors=#<ActiveRecord::Errors:0x4121c208 @errors={}, @base=#<Ticket:0x4121cbb8 ...>>, @attributes={"name"=>"Ticket for second #4", "no"=>4, "project_id"=>2, "id"=>8}>
>>

DB の内容をチェック

$ sqlite3 db/development.sqlite3
SQLite version 3.3.8
Enter ".help" for instructions
sqlite> .explain ON
sqlite> select * from tickets;
id    project_id      no          name
----  --------------  ----------  ----------
1     1               1           new Ticket
2     1               2           Ticket #2
3     2               1           new Ticket
4     2               2           Ticket for
5     1               3           Ticket #3
6     2               3           Ticket for
7     1               4           Ticket #4
8     2               4           Ticket for

うまく出来た。

トラックバック - http://rubyist.g.hatena.ne.jp/gaba/20070529