はじめに
Modelで定義したメソッドがControllerで呼び出せなくなったとき、
selfを使って2パターンの解決法を見つけたため、記録として残しておく。
今回は、helloという名前のメソッドをモデルで定義するという設定とする。
解決法1(特異メソッド方式)
class Post
def self.hello
puts 'hello'
end
end
メソッド名の前にself.をつけるやり方
ruby初学者なら何度も見たことのある形だ。
解決法2(特異クラス方式)
class Post
class << self
def hello
puts 'hello'
end
end
end
こちらでも、きちんとcontrollerで呼び出すことができた。
この場合だと、メソッド名の前にself.を書く必要もないし、class << self と end内であれば、
複数のメソッドを同じように定義できるのがメリットだ。
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の記事を参考にして欲しい。
参考記事