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

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

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

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

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

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


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

## attr_accessorの使用用途

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


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

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

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


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

```ruby: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種類あり、**メソッドを定義する方法**と**アクセスメソッドを使う方法**です。

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

```ruby:
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
```

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

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

```ruby:
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と同じような感覚でインスタンスの値に別の値を代入してみると…

```ruby:
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種類があります。

```ruby:
def name=(name)
    @name = name
end
```

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

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


```ruby:
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**を使います。

```ruby:
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種類を書かなくても

```ruby:
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とモデルという存在について](https://qiita.com/ichihara-development/items/9e9a8454178947eb519d)

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

## まとめ

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

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

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

それではー