Chloe
Chloe

Reputation: 26264

How do I clone a Rails model attribute?

How do I clone a single attribute in a Rails model? This didn't work:

irb(main):309:0> u.reload
=> #<User id: 1, username: "starrychloe", ...
irb(main):310:0> u2 = u.dup
=> #<User id: nil, username: "starrychloe", ...
irb(main):311:0> u2 = u.clone
=> #<User id: 1, username: "starrychloe", ...
irb(main):312:0> u2.username = u.username.clone
=> "starrychloe"
irb(main):313:0> u2.username = 'star'
=> "star"
irb(main):314:0> u.username ############ Changes original
=> "star"

Neither did this:

irb(main):320:0> u.reload
=> #<User id: 1, username: "starrychloe", ...
irb(main):321:0> u2 = u.clone
=> #<User id: 1, username: "starrychloe", ...
irb(main):322:0> u2[:username] = u[:username].clone
=> "starrychloe"
irb(main):323:0> u2.username = 'cow'
=> "cow"
irb(main):324:0> u.username ############ Changes original
=> "cow"

#dup doesn't copy the ID, and #clone on the attribute keeps the reference to the same string. This will not solve my problem.

Upvotes: 2

Views: 4161

Answers (5)

Chloe
Chloe

Reputation: 26264

I ended up making copies of each of the fields I wanted to keep track of:

@oldUsername = @user.username.clone

User.new looked promising, but it treated the copy as a new object, when it was an existing model, and output invalid forms to edit the model in the views:

> app.controller.view_context.form_for u2 do end   # This is from Rails console
=> "<form accept-charset=\"UTF-8\" action=\"/users\" class=\"new_user\" id=\"new_user_1\" method=\"post\">

So it would attempt to PATCH to /users (from the view), which is invalid, when it should PATCH to /users/1/.

It's unbelievable that Rails won't clone objects correctly. In Java, you could use u2.setProperty( u.getProperty().clone() ) and be sure to have a new object that won't interfere with the old one.

Upvotes: 0

BroiSatse
BroiSatse

Reputation: 44685

You might wanna look into amoeba gem. https://github.com/rocksolidwebdesign/amoeba

Upvotes: 1

bjhaid
bjhaid

Reputation: 9762

To make a copy of the instance with its attributes and de-reference you can do this:

u2 = u.class.new(u.attributes)

Upvotes: 0

Victor Ronin
Victor Ronin

Reputation: 23268

u2 = User.new(u.attributes.merge(username: "cow"))

Also, take a look at this question. It has a lot of interesting info on similar subject: What is the easiest way to duplicate an activerecord record?

Upvotes: 2

Mark Swardstrom
Mark Swardstrom

Reputation: 18080

Do you want to duplicate an instance or an attribute?

To duplicate an instance, use u2 = u.dup not u2 = u.clone.

Upvotes: 1

Related Questions