YASD-TECH
YASD TECH
# Ruby

attr_accessorが定義するゲッターとセッター(user= はメソッド名)

投稿日:2026/8/11

更新日:2026/8/11

ttitleImage

attr_accessor が定義するゲッターとセッター(user= はメソッド名)

attr_accessor :user を展開すると def userdef user=(value) の2つになる、という説明を読んで
「なぜ = が付くのか」「def user(value) ではダメなのか」で詰まったのでまとめた。
結論から言うと、= はお作法ではなくメソッド名の一部で、これが無いと代入の構文そのものが使えない。

結論

  • インスタンス変数 @user は外から直接触れない。だから読み書きの窓口としてメソッドが要る
  • foo.user = 値 は変数への代入ではなく、user= という名前のメソッドの呼び出し
  • useruser= は名前の違う別々のメソッド。ゲッターとセッターは「同じメソッドの2つの顔」ではない
  • def user(value) でも Ruby としては動くが、foo.user = 値 が書けず、ゲッターと共存もできず、Rails の一括代入も壊れる
  • attr_accessor が作るのは変数ではなくメソッド。だからクラス内では self.user = 値 と書く必要がある

なぜメソッドが要るのか

Ruby のインスタンス変数(@ で始まるもの)は、そのオブジェクトの中からしか読み書きできない

ruby
class Foo
  def initialize
    @user = "たろう"
  end
end

foo = Foo.new
foo.@user   # ← 文法エラー。そもそもこう書けない

Java の private フィールドと同じで、外部から直接アクセスする手段が言語レベルで存在しない。
外から触りたいなら、メソッドを経由するしかない

ruby
class Foo
  def user            # ゲッター(読む窓口)
    @user             # @user の中身を返すだけ
  end

  def user=(value)    # セッター(書く窓口)
    @user = value     # 渡された値を @user に入れるだけ
  end
end

foo = Foo.new
foo.user = "たろう"   # セッターが呼ばれる
foo.user              # => "たろう"  ゲッターが呼ばれる

attr_accessor :user は、この2つのメソッドをその場で定義するだけのショートカット(Module が持つマクロ)。
Rails の機能ではなく素の Ruby の話。

書き方 定義されるもの
attr_reader :user user(ゲッターだけ)
attr_writer :user user=(セッターだけ)
attr_accessor :user useruser=(両方)

foo.user = 値 は代入ではない

ここが最大の勘所。代入しているように見えて、実際は = までを含めた user= というメソッドを呼んでいる。

ruby
foo.user = "たろう"
# ↓ Ruby が内部でやっていること(こう書いても同じ)
foo.user=("たろう")
foo.send(:user=, "たろう")

Ruby では = ? ! をメソッド名の末尾に使える。def user=(value)= はタイポではなく名前の一部。

flowchart TD
    W["foo.user = 値 と書いた"] --> W2["user= という名前のメソッドを探す"]
    W2 --> W3["見つかったら実行して @user に代入"]
    R["foo.user と書いた"] --> R2["user という名前のメソッドを探す"]
    R2 --> R3["見つかったら実行して @user を返す"]

つまり useruser= は、Ruby から見ると foofoo! くらい別物の名前

書き方 呼ばれるメソッド名 何をするか
foo.user user @user を返す(読む)
puts foo.user user 同上。右辺が無ければ常にゲッター
foo.user = "たろう" user= @user に入れる(書く)

見分け方は単純で、foo.user の後ろに = 値 が続いているかどうかだけ。

どちらが呼ばれたか自信が無いときは、def user; p "ゲッター"; @user; end のように p を仕込むと一発で分かる。


def user(value) ではなぜダメか

引数を1つ取る普通のメソッドとして定義すること自体は、Ruby の文法上まったく問題ない。

ruby
class Foo
  def user(value)
    @user = value
  end
end

foo.user("たろう")   # => 動く。ただのメソッド呼び出し

動くのに使わないのは、次の3つを失うから。

= を使った代入が書けない

ruby
foo.user = "たろう"
# => NoMethodError: undefined method `user=' for an instance of Foo

Ruby は .user = という構文を見たら、必ず user= という名前のメソッドを探しに行く。
user という名前のメソッドで代用してはくれない。

② ゲッターと共存できない

Ruby にはオーバーロード(同名で引数違いのメソッド)が無い。後から定義した方が前を上書きする。

ruby
class Foo
  def user          # 読む用
    @user
  end

  def user(value)   # ← 上書きしてしまう。読む用が消える
    @user = value
  end
end

foo.user   # => ArgumentError: wrong number of arguments (given 0, expected 1)

user= という別名にすることで、初めて読み書きの2つを同時に持てる。

③ Rails の一括代入が動かなくなる

実務でいちばん効くのはこれ。Rails は属性を代入するとき、内部でほぼ必ず send("#{キー名}=", 値) を呼んでいる。

sequenceDiagram
    participant C as コントローラ
    participant F as SignupForm
    participant S as セッター email=
    C->>F: SignupForm.new(email: "x")
    F->>S: send("email=", "x")
    S->>S: @email に "x" を代入
ruby
SignupForm.new(email: "x", company_name: "y")
form.assign_attributes(email: "z")
form.update(params)

これらは全部 email= company_name= を探して呼び出す。
def email(value) と定義していると、どれも NoMethodError になる。
フォームオブジェクトで attr_accessor を書くのは、この規約に乗るため。


ハマりどころ

クラス内では self. が要る

attr_accessor が作るのはメソッドであって変数ではない@user は、セッターが初めて呼ばれたときに生まれる。
そのためクラスの内部で self. を省くと、セッターではなくローカル変数への代入になる。

ruby
class Foo
  attr_accessor :user

  def do_something
    user = "たろう"        # ← バグ。ローカル変数を作っただけでセッターは呼ばれていない
    self.user = "たろう"   # ← 正解。self を付けて初めてセッターが呼ばれる
  end
end

読むときは user だけで済む(self.user でもよい)のに、書くときだけ self. が必須になるのが非対称でハマりやすい。

セッターの戻り値は無視される

セッターだけの特殊ルールとして、中で何を返しても代入式全体の値は右辺の値になる

ruby
class Foo
  def user=(value)
    @user = value
    "何か別の値"    # 何を返しても……
  end
end

result = (foo.user = "たろう")
result   # => "たろう"   ← 右辺がそのまま返る

「代入式の値は代入した値」という直感を壊さないための仕様。
セッターの戻り値を工夫しても呼び出し側は受け取れないので、return で何かを返す設計にしない。


参考

Index

  • attr_accessor が定義するゲッターとセッター(user= はメソッド名)
  • 結論
  • なぜメソッドが要るのか
  • foo.user = 値 は代入ではない
  • def user(value) ではなぜダメか
  • ① = を使った代入が書けない
  • ② ゲッターと共存できない
  • ③ Rails の一括代入が動かなくなる
  • ハマりどころ
  • クラス内では self. が要る
  • セッターの戻り値は無視される
  • 参考