LoginSignup
2
1

More than 5 years have passed since last update.

インスタンスメソッド内での気をつけたい変数の取り扱い(参照の値渡し)

Last updated at Posted at 2016-06-21

何の話?

変数について、参照の値渡し(共有渡し)とか。

まぁ、Rubyの破壊的メソッドと参照の値渡しとほとんど同じです。

ダメな例

とりあえず以下のコードを見てください

last_name(string)とfirst_name(string)というattributeを持ったUserモデルについて、この2つを結合して返すメソッドを用意しています。

models/person.rb
class Person < ActiveRecord::Base
  def fullname
    str = last_name
    str << first_name
  end
end
controllers/people_controller.rb
class PeopleController < ApplicationController
  def show
    @person = Person.find( params[:id] )
  end
end  
views/people/show.html.erb
<%= @person.fullname %>

何が問題か

@person.fullnameがviewの中で2回呼ばれると期待しない値が返ってくる。

例えばlast_name:山田first_name:太郎というインスタンスについて、viewから2回呼び出すと山田太郎太郎が返ってきます。

なぜか

インスタンスメソッドのstr = last_nameのところが参照の値渡しになっており同一のオブジェクトを参照しています。(str.object_idlast_name.object_idは同一の値です)
したがってstrを更新すると、同時に@person.last_nameを更新しており、二回目に呼ばれた際にlast_nameは一回目の結果となるstr(山田太郎)を返すからです。
(インスタンスはpeople_controller.rbで呼び出している通り@person一つです。)

models/person.rb
class Person < ActiveRecord::Base
  def fullname
    puts last_name #一回目は'山田'、二回目は'山田太郎'
    str = last_name
    puts first_name #一回目も二回目も'太郎'
    str << first_name
    puts str #一回目は'山田太郎'、二回目は'山田太郎太郎'
    str #↑にputsを入れたので明示的にreturnしています。
  end
end

改善案

models/person.rb
class Person < ActiveRecord::Base
  def fullname
    last_name + first_name
  end
end

処理がよほど重たい場合などはクラスインスタンス変数を使うなどすると良いですよ。

参考

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