DataMapper で relation を使った検索

ドキュメントに載ってないことを補足していこうシリーズ。

DataMapper で、たとえば次のようなモデルクラスがあるとする。

### 従業員
class Employee
  include DataMapper::Resource
  property :id, Serial
  property :name, String, :nullable => false
  property :department_id, Integer
  belongs_to :department
end

### 部門
class Department
  include DataMapper::Resource
  property :id, Serial
  property :name, String, :nullabel => false, :unique_index => true
  has n, :employees
end

ここで、従業員の名前で検索するには次のようにする (これはよく知られている)。

  • 「Employee.all(:name => "Kathy")」とすると、名前が Kathy である従業員
  • 「Employee.all(:name.not => "Kathy")」とすると、名前が Kathy でない従業員


また relation を使った検索は、次のようにする (これはドキュメントに載ってないと思う)。

  • 「Employee.all("department.name" => "Sales")」とすると、所属部門の名前が Sales である従業員
  • 「Employee.all("department.name.not" => "Sales")」とすると、所属部門の名前が Sales でない従業員


実行例:

$ merb -i
irb> Employee.all("department.name"=>"Sales")
 ~ SELECT "employees"."id", "employees"."name", "employees"."department_id"
   FROM "employees" INNER JOIN "departments"
   ON ("departments"."id" = "employees"."department_id")
   WHERE ("departments"."name" = 'Sales')
   ORDER BY "employees"."id"
=> [#<Employee id=3 name="Kathy" department_id=1>]

irb> Employee.all("department.name.not"=>"Sales")
 ~ SELECT "employees"."id", "employees"."name", "employees"."department_id"
   FROM "employees"
   INNER JOIN "departments"
   ON ("departments"."id" = "employees"."department_id")
   WHERE ("departments"."name" <> 'Sales')
   ORDER BY "employees"."id"
=> [#<Employee id=4 name="Jack" department_id=2>,
    #<Employee id=5 name="Bill" department_id=2>,
    #<Employee id=6 name="Scott" department_id=3>]

Merb のバージョンを更新すると起動しない場合

Merb を新しいバージョンにして起動すると、次のようなエラーがでる場合がある。

 ~ FATAL: The gem merb-action-args (= 1.0.2, runtime), [] was not found

この場合は、config/dependencies.rb に書かれてあるバージョンを書き換えてやるとよい。

merb_gems_version = "1.0.4"
dm_gems_version   = "0.9.8"

「FATAL: Could not bind to 4000」と言われて Merb が起動できない場合

症状:「FATAL: Could not bind to 4000」と言われて、Merb が起動できない。

原因:すでに別の Merb が起動しているか、前に起動したときの worker process が終了されていない。

対処:4000 番ポートを使っている process を lsof で見つけ、kill する。

$ merb
merb : worker (port 4000) ~ Starting Mongrel at port 4000
merb : worker (port 4000) ~ 
merb : worker (port 4000) ~ FATAL: Could not bind to 4000. It was already in use
merb : worker (port 4000) ~ 
$ sudo lsof -i:4000
COMMAND   PID   USER   FD   TYPE    DEVICE SIZE/OFF NODE NAME
ruby    52132 kwatch   13u  IPv4 0xbe26a68      0t0  TCP *:terabase (LISTEN)
$ kill -9 52132