中間テーブルを用いた多対多の関係(その 1)

今「一人の従業員が複数(0 個も含む)の資格を持っている」「ある資格を持っている従業員が複数(0 人も含む)いる」という状況を考えます。これは多対多の関係ですが、RDBMS では多対多の関係をそのまま表現することができないので中間テーブルを用います。まずは関連モデルと中間テーブル作成からやっていきましょう。

rails g model employee name:string age:integer salary:integer sex_id:integer --timestamps=false
rails g model sex name:string --timestamps=false
rails g model license name:string --timestamps=false
rails g migration CreateEmployeesLicenses employee_id:integer license_id:integer

できたマイグレーションファイル(xxxxxxxxxxxxxx_create_employees_licenses.rb)を編集します*1

class CreateEmployeesLicenses < ActiveRecord::Migration
  def change
    create_table :employees_licenses, :id => false do |t|
      t.references :employee
      t.references :license
    end
  end
end

今回作成する中間テーブルは外部キー以外を持たない(主キーも持たない !)ようにしたいので

:id => false

のオプションを付けます。

次にデータを挿入します。モデルがあるものは seeds.rb を利用して挿入します。

# (略)

Sex.create(
  :name => '男性'
)

Sex.create(
  :name => '女性'
)

Sex.create(
  :name => 'その他'
)

License.create(
  :name => '普通自動車第1種免許'
)

License.create(
  :name => '英語検定1級'
)

License.create(
  :name => '中国語検定1級'
)

License.create(
  :name => '簿記'
)

License.create(
  :name => '調理師'
)

License.create(
  :name => '国内旅行取り扱い主任者'
)

License.create(
  :name => '中小企業診断士'
)

Employee.create(
  :name => '田中健太郎',
  :age => 27,
  :salary => 198000,
  :sex_id => 1
)

Employee.create(
  :name => '島田麻紀',
  :age => 23,
  :salary => 172000,
  :sex_id => 2
)

Employee.create(
  :name => '福井肇',
  :age => 32,
  :salary => 220000,
  :sex_id => 1
)

Employee.create(
  :name => '山本加奈子',
  :age => 33,
  :salary => 210000,
  :sex_id => 2
)

Employee.create(
  :name => '遠藤隆',
  :age => 45,
  :salary => 370000,
  :sex_id => 1
)

Employee.create(
  :name => '佐藤龍',
  :age => 52,
  :salary => 440000,
  :sex_id => 1
)

Employee.create(
  :name => '岩隈優',
  :age => 28,
  :salary => 270000,
  :sex_id => 2
)

Employee.create(
  :name => '本間佳子',
  :age => 29,
  :salary => 250000,
  :sex_id => 2
)

Employee.create(
  :name => '中田和良',
  :age => 55,
  :salary => 470000,
  :sex_id => 1
)

Employee.create(
  :name => '吉本一郎',
  :age => 48,
  :salary => 270000,
  :sex_id => 1
)

中間テーブルのデータは対応するモデルが無いので SQL 文を直接発行します。

INSERT INTO employees_licenses(employee_id, license_id) VALUES(1,1);
INSERT INTO employees_licenses(employee_id, license_id) VALUES(1,2);
INSERT INTO employees_licenses(employee_id, license_id) VALUES(1,4);
INSERT INTO employees_licenses(employee_id, license_id) VALUES(2,2);
INSERT INTO employees_licenses(employee_id, license_id) VALUES(3,1);
INSERT INTO employees_licenses(employee_id, license_id) VALUES(3,4);
INSERT INTO employees_licenses(employee_id, license_id) VALUES(7,1);
INSERT INTO employees_licenses(employee_id, license_id) VALUES(8,5);
INSERT INTO employees_licenses(employee_id, license_id) VALUES(9,1);
INSERT INTO employees_licenses(employee_id, license_id) VALUES(9,7);

モデルにアソシエーションを定義します。

class Employee < ActiveRecord::Base
  has_and_belongs_to_many :licenses
  belongs_to :sex
end
class License < ActiveRecord::Base
  has_and_belongs_to_many :employees
end
class Sex < ActiveRecord::Base
  has_many :employees
end

has_and_belongs_to_many メソッドを利用して、中間テーブルを通して多対多の関係を表現します。

実際の利用例は次回以降に。

*1:他のマイグレーションファイルも若干修正していますが、今回の話題の本質ではないので割愛します。