Railsで規約に従わないテーブル名を使う

Ruby On Railsでデータベースを扱う時は、Railsの規約に従ってモデル名、テーブル名等を決定します。しかし、古いシステムからDBを引き継ぐ、他のプログラムとDBを共有する等、場合によっては、規約から外れた名前が必要になることがあります。

今回は、そんな場合にどうするかの内容です。

なお、Rails単体で新しくアプリを作る場合は、規約にきちんと従うことを強くお勧めします。

この内容は、Yokohama.rbのLT大会で話した内容をまとめ直したものです。(初めてのLTだったので、スライドを晒す勇気がなかったので、日記にまとめて書くことにしました。)

テーブル名を規約から変える

例えば、ユーザのテーブルを作る場合、モデル名は大文字始まりの単数形(例:User)、テーブル名は小文字始まりの複数形(例:users)を使うのがRailsの規約です。Userという名前のモデルクラスがある場合、自動的にusersテーブルを読みに行くようになっています。

これを変えたい場合、Rails3.0の場合、

def User < ActiveRecord::Base
  set_table_name 'myuser'

end

のように、set_table_nameを使います。が、Rails3.2に上げたら、deprecation warningが出ました。Rails3.2では、

def User < ActiveRecord::Base
  self.table_name = 'myuser'

end

と、self.table_name に代入します。
(※Rails3.1でどうだったかは試してないです確か、Rails3.1からの変更だったと思います。定かではないので、間違っていたらごめんなさい。)

単数形を使いたい場合も同じようにできます。
(※単純に複数形が不規則なだけの場合は、/config/initializers/inflections.rb で設定しましょう。)

テーブル名を規約から変えた時のテスト

テストでは、set_fixture_classを使うことで、フィクスチャの名前と、モデルクラス名を対応付けすることができます。まず、フィクスチャは、テーブル名に従って名前を付けます(例: myuser.yml)。そして、テストでは、fixturesで利用するフィクスチャを定義する前に、set_fixture_classでフィクスチャとモデルクラスの結びつきを定義します。

describe User do
  set_fixture_class :myuser=> User
  fixtures :myuser #, :follows 等と、必要なものを挙げる

end

主キーをidから変える

主キーをidから変えたい場合は、set_primary_keyを使うことができますが、

def User < ActiveRecord::Base
  set_primary_key :username

end

Rails3.2では、同様にprimary_key=を使うようです。多分。

def User < ActiveRecord::Base
  primary_key = :username

end

複合主キー

Railsでは基本的にサロゲートキー(代理キー)を使って、idが主キーになりますが、場合によっては複合主キーが使いたいこともあります。
そんなときは、composite_primary_keysというgemを使います。

まず、Gemfileに

gem composite_primary_keys

を追加して、bundle installをします。

次に、set_primary_keys(さっきと違って複数形です)で主キーを設定します。

def Follow < ActiveRecord::Base
  set_primary_keys = :user_id, :following_user_id
end

Rails3.2に対応したバージョンのものでは、Railsの変更に合わせて、primary_keys=になっています。

def User < ActiveRecord::Base
  primary_keys = :user_id, :following_user_id

end

まとめ

このあたりまで出来れば、大分いろいろなテーブル構造に対応できるとおもいます。

RailsというとCoC(設定より規約を)によって規約に従わないといけないイメージがありますが、規約に従えば設定をしなくてもいいだけで、細かい設定はいろいろすることができます。

Railsは柔軟であるということが、よくお分かりいただけるのではないかと思います。

あと、最後に言っておきますが、規約に従って差し支えない時は、積極的に規約に従ったほうがシンプルになって簡単です。