Ruby on Railsで複合キーを扱う(2)
2012/03/26
前回は、Gemライブラリcomposite_primary_keysを用いるとRailsアプリケーションにおいて複合キーでレコードを検索したり、複合キーを持つモデル同士を関連づけできることを確かめました。
今回はルーティング編です。
コントローラの生成・実装からルーティングの設定まで
% rails g controller departments index % rails g controller products index show
app/controllers/departments_controller.rb を修正。
class DepartmentsController < ApplicationController
def index
@departments = Department.order("code, seq_number")
end
end
app/controllers/products_controller.rb を修正。
class ProductsController < ApplicationController
def index
@department = Department.find(params[:department_id])
@products = @department.products.order("products.code, products.model_number")
end
def show
@department = Department.find(params[:department_id])
@product = @department.products.find(params[:id])
end
end
config/routes.rb を修正。
Synthetos::Application.routes.draw do
resources :departments do
resources :products
end
end
ビューの実装
app/views/departments/index.html.erb を修正。
<h1>Departments#index</h1>
<ul>
<% @departments.each do |d| %>
<li>
<%= d.name %>: <%= link_to "Products", [ d, :products ] %>
</li>
<% end %>
</ul>
app/views/products/index.html.erb を修正。
<h1>Products#index</h1>
<ul>
<% @products.each do |p| %>
<li>
<%= link_to p.name, [ @department, p ] %>
</li>
<% end %>
</ul>
app/views/products/show.html.erb を修正。
<h1>Products#show</h1> <ul> <li>Name: <%= @product.name %></li> <li>Code: <%= @product.code %></li> <li>Model number: <%= @product.model_number %></li> <li>Description: <%= @product.description %></li> </ul>
シードデータの投入
config/routes.rb を修正。
%w(robot automobile ship).each do |code|
Department.create!(
code: code,
seq_number: 1,
name: code.capitalize,
established_on: 2.years.ago
)
end
%w(alpha bravo).each do |code|
Product.create!(
code: code,
model_number: 2012,
department_code: "robot",
department_seq_number: 1,
name: code.capitalize,
description: ""
)
end
% rake db:reset
モデルの修正
Gemライブラリcomposite_primary_keysの説明によれば、["robot", 1] という複合キーを持つオブジェクト@departmentに対して、to_paramメソッドを呼ぶと "robot,1" という文字列が返ってくるべきなのですが、実際には "robot-1" という文字列が返ってきます。これではいろいろとうまく動かないので、モデルに少し修正を加えます。
たぶん composite_primary_keys がRails 3に完全に対応し切れていないためと思われます。作者に連絡したので、そのうちに直るでしょう。
app/model/department.rb を次のように修正します。
class Department < ActiveRecord::Base
self.primary_keys = :code, :seq_number
has_many :products, foreign_key: [ :department_code, :department_seq_number ]
def to_param
persisted? ? to_key.join(',') : nil
end
end
同様に、app/model/product.rb を次のように修正します。
class Product < ActiveRecord::Base
self.primary_keys = :code, :model_number
belongs_to :department,
foreign_key: [ :department_code, :department_seq_number ],
primary_key: [ :code, :seq_number ]
def to_param
persisted? ? to_key.join(',') : nil
end
end
ブラウザで動作確認
% rails s
ブラウザで http://localhost:3000/departments を開くと次のような画面になります。

「Robot」の右の「Products」リンクをクリックすると次のような画面になります。URLに注目してください。

そして、「Alpha」リンクをクリックすると次のような画面になります。

ちょっとしたバグ(?)が見つかりましたが、ルーティングはうまく動いているようですね。ただし、URLにコンマ(,)が含まれる点はちょっと気になります。
次回は、複合キーの一つが文字列や数値ではなく、「期間」になっている場合について考えます。
