LoginSignup
3
3

More than 3 years have passed since last update.

selfを使って、undefined methodエラーを解消

Posted at

はじめに

Modelで定義したメソッドがControllerで呼び出せなくなったとき、
selfを使って2パターンの解決法を見つけたため、記録として残しておく。

今回は、helloという名前のメソッドをモデルで定義するという設定とする。

解決法1(特異メソッド方式)

post.rb
class Post
  def self.hello
    puts 'hello'
  end
end

メソッド名の前にself.をつけるやり方

ruby初学者なら何度も見たことのある形だ。

解決法2(特異クラス方式)

post.rb
class Post
  class << self
    def hello
      puts 'hello'
    end
  end
end

こちらでも、きちんとcontrollerで呼び出すことができた。
この場合だと、メソッド名の前にself.を書く必要もないし、class << self と end内であれば、
複数のメソッドを同じように定義できるのがメリットだ。

post.rb
class Post
  class << self
    def hello
      puts 'hello'
    end

    def goodmorning
      # 二つ定義しても self つけなくて良い
      puts 'Good morning'
    end
  end
end

そもそも

ここからは、特異メソッド方式や特異クラス方式、selfについてもう一歩踏み込んだところまで理解したい方々に読んで欲しい。

class << selfの仕組み

 特異メソッド

hello = 'hello'
def hello.say
  puts hello + 'world'
end
hello.say #=> hello world

another_hello = 'hello'
another_hello.say #=> NoMethodError: undefined method `say' for "hello":String

このように、特異メソッド(hello.say)とは、オブジェクト(hello)に直接固有のメソッドを定義したものだ。
なので、上記のように別のオブジェクト(another_hello)には使うことはできない。

これに加えて、もう一つ特異メソッドを定義する方法がある。

hello = 'hello'

class << hello
  def say_world
    puts "#{self}, world"
  end
end
hello.say_world #=> hello, world

これも << hello というところで helloオブジェクトの特異クラスを引き出しており、あくまでオブジェクトに対しての特異メソッドの定義となっている。

つまり、一番最初のこの部分、

class Post
  class << self

クラス定義のコンテキストでの self とは、Classクラスのインスタンス Post class だ。class Post とはクラスを定義するときの記法だが、Ruby の中での理解としては、Class クラスのオブジェクトを生成し Post というグローバルな定数へ代入している。

なので、以下の2つの記述は同じ意味だ。


class Post
  def hello
    puts 'hello'
  end
end
post = Post.new
post.hello #=> hello

Post = Class.new do
  def hello
    puts 'hello'
  end
end
post = Post.new
post.hello #=> hello

定数 Post に入っている Class クラスのオブジェクトへ特異メソッドを定義してみる。


Post = Class.new do
  def hello
    puts 'hello'
  end
end
def Post.bye
  puts 'good bye'
end
Post.new.hello #=> hello
Post.bye       #=> good bye

Post.bye という呼出しができた。これはクラスメソッドの呼出しと同じ。
つまり、クラスメソッド Post.bye というのは、Post に入っている Class クラスのオブジェクトへの特異メソッドの定義として読むことができる。

これにオブジェクトの特異クラスの引き出しの記法 << をあわせて考えると、一番冒頭のコードでやろうとしていることがわかってくる。

特異クラス

クラスメソッドの定義は特異メソッド形式と特異クラス形式があった。

特異メソッド形式で定義した def Post.bye を特異クラス形式へ書きかえてみる。


Post = Class.new do
  def hello
    puts 'hello'
  end
end
class << Post
  def bye
    puts 'good bye'
  end
end
Post.new.hello #=> hello
Post.bye       #=> good bye

さらに書き換えると下記にようになる


class Post
  def hello
    puts 'hello'
  end

  class << self
    def bye
      puts 'good bye'
    end
  end
end
Post.new.hello #=> hello
Post.bye       #=> good bye

クラスメソッドのための記法があるわけではなく、特異メソッドという仕組みを使って巧みにクラスメソッドが実現されていることがわかった。

おわりに

今まで何気なく使っていたself。
というかなんとなく理解できたようでできていなかった部分だった。

私が参考にした、というかこの記事はほぼ下記の記事のコピペなので、私の記事がわかりにくかったという方は、ぜひ下のURLの記事を参考にして欲しい。

参考記事

3
3
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
3
3