本記事の概要
ProgateのRails学習コース内で、インスタンスメソッド内で使用するselfについて、
その仕様を自分なりに噛み砕いてまとめています。
誰向けの記事か
selfの使い方について、Progate内の解説が簡素すぎて、よく分からなかった人向け(私がそうでした)
問題の箇所
Postsテーブル:id,content,user_id
Usersテーブル:id, name,email
def user
return User.find_by(id: self.user_id)
end
# ターミナルでrails consoleを実行したのち、以下を実行
post = Post.find_by(id:1)
post.user
#結果=>
id:1,
name:hogehoge ~~~
スライド内の解説
Postモデル内にその投稿に紐付いたuserインスタンスを戻り値として返すuserメソッドを定義しましょう。
インスタンスメソッド内で、self はそのインスタンス自身を指す
「selfはそのインスタンス自身を指す」←?????
#自分なりに処理の流れを追ってみた
まず、Progateのスライドでは、Controller内ではなくコンソールで、インスタンスメソッドであるuserを呼び出している点に注意です。
演習では、インスタンスメソッドであるuserの呼び出しは、posts_controllerで行います。
そちらでどう記述するか、を先に見てしまいましょう。
以下になります。
def show
@post = Post.find_by(id: params[:id])
@user = @post.user
end
インスタンスメソッドuserを定義しているコードと合わせて、見てみましょう。
以下です。
def user
return User.find_by(id: self.user_id)
end
そして、スライドの解説文をもう一度。
インスタンスメソッド内で、self はそのインスタンス自身を指す
インスタンスメソッドuser内の self は、インスタンスメソッドuserを呼び出すインスタンス自身を指している、ということです。
実際にuserが使用されているcontrollerをもう一度見てみましょう。
def show
@post = Post.find_by(id: params[:id])
@user = @post.user
end
@user = @post.user
↑↑まさにここで、インスタンスメソッドuserが呼び出されていますね。
そして、呼び出しているインスタンスは、@postです。
インスタンスメソッドuser内の self は、
インスタンスメソッドuserを使用するインスタンスである@postを指している、
ということです。
では、@postの中身は何かというと、
@post = Post.find_by(id: params[:id])
⇨「Postテーブルの中身を、idで検索して得られた結果」です。
Postsテーブルのカラムは、id,content,user_id であり、それぞれに値が入っています。
・インスタンスメソッドuser内の self は、
インスタンスメソッドuserを使用するインスタンスである@postを指している
・@postの中身は、Postテーブルの中身を、idで検索して得られた結果
それを踏まえて、再度、インスタンスメソッドuserの中身を見てみましょう。
def user
return User.find_by(id: self.user_id)
end
⇨@postの中身から、user_idを取り出して(参照して、が正しいか?)、
Userテーブルについて、そのuser_idをidとして検索し、
その結果をreturnする
というのが、インスタンスメソッドuserの中身である、ということになります。
Userテーブルにはuser_idというカラムは存在しませんが、Postテーブルのuser_idとUserテーブルのidが等しいため、
Userテーブルでの検索条件に@post.user_idを用いることで、PostテーブルとUserテーブルを関連づけた形の検索結果が得られる、ということになります。
#Progate以外での、selfの使用例
Qiitaの記事で、ズバリな解説をしてくださっているものがありましたので引用いたします。
https://qiita.com/leavescomic1/items/99f32f45cd04035f146c#%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89
以下引用ーーーーーーーーーーーーーーーーーーーーーーーーーーーー
以下のusers_controllerの@userがインスタンスになります。
@user = User.find(params[:id])
#findはインスタンスを探すメソッド
#Userクラスから調べたいidに該当するユーザー情報をデータベースから取得しています。
@my_age = @user.too_young
#@userというインスタンスにtoo_youngというメソッドを使っている。
ここで、@userというインスタンスに対してtoo_youngというメソッドが使われています。
@userというインスタンスに使うメソッド....これがインスタンスメソッドとなります。
もう一度user.rb内に記載されているtoo_youngメソッドを見てみましょう。
class User < ApplicationRecord
validates :username, presence: true
validates :email, presence: true
#ここがインスタンスメソッド
def too_young
if self.age >= 20 #20歳以上の場合
return "大人です!"
else #20歳以下の場合
return "子供です!"
end
end
end
too_youngメソッド内に「self」というものがあります。
この「self」は何かというとusers_controller.rbで定義された@userのことです。
@userというインスタンスに対して「.(ドット)」で繋げてインスタンスメソッドを呼び出す時、インスタンスメソッド内では「self」が使え、self=呼び出し元のインスタンス(@user)となります。
今@userの中身は
user.rb
id: 1, username: "山田太郎", email: "hogehoge@example.com", age: 28
なので、self.ageでageカラムの値が呼びだされ、「28」という数字が返ってきます。
引用ここまでーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
#おわりに
Progateは、初学者にとって非常に便利な学習サイトですが、解説がシンプルすぎる箇所があります。
理解が曖昧だと感じたときは、その箇所を使ったコードをProgate以外で探して見ると、理解が深まります。
(更に、その部分について自分のローカル環境でコーディングして、改変してエラーを出す、などしてみるのが、最も仕様を理解できる手段です)
今回の self がどのくらい重要かは正直今の知識ではよく分からないですが、
色々と調べてみて、「多分こういうことだろう」と理解できたのは自分にとってプラスになったと感じたので、
備忘録的な形で記事として残すこととします。
万が一、同じように詰まっている人がいたら、少しでも参考にしていただければと思います。