Ruby
Rails
MySQL
rails5,

activerecordでself.table_nameの値と、定義したmodelのrelationshipが被っちゃった時の悲劇

More than 1 year has passed since last update.

ふと思ったのですが、映画の年間パスが非常に欲しいのですがそういうのあまりないんですね。


背景

とある既存システムの、次世代バージョンを開発している。その既存システムはweb版とネイティブ版を持っていて、僕はネイティブ版の次世代バージョンを作っている。web版との兼ね合いでデータベースは既存のものを使うことになっている(ここがめっちゃ辛い)。ネイティブはreact-native, APIはrailsで開発している。

データベースは既存のものを使うことになっているのですが、この命名とかが僕的にはとてもわかりにくかったので、DBのテーブル名とモデル名は基本的に全て違っている。activerecordで帳尻合わせをしている感じ。

開発中に諸事情によりテーブル名を変更した。そのタイミングでよくわからないエラーが出続けて非常に困ったのでその備忘録と、理由を知っている人がいたら教えて欲しいのでqiitaに残しておくことにした。

叩いたコマンドは以下の通り。relation組んでる相手側から呼び出そうとするとエラーがでる。relationの組み方にはエラーはまったくありません。

AnotherModelClass.first.test


実際のコード

ちなみに僕はrailsの書き始めて2ヶ月。プログラミング始めて10ヶ月のぺーぺーで、まだ至らない点がそりゃもうたくさん。これからエラーが出るコードとその内容を書いて行くのですが、見て欲しいのは次の3箇所。


  1. self.table_name = "value1"

  2. has_one :value2

  3. エラーメッセージの NameError: 以下略

以下の3つのパターンを試したところ全て挙動が違っていた。railsの裏側もしっかり学ばないとな。。って思った次第です。


エラーが出るパターン


app/model/user.rb

class Test < ApplicationRecord

self.table_name = "test_users"

has_one :test_user

# エラーは以下のとおり
=begin
NameError: uninitialized constant Test::TestUser
from /path/to/app/vendor/bundle/ruby/2.3.0/gems/activerecord-5.0.1/lib/active_record/inheritance.rb:152:in `compute_type
=end



エラーでないパターン


app/model/user.rb

class Test < ApplicationRecord

self.table_name = "different_users"

has_one :test_user

## エラーなし



まとめ

結局エラーが解消できたのでよかった。ちゃんと理解していないことについてまとめるのは大変だなぁと思いつつ、なんかよくわからないからとりあえずまとめるしかなかった。言葉とかわかりにくいと思いますが、最後まで付き合ってくれた方、ありがとうございます。