6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Railsから入った自分は【attr_accessor】が何か全くわからなかった

Last updated at Posted at 2020-07-08

Rubyの基礎文法などを見ているとちょくちょく登場するattr_accessorというメソッド。

Ruby on Railsから入った自分は、最初見たときには全く使用用途が分かりませんでした。

そこからいろいろ調べてみるも

  • セッターとゲッターの両方を担うメソッド
  • インスタンス変数の値を参照、変更する

などなど正直理解不能です…

わかっている方には当た有前すぎて何言ってんだこいつ状態かもしれませんが、もし自分と同じところでつまずいた方がいらっしゃれば参考にしていただけると幸いです。

attr_accessorの使用用途

まずは問題のattr_accessorメソッドですが一言でいうとインスタンスに外部から参照、更新可能な属性を持たせるメソッドです。

一つ一つ解説していきます。

インスタンスの値には直接アクセスできない

Railsを使っていると忘れがちなのですが、大前提としてインスタンスの値には直接アクセスすることはできません。

例として以下にHogeクラスを用意しました。インスタンス変数としてnameageの2つがあります。

attr_accessor.rb


class Hoge

  def initialize(name, age)
    @name = name
    @age = age
  end


  def hello
    p "Hello! I'm #{@name} "
    p "I'm #{@age} old"
  end
end

hoge = Hoge.new("hogehoge",12)
hoge.hello

p hoge.name

この状態でHogeのインスタンスであるhogeの変数であるnameを出力しようとしてみると…

"Hello! I'm hogehoge "
"I'm 12 old"
Traceback (most recent call last):
attr_accessor.rb:33:in `<main>': undefined method `name' for #<Hoge:0x0000000004e68eb8 @name="hogehoge", @age=12> (NoMethodError)

とNoMethodErrorが発生します。

それもそのはず。Hogeクラスにはnameというメソッドが存在していないためです。

こういったインスタンスの値にアクセスできない問題を解決するためにセッターゲッターというメソッドが出てきます。

ゲッター

先ほどのようにインスタンスの値を参照したいときに使われるのがゲッターです。ゲッターの設定方法には2種類あり、メソッドを定義する方法アクセスメソッドを使う方法です。

メソッドを定義する方法は実にシンプルで

class Hoge

  def initialize(name, age)
    @name = name
    @age = age
  end
 
 # インスタンス変数と同じ名前にすることで値の参照を実現させる
  def name
    name = @name
  end

  def hello
    p "Hello! I'm #{@name} "
    p "I'm #{@age} old"
  end
end

と実行した際にインスタンス変数を引っ張ってくるメソッドを定義します。

ただこれだと少しかっこ悪いのでアクセスメソッドを使った方がまとまりが良いです。

class Hoge
  attr_reader :name

  def initialize(name, age)
    @name = name
    @age = age
  end


  def hello
    p "Hello! I'm #{@name} "
    p "I'm #{@age} old"
  end
end

attr_readerメソッドを使いことで上のようにインスタンス変数の値を参照できます。この際定義する値はインスタンス変数で定義したものと同じでなければいけません。

これが値を参照するためのゲッターという役割です。

セッター

それでは値の参照ができるようになったので、Railsと同じような感覚でインスタンスの値に別の値を代入してみると…

class Hoge

  attr_reader :name

  def initialize(name, age)
    @name = name
    @age = age
  end

  def hello
    p "Hello! I'm #{@name} "
    p "I'm #{@age} old"
  end

end

hoge = Hoge.new("hogehoge",12)
hoge.hello
p hoge.name
hoge.name = "fugafuga"


--------------------------------------------------------------------------------

"Hello! I'm hogehoge "
"I'm 12 old"
"hogehoge"
Traceback (most recent call last):
attr_accessor.rb:37:in `<main>': undefined method `name=' for #<Hoge:0x0000000004fbb040 @name="hogehoge", @age=12> (NoMethodError)
Did you mean?  name

とまたもや怒られてしまいます。

これはゲッターでは値を参照することができても、更新する機能は含まれていないので新しい値を代入できないためです。

この問題を解決するために使われるのがセッターと呼ばれるものです。

セッターもメソッドをそのまま定義する方法とアクセサメソッドを使う方法の2種類があります。

def name=(name)
    @name = name
end

メソッドの後に**=**を付けるとセッターになります。
内容はシンプルで受け取った引数をインスタンス変数に反映するだけです。

アクセサメソッドを使う方法。

class Hoge

  attr_reader :name
  attr_writer :name

  def initialize(name, age)
    @name = name
    @age = age
  end

  def hello
    p "Hello! I'm #{@name} "
    p "I'm #{@age} old"
  end
end

アクセサメソッドはattr_writerを使います。

hoge = Hoge.new("hogehoge",12)
hoge.hello
p hoge.name
hoge.name = "fugafuga"
hoge.hello

------------------------------------------------------

"Hello! I'm hogehoge "
"I'm 12 old"
"hogehoge"
"Hello! I'm fugafuga "
"I'm 12 old"

と確かにnameの値が更新されています。

attr_accessor

いよいよattr_accessorの解説ですが上記のゲッターとセッターの両方を担うのがこのメソッドの役割ということになります。

つまりattr_reader, attr_writerの2種類を書かなくても

class Hoge
  # この一行でゲッターとセッターの役割を果たしている
  attr_accessor :name

  def initialize(name, age)
    @name = name
    @age = age
  end

  def hello
    p "Hello! I'm #{@name} "
    p "I'm #{@age} old"
  end
end

hoge = Hoge.new("hogehoge",12)
hoge.hello
p hoge.name
hoge.name = "fugafuga"
hoge.hello

----------------------------------------------------------

Hello! I'm hogehoge "
"I'm 12 old"
"hogehoge"
"Hello! I'm fugafuga "
"I'm 12 old"

とかなりシンプルに書くことができます。

ここまで読んでいて不思議に思ったかもしれませんが、Railsでは通常このアクセサメソッドは出てきません。

ではなぜメソッドのようにテーブルの値を参照、更新できているのかというと、ActiveRecord::Baseで自動機的に設定されているからです。

よければそのことについても記事を書いているのでご覧下さい
>> rails db:migrateとモデルという存在について

ここまでがattr_accessorの解説になります。

まとめ

メソッド 機能 役割
attr_reader ゲッター インスタンス変数の値を参照できるようになる
attr_writer セッター  インスタンス変数の値を更新できるようになる
attr_accessor ゲッター・セッター  インスタンス変数の値を参照、更新できるようになる

Ruby on Railsは非常に便利なフレームワークですが、時々Rubyの基礎を勉強し直さないといけないなと強く思いました…

皆様も是非一度この辺りの内容を自分でコードを書いてみることをおすすめします!

それではー

6
1
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
6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?