不可算名詞をモデルやテーブルに使う場合の注意点

不可算名詞をモデルやテーブルに使う場合の注意点

アプリケーション開発中にモデル名やテーブル名に不可算名詞を使う機会があり、そこで少しハマったのでこちらに対処方法をまとめます。

[fish]というモデル名で[fishes]というテーブル名を付けたい場合に、モデルファイルとスキーマファイルを以下のようにしました。

[app/models/fish.rb]

class Fish < ApplicationRecord
end
[db/schema.rb]

  create_table "fishes", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t|
    t.string "kind", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["kind"], name: "index_fishes_on_kind", unique: true
  end

[rails c]でFishモデルを使おうとすると以下のようなエラーになってしまいました。

$ rails c
Loading development environment (Rails 6.0.4.1)
irb(main):001:0> Fish.all
  Fish Load (0.4ms)  SELECT `fish`.* FROM `fish` LIMIT 11
Traceback (most recent call last):
ActiveRecord::StatementInvalid (Mysql2::Error: Table 'fishing_cooking_development.fish' doesn't exist)

fishテーブルがありませんとなってしまいます。
スキーマファイルに[fishes]と記載しており、Mysqlにも[fishes]テーブルがあるのに、なぜか[fish]テーブルを使おうとする。。。

これは、railsがモデル名から使用するテーブル名を予測していることによる原因でした。
通常railsは、モデル名を単数系で記述してテーブル名を複数形で記述することにより、使うテーブルをrailsが予測してくれますが、今回のように[fish]という不可算名詞を使用すると、railsは、テーブル名も[fish]というテーブル名を使用しようとします。
[fish]の場合は、1種類の魚がたくさんいる場合は複数形も[fish]になりますが、たくさんの種類の魚という場合には、複数形は[fishes]となります。

上記のことからrailsは、[fish]の複数形は[fish]と解釈して[fish]というテーブルを使おうとしていました。

railsの複数形、単数系の判断は以下のコマンドで調べることができます

irb(main):001:0> "fish".pluralize      #[fish]の複数形を調べる
=> "fish"
irb(main):002:0> "fishes".singularize   #[fishes]の単数系を調べる
=> "fish"

今回のようにモデル名を[fish]でテーブル名を[fishes]にしたい場合は、以下のように設定することでイレギュラー設定をすることができます。

ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.irregular 'fish', 'fishes'
end

上記を記述後に再度railsの単数系と複数形の判断を確認すると以下のようになります。

irb(main):001:0> "fish".pluralize
=> "fishes"
irb(main):002:0> "fishes".singularize
=> "fish"
irb(main):003:0> Fish.all
  Fish Load (1.8ms)  SELECT `fishes`.* FROM `fishes` LIMIT 11
=> #<ActiveRecord::Relation []>

上記のようにFishのActiveRecordも使えるようになりました。

参考記事

Railsで単数形を複数形に変換する方法と、その変換がうまく行かない場合の対処法 - 久保清隆のブログ