Railsと複合主キー その2

なかなか時間が取れないけど、ちょっとだけ複合主キー(CPK)*1テーブルのマイグレーションとアクセスを試してみた。ちゃんとしたパターンテストはしていないが…
これは結構イケてる!

マイグレーション

こんな感じ*2

class CreatePermissions < ActiveRecord::Migration
   def self.up
      create_table :permission,
                   :primary_key => [:role_cd, :action_cd] do |t|
         t.column :role_cd,       :string, :limit => 20
         t.column :action_cd,     :string, :limit => 20
         t.column :is_permitted, :boolean
         t.column :updated_at,   :timestamp
      end
   end

   def self.down
      drop_table :permission
   end
end

このprimary_key指定が、idでない単一キーの時に使えるといいのだが、そうは問屋が卸さない。参考にさせていただいた2006-10-25にもあるが、primary_key指定は、暗黙に「自動採番のInteger型」に定義されているのだった。

アクセス

consoleで試したら、こんなことが出来る。

>> p = Permission.new
=> #<Permission:0xb72c2f38 
    @attributes={"updated_at"=>nil, "action_cd"=>nil,
    "is_permitted"=>nil, "role_cd"=>nil}, @new_record=true>
>> p.role = Role.find(:first)
=> #<Role:0xb72bee38 
    @attributes={"updated_at"=>"2007-09-13 22:32:15.328273",
    "role_name"=>"部門アシスタント", "role_cd"=>"DA"}>
>> p.action = Action.find('show_news')
=> #<Action:0xb72ba464 
    @attributes={"updated_at"=>"2007-09-13 23:59:55.983605",
    "action_name"=>"Show Whats New", "action_cd"=>"show_news",
    "module_name"=>"Menu"}>
>> p.save
=> true
>> p2 = Action.find('show_news').permissions[0]
=> #<Permission:0xb72a14dc
    @attributes={"updated_at"=>"2007-09-14 00:02:26.987196",
    "action_cd"=>"show_news", "is_permitted"=>nil, "role_cd"=>"DA"}>
>> p2.role
=> #<Role:0xb729e714
    @attributes={"updated_at"=>"2007-09-13 22:32:15.328273",
    "role_name"=>"部門アシスタント", "role_cd"=>"DA"}>
>> Permission.find(['DA', 'show_news'])
=> #<Permission:0xb729a0b0
    @attributes={"updated_at"=>"2007-09-14 00:02:26.987196",
    "action_cd"=>"show_news", "is_permitted"=>nil, "role_cd"=>"DA"}>

面白ーい。varcharの複合主キーは、ちゃんと使えている。最後の複合主キーのfindはちょっとぎごちない感じがするけど、もっと上手い書き方があるのかも知れない*3
ちなみにモデル定義は

class Role < ActiveRecord::Base
   set_primary_key   :role_cd
   
   has_many    :permissions,
               :foreign_key => :role_cd
end
class Action < ActiveRecord::Base
   set_primary_key   :action_cd

   has_many :permissions,
            :foreign_key => 'action_cd'
end
class Permission < ActiveRecord::Base
   set_primary_keys  :role_cd, :action_cd
   
   belongs_to  :role,
               :foreign_key => :role_cd
   belongs_to  :action,
               :foreign_key => :action_cd
end

いい感じなので、ちゃんと検証する気になった。
(つづく)

*1:http://compositekeys.rubyforge.org/

*2:レガシー調を出すため、単数系のテーブル名、マスター側の主キーは"id"ではなくStringの「xxコード」にしてみた

*3:HashにしたらNGだった。キーの順番覚えてないとダメかなぁ?