LoginSignup
54
46

More than 3 years have passed since last update.

[Rails] 別名で外部キー設定して関連付けしたい

Last updated at Posted at 2018-09-02

やりたいこと

  • 通貨の交換を管理する際、交換モデルから通貨モデルを外部キー設定したい。
  • 外部キーは買い通貨と売り通貨の2種類
  • 通貨モデルは親通貨モデルCurrencyを継承したActiveRecordで実装
  • つまり、参照側はされる側のスーパークラスを参照したい

参照する側(交換モデルの実装)

マイグレーション

CeateExchanges.rb
create_table :exchanges do |t|
  t.references :buy_currency, foreign_key: { to_table: :currencies }
  t.references :sell_currency, foreign_key: { to_table: :currencies }
end
  • ポイントは実際のテーブル名と異なる属性名を使用している
  • その際はto_tableキーの値で実際のテーブル名を指定

モデル

Exchange.rb
class Exchange < ApplicationRecord
  belongs_to :buy_currency, class_name: "Currency"
  belongs_to :sell_currency, class_name: "Currency"
end
  • ポイントはbelongs_toには参照したい名称を指定
  • 実際のクラス名はclass_nameキーの値で指定
  • belongs_to :currency_jpyとか子通貨テーブルの名称を関連付けに設定してしまうと、exchangeテーブルにレコードを挿入できなくなります。
  • なぜなら、実際には親通貨モデルを外部キーとして設定しているにも関わらず、子通貨モデルを関連付けることで、レコード挿入時には子通貨の値がないはずで、バリデーションで子通貨がblankだと怒られるからです

参照される側(親通貨モデルの実装)

マイグレーション

CeateCurrencies.rb
create_table :currencies do |t|
  t.string :name, null: false
end

モデル

Currency.rb
class Currency < ApplicationRecord
  self.table_name_prefix = "currency_"
  has_many :exchanges

  def buy(amounts)
    self.amounts += amounts
  end

  def sell(amounts)
    self.amounts -= amounts
  end
end
  • 本記事の主旨からズレますが、ダックタイピングを使ってます。総量を表すamountsは親通貨モデルには定義していません。親クラスから継承した子通貨モデル側で総量を定義していれば、問題なく動作します。
db/seeds.rb
Currency.create(name: "JPY")
Currency.create(name: "USD")
Currency.create(name: "BTC")
  • このseedのように親クラスでは扱える通貨一覧を管理する目的でレコードを保有
  • その心はcollection_selectフォームヘルパーを使用したいからです

参照される側(子通貨モデルの実装)

マイグレーション

CeateCurrencyJpy.rb
create_table :currency_jpy do |t|
  t.float :amounts, null: false, default: 0
end
  • モデルの生成で自動作成されるマイグレーションには複数形のテーブル名が付与されるので、通貨としては扱いづらいために書き換えてます
  • 実用的にはユーザーモデルとの関連付けが必要だと思います

モデル

コンソール
$ rails g model Currency::Jpy
  • この記事では通貨はcurrency名前空間の配下に作成して少し複雑なケースでまとめます
currency/jpy.rb
class Currency::Jpy < Currency
end

まとめ

Railsの基本的な使い方をしていると気付かないような動きを確認することができました。
アソシエーションを設定することで普段は気にしていない動作が走っていることなど、勉強になりました。
個人的にはモデルのnamespaceは動きが読めなくて使いづらく、おススメできないです。

54
46
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
54
46