こんばんは。
プログラミング初学者です。
現在、Ruby on Rails + Docker + MySQLでアプリの開発をしています。
そこであるエラーにハマり、数日奮闘した結果ようやく解消できたのでそのことをまとめました。
発生したエラー
バイクのレビュー投稿アプリ(名前はBIKKE)を作成しており、そのレビューの投稿画面実装のためコントローラーを下記のように記載
class BikkesController < ApplicationController
def index
@user = User.new
end
def new
@bikke = Bikke.new
end
end
そして新規投稿画面に遷移すると、
NoMethodError!!!!!!しかもnewメソッドが!!??
なぜ!?モデルやマイグレーションファイルの記載に間違いはなし。
まさかnewメソッドがエラーとして返されるとは、その時想像もしておりませんでした。
解消
エラー画面を見てみると、下記文面が記載されています。
undefined method 'new' for Bikke:Module
このModuleがミソですね。
つまり、このBikkeというオブジェクトがクラスではなくメソッドとして認識されている、ということを表しています。
どこかにmodule Bikkeやclass Bikke::Somethingと定義されていないか確認を行いました。
※この解はTeratailにて先人エンジニアさんに教えていただきました。本当に感謝です。
module Bikkeで検索をかけると、ありました。
module Bikke
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 6.1
# Configuration for the application, engines, and railties goes here.
#
# These settings can be overridden in specific environments using the files
# in config/environments, which are processed later.
#
# config.time_zone = "Central Time (US & Canada)"
# config.eager_load_paths << Rails.root.join("extras")
# Don't generate system test files.
config.generators.system_tests = nil
end
end
つまり、railsはrails new
を行った時に、このapplication.rbでアプリ名をモジュールとして定義する仕様のようですね。
そうです。私はアプリ名とコントローラー・モデル名を同じ名前にしてしまったのです。
コントローラーやモデル名の再構築、その他ファイルの修正を行い、再度新規投稿画面に移行すると無事遷移することができました。
学び
本件では、Module Bikkeと認識されていたため、newメソッドを使えるclass Bikkeが見えなくなっていたことがエラーの原因であることがわかりました。
そもそもnewメソッドとは何か?
→ActiveRecordメソッドの一つ
→ActiveRecordメソッドとはモデルがテーブル操作に関して使用できるメソッドの総称である。
ここで、上記のコントローラーやモデルをReview
に変更したとしましょう。
rails c
でコンソールを開き、下記コマンドを打ちます。
[1] pry(main)> Review.superclass
=> ApplicationRecord(abstract)
このReview
はApplicationRecord
を継承していることがわかります。
さらに下記コマンドを打ち込みます。
[2] pry(main)> ApplicationRecord.superclass
=> ActiveRecord::Base
つまりReview
はしっかりActiveRecord::Base
を継承しているからnewメソッド
、そしてallメソッド
やfindメソッド
,saveメソッド
などが使えるのですね。
ちなみに
[3] pry(main)> Bikke.superclass
NoMethodError: undefined method `superclass' for Bikke:Module
アプリ名はしっかりモジュールと定義されているため、superclassメソッド
も使えないのですね。
そして、
[4] pry(main)> Module.superclass
=> Object
モジュールはオブジェクトを継承している・・・っ!
では、モジュールとクラスの違いは何なのでしょうか?
端的にいうと、
クラスはインスタンスの生成ができるのに対し、モジュールではできない。そしてクラスは継承していけるが、モジュールでは継承ができない。
厳密にはMix-inによってモジュールの機能をクラスに提供、いわば継承のようなことはできるようですが・・・。
ふんわりとした表現ですが、本件ではモジュールとクラスで継承しているものが独立しているため、使えるメソッドの違いがあり、エラーの発生に繋がったのだと考えます。
この辺はRubyの真髄でもあるのでより深ぼって理解を深めたいところですね。
兎にも角にも一度作ったコントローラーやモデルの再構築は、ER図やREADMEの変更、その他ビューファイルの調整などあらゆる部分の編集に手間がかかって疲れた・・・。
しかし、非常に良い学びとなりました。
ここまでご覧いただきありがとうございました。