おいちゃんと呼ばれています

ウェブ技術や日々考えたことなどを綴っていきます

レガシーなウェブアプリを Rails で拡張するときに DB の扱いで気をつけること #rubyhiroba

最近仕事で PHP 製のレガシーなウェブアプリの APIRails でつくるということをやっていまして(僕がイチから構築したわけではないですが)、Rails way に沿っていないスキーマの DB を扱う際に苦労しました。

そのとき苦労した点を一昨日 RubyHiroba 2014 というイベントで発表してきたのでスライドを公開します。

タイトルは一部変更しました。

スライドは添え物で、ほとんど口で説明したのでなかなか理解しづらい点はあるかもしれませんが、このエントリーでは一番ハマった点だけ紹介します。

例: Sale has_many sale_details

例えば、下記のようなテーブル定義があったとして、

CREATE TABLE `sales` (
  `id`
  `account_id`, …

CREATE TABLE `sale_details` (
  `id`
  `account_id`
  `sales_id` # ここが sale_id ではないのがポイント

モデルのアソシエーションを Sale has_many sale_details にしたいとします。

sale.sale_details

sale.sale_details したときに下記のような SQL を実行してほしいときは、

SELECT `t_sales_detail`.*
FROM `t_sales_detail`
WHERE t_sales_detail`.`sales_id` = 999

アソシエーション設定に foreign_keyprimary_key オプションを使います。

class Sale < ActiveRecord::Base
  has_many :sale_details,
    :foreign_key => :sales_id,
    :primary_key => :id
end

もう一歩進めて、インデックスをうまく使えるようにする

例えば、インデックスが下記のような複合インデックスになっていたら、

add_index "sale_details", ["account_id", "sales_id"], :name => …

このままではインデックスが使えないので、下記のような SQL がほしい。

SELECT `t_sales_detail`.*
FROM `t_sales_detail`
WHERE t_sales_detail`.`account_id` = 123
  AND t_sales_detail`.`sales_id` = 999

そのときはアソシエーションを下記のように設定する必要があります。

class Sale < ActiveRecord::Base
  has_many :sale_details,
    :foreign_key => [:account_id, :sales_id],
    :primary_key => [:account_id, :id]
end

とかいう辺りが Rails Guides の該当箇所を読んでもよく理解できなかったので、手を動かしながら調べて分かったことを紹介した感じです。興味がある方はスライドのほうを見てみてください。

Rails Guides の日本語版が出たようです

で、その Rails Guides なのですが、話逸れますけど、日本語版が先日公開されたようです。中の人である [twitter:@yasulab] さんが RubyHiroba で Rails Guides の中の仕組みを発表されていました。こういうのめっちゃ有り難い!感謝です!

謝辞

RubyHiroba 2014 運営チームのみなさん、おつかれさまでした。本当にありがとうございました!この場を借りてお礼申し上げます。