RubyのcloneとdupとActiveRecordのcloneとdupは別物?
Rubyのcloneとdupの動き
クラス定義
class Hoge
attr_accessor :name
end
clone
h = Hoge.new
hc = h.clone
h.name = 'name'
hc.name = 'clone'
h.name #=> 'name'
dup
h = Hoge.new
hd = h.dup
h.name = 'name'
hd.name = 'dup'
h.name #=> 'name'
ActiveRecordのcloneとdupの動き
clone
p = Piyo.find(1)
p.name = 'name'
pc = p.clone
pc.name = 'clone'
p.name #=> 'clone'
dup
p = Piyo.find(1)
p.name = 'name'
pd = p.dup
pd.name = 'dup'
p.name #=> 'name'
挙動まとめ
Rubyのcloneとdupはどちらもオリジナルのアトリビュートを変更しない。
ActiveRecordのcloneはオリジナルのアトリビュートを変更する。
ActiveRecordのdupはオリジナルのアトリビュートを変更しない。
参考資料
こちらの記事 を参考にさせていただきActiveRecord オブジェクトをコピーしようと思ったのですが、Rails3.1以降でdupとcloneの動作が逆になったようです。
RubyとARで違うような挙動な上に、途中で仕様が変わっているようで、混乱しています。私はRails4を想定しています。
* https://github.com/rails/rails/blob/master/activerecord/lib/active_record/core.rb#L356
# :method: clone # Identical to Ruby's clone method. This is a "shallow" copy. Be warned that your attributes are not copied. # That means that modifying attributes of the clone will modify the original, since they will both point to the # same attributes hash. If you need a copy of your attributes hash, please use the #dup method. # # user = User.first # new_user = user.clone # user.name # => "Bob" # new_user.name = "Joe" # user.name # => "Joe" # # user.object_id == new_user.object_id # => false # user.name.object_id == new_user.name.object_id # => true # # user.name.object_id == user.dup.name.object_id # => false ## # :method: dup # Duped objects have no id assigned and are treated as new records. Note # that this is a "shallow" copy as it copies the object's attributes # only, not its associations. The extent of a "deep" copy is application # specific and is therefore left to the application to implement according # to its need. # The dup method does not preserve the timestamps (created|updated)_(at|on).
RoRのソースを見てみましたが、ドキュメント(コメント)はあるようですが、clone
とdup
の実装は見当たりませんでした。
質問
- RubyのcloneとdupとActiveRecordのcloneとdupは別物なのでしょうか?
- 違うとした場合、具体的にどのように違うのでしょうか?
If you need a copy of your attributes hash, please use the #dup method.
と書いてあるのは深いコピー
のことでしょうか?(Rubyのdupは浅いコピーなので別物になっている)