何の話?
変数について、参照の値渡し(共有渡し)とか。
まぁ、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_id
とlast_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
処理がよほど重たい場合などはクラスインスタンス変数を使うなどすると良いですよ。