What's the difference between Rails dup and clone methods? [duplicate] - ruby-on-rails

This question already has answers here:
What's the difference between Ruby's dup and clone methods?
(6 answers)
Closed 7 years ago.
I need to know the difference between Rails dup and clone methods, because dup duplicates the id attribute and clone doesn't:
juan:~/alhambra$ rails c
Loading development environment (Rails 3.0.1)
1.9.3-p551 :001 > #user=User.last
=> #<User id: 2, email: "ferbad12#hotmail.com", encrypted_password: "$2a$10$/Fsz8DZ9PQbReTU1.wyxS.m3IOxZSV3siKDrrtUJdupz...", password_salt: "$2a$10$/Fsz8DZ9PQbReTU1.wyxS.", reset_password_token: nil, remember_token: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2015-05-06 23:34:20", last_sign_in_at: "2015-05-06 23:34:20", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", created_at: "2015-05-06 23:33:37", updated_at: "2015-05-06 23:34:20">
1.9.3-p551 :002 > #user.clone
=> #<User id: nil, email: "ferbad12#hotmail.com", encrypted_password: "$2a$10$/Fsz8DZ9PQbReTU1.wyxS.m3IOxZSV3siKDrrtUJdupz...", password_salt: "$2a$10$/Fsz8DZ9PQbReTU1.wyxS.", reset_password_token: nil, remember_token: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2015-05-06 23:34:20", last_sign_in_at: "2015-05-06 23:34:20", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", created_at: "2015-05-06 23:33:37", updated_at: "2015-05-06 23:34:20">
1.9.3-p551 :003 > #user.dup
=> #<User id: 2, email: "ferbad12#hotmail.com", encrypted_password: "$2a$10$/Fsz8DZ9PQbReTU1.wyxS.m3IOxZSV3siKDrrtUJdupz...", password_salt: "$2a$10$/Fsz8DZ9PQbReTU1.wyxS.", reset_password_token: nil, remember_token: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2015-05-06 23:34:20", last_sign_in_at: "2015-05-06 23:34:20", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", created_at: "2015-05-06 23:33:37", updated_at: "2015-05-06 23:34:20">

In rails 3.0, dup and clone performed essentially opposite roles as to what they do now. From ActiveRecord::Base:
Cloned objects have no id assigned and are treated as new records. Note that this is a "shallow" clone as it copies the object's attributes only, not its associations. The extent of a "deep" clone is application specific and is therefore left to the application to implement according to its need.
While it can be seen in the same file that dup simple copied the record and its attributes:
def dup
obj = super
obj.instance_variable_set('#attributes', #attributes.dup)
obj
end
This differs from current rails 4, which defines dup and clone to more follow the note from the ruby docs, noted in a similar question not specific to rails.
In general, clone and dup may have different semantics in descendent classes. While clone is used to duplicate an object, including its internal state, dup typically uses the class of the descendent object to create the new instance.
As can be seen from the from the more current ActiveRecord source:
##
# :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).

The tutorial explains this, everything opposite what my console displays
p1 = Post.create(title: 'Post 1', message: 'Amazing message')
p3 = p1.clone
p3.title = "This is now p3"
p1 #=> #<Post id: 1, title: "Post 1", message: "Amazing message", created_at: "2014-07-01 19:45:44", updated_at: "2014-07-01 19:45:44">
p3 #=> #<Post id: nil, title: "This is now P3", message: "Amazing message", created_at: nil, updated_at: nil>

Related

Rails upgrade 3.2.* to 4 Does not show all user attributes in rails console

Kind of an odd bug I am running into. Working on upgrading a Rails app from 3.2.22.1 tp 4.2.11.3. Everything is working pretty well. Test suite is passing on green. However when I go into the rails console and do user = User.new or list the attributes using User.new.attributes I am only getting a few of the fields returned.
Specifically
{"_id"=>BSON::ObjectId('XXxxXXxxxxXXXxXX'),
"email"=>"",
"encrypted_password"=>"",
"sign_in_count"=>0,
"time_zone"=>"Central Time (US & Canada)",
"admin"=>false}
This list should be much larger, for example, it is excluding all Devise fields like last_sign_in_at or any of them. Here is what it looks like, the same command, run on our production server which is the previous version of rails
_id: xxxXXXxxxXXXXxXXXXxx,
invited_by_type: nil,
invited_by_field: nil,
invited_by_id: nil,
email: "",
encrypted_password: "",
reset_password_token: nil,
reset_password_sent_at: nil,
remember_created_at: nil,
sign_in_count: 0,
current_sign_in_at: nil,
last_sign_in_at: nil,
current_sign_in_ip: nil,
last_sign_in_ip: nil,
confirmation_token: nil,
confirmed_at: nil,
confirmation_sent_at: nil,
unconfirmed_email: nil,
invitation_token: nil,
invitation_created_at: nil,
invitation_sent_at: nil,
invitation_accepted_at: nil,
invitation_limit: nil,
name: nil,
time_zone: "Central Time (US & Canada)",
admin: false
I am worried that there is something failing silently and I am not detecting it. I can save the unlisted values in the console, but it does not show them to me, which is not how it worked previously.
Anyone understand why this is happening?
specific versions are:
mongid -> 5.0.1
devise -> 4.7.2
Rails -> 4.2.11.3
Latest version of Mongoid does not include attributes that were never written in attributes.
Unless you have references to documentation that claims that Mongoid would return attributes that were never written, you are experiencing expected behavior.

Rails 4 - mapping

I have a user model and a profile model.
The associations are:
user has_one :profile
profile belongs_to :user
I have a user model which I am trying to use to create a profile when a new user is first created. I only want to run this method if the user is new.
I have this callback method in user.rb:
after_create :build_profile
def build_profile
Profile.create(user: self) # Associations must be defined correctly for this syntax, avoids using ID's directly.
# Profile.save
end
When I save this and go through my authentication process (using devise & omniauth), I get this runtime error:
RuntimeError (Could not find a valid mapping for [#<User id: 1, first_name: "Me", last_name: "Ma", email: "me#gmail.com", encrypted_password: "$2a$10$KCZn..HS2GuGjvlcNtfAH/28.DQoWetO...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 16, current_sign_in_at: "2015-12-15 09:57:14", last_sign_in_at: "2015-12-15 09:27:07", current_sign_in_ip: #<IPAddr: IPv4:49, last_sign_in_ip: #<IPAddr: IPv4:49.195>, confirmation_token: nil, confirmed_at: "2015-12-15 09:02:58", confirmation_sent_at: "2015-12-15 08:42:48", unconfirmed_email: nil, failed_attempts: 0, unlock_token: nil, locked_at: nil, created_at: "2015-12-09 23:53:20", updated_at: "2015-12-15 09:57:14", image: nil>, #<Profile id: 1, user_id: 1, title: nil, hero_image: nil, overview: nil, occupation: nil, external_profile: nil, working_languages: nil, created_at: "2015-12-18 21:58:49", updated_at: "2015-12-18 21:58:49">]):
I'm not sure what this mapping error means.
I have a user_id integer in my profiles table and it seems to be referencing the relevant user id properly.
I tried adding profile.save to the build_profile method, but the same error is generated, so I don't thing that helps.
Can anyone see what's going wrong?

How can a user be saved without a created_at?

This is a weird question... The context is that somehow, my program keeps creating weird arbitrary blank users with no information. I'm trying to debug it because it's certainly annoying but I don't want it to have some potentially other problems.
I'd like to debug it by figuring out when these random blank users were created and then looking at the logs with that time stamp. Unfortunately the user looks like this:
#<User id: 175, email: "", created_at: nil, updated_at: nil, encrypted_password: "", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, confirmation_token: nil, confirmed_at: nil, confirmation_sent_at: nil, unconfirmed_email: nil, failed_attempts: 0, unlock_token: nil, locked_at: nil, stripe_customer_id: nil, stripe_card_id: nil, invite_code: nil, invited_by: nil, profile_pic: nil, first_name: nil, last_name: nil, full_name: nil>
I didn't realize it was possible to have this happen (creation without created_at), so am curious to see what could lead to this, and maybe that will help the debugging.
FYI I have tried to just look at my log over a long time period but the weird thing is I definitely do NOT see the actual create action being called so many times. I even have a puts statement right after the create just to catch this and it has only been logged twice (the appropriate amount). FWIW I'm using Devise.
Thanks

test error:-in Ruby on rails

I'm working with ruby on rails and I'm having a problem while running a "ruby -Itest test/models/user_test.rb". I get an error when I make changes in the regular expression /^[a-zA-Z0-9-]+$/ and now I am stuck in this problem and I don't know how to get over it.
My user.rb file:-
validates :profilename, presence: true,
uniqueness: true, format: { with: /^[a-zA-Z0-9-]+$/ , multiline: true,
message: 'Must be formatted correctly.' }
Running test:-
$ ruby -Itest test/models/user_test.rb
DL is deprecated, please use Fiddle
Run options: --seed 50723
Running:
.....#<ActiveModel::Errors:0x4ecc8a0 #base=#<User id: nil, first_name: "sarah", last_name: "gupta", profile_name: "S_arah-1", email: "sarah089#gma
il.com", encrypted_password: "", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at
: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: nil, updated_at: nil>, #messages={}>
E..
Finished in 0.380267s, 15.7784 runs/s, 28.9270 assertions/s..
1) Error: UserTest#test_a_user_can_have_a_correctly_formatted_profile_name: ArgumentError: wrong number of arguments (0 for 1..2) test/models/user_test.rb:41:in `block in <class:UserTest>'
6 runs, 11 assertions, 0 failures, 1 errors, 0 skips
Here is the code for a_user_can_have_a_correctly_formatted_profile_name
test "a user can have a correctly formatted profile name" do
user = User.new(first_name: 'sarah', last_name: 'gupta', email: 'sarah089#gmail.com')
user.password = user.password_confirmation = 'welcome'
user.profile_name = 's_arah-1'
assert.user.valid?
end
Thanks for your help!
It looks like the answer to your question is in the file user_test.rb. Try checking where test_a_user_can_have_a_correctly_formatted_profile_name is defined, and where it's called: according to the error, it's being called without the required one or two arguments. I'm guessing you need to give it a test username.

"Password can't be blank" error when seeding database

I'm attempting to seed my database using the data that I grabbed with the seed_dump gem, found here. Anyway, the seed file generated looks legit, but it seems to be falling afoul of the user model validation:
ActiveRecord::RecordInvalid: Validation failed: Password can't be blank
To give an idea the seed looks like this:
User.create!([
{email: "1234#localhost", encrypted_password: "$2a$10$5eoHh6M2q4GjGkHClO.NqebWWhS94D8rNj5Ot6CB2qrbn7IrTfkSa", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2014-12-31 22:27:09", last_sign_in_at: "2014-12-31 22:27:09", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", admin: false}
])
Also, I'm using the devise gem for users management.
Is there an elegant way to seed the user data given this filter?
You can do:
u = User.new([
{email: "1234#localhost", encrypted_password: "$2a$10$5eoHh6M2q4GjGkHClO.NqebWWhS94D8rNj5Ot6CB2qrbn7IrTfkSa", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2014-12-31 22:27:09", last_sign_in_at: "2014-12-31 22:27:09", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", admin: false}
])
u.save!(validate: false)
Had the same issue. The User.new solution did not work for me.
The following solution did work, from similar question on "Seeding Users with Devise" here:
Seeding users with Devise in Ruby on Rails
In short, replace the encrypted_password with password and a plain text password you are comfortable using.
Example:
User.create!([
{email: "1234#localhost", password: "some_password", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2014-12-31 22:27:09", last_sign_in_at: "2014-12-31 22:27:09", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", admin: false}
])
You can then run rake db:seed. Rails will do its magic (by automatically creating the encrypted_password hash) for each user, and you will be able to login normally.

Resources