1

In my ruby on rails application I have a problem while I'm trying to save a model after cloning it. I have the following models.

class Company < ApplicationRecord

    has_many :employees

end

class Employee < ApplicationRecord

    belongs_to :company
    has_one :user   

end

class User < ApplicationRecord

    belongs_to :employee

end

When I user the following piece of code I get 'ActiveRecord::RecordInvalid: Validation failed: Employee must exist' error.

company = Company.new
employee = Employee.new(company: company)
user = User.new(name: 'John',email:   'example@gmail.com',password: 'password')
user.employee = employee

u = user.dup

u.save!

On the other hand, when I use 'clone' instead of 'dup' Rails tries to save User model twice and this leads exception

company = Company.new
employee = Employee.new(company: company)
user = User.new(name: 'John',email:   'example@gmail.com',password: 'password')
user.employee = employee

u = user.clone

u.save!  

If I save model without dupping and cloning, there is no problem. In my application I'm using builder pattern and have to use one of the methods of dup or clone.

I can't see what I'm missing.

Any suggestions ?

Thanks.

Adamantish
  • 1,888
  • 2
  • 20
  • 23
Hilmi Yamcı
  • 463
  • 8
  • 20
  • What is your use case for cloning the model? – teacher Aug 12 '17 at 19:04
  • Indeed, it seems this might not be the use of builder pattern intended by your instructor or boss. I'd go and check carefully because there isn't a clear value to the duplication in this context. – Adamantish Aug 12 '17 at 19:13

1 Answers1

1

In both cases the trouble is the association you're making before duplicating. This is one of those things that's hard to do because there are better ways to approach it in the real world.

In general duplicating things gets sticky when they're attached to other things. It's not clear from a command like clone which of the attached things you also want to duplicate and in which way and what about the things attached to those? That's why you'll have to write more explicit code.

As this answer explains, dup doesn't copy associations. With clone both your original user and the clone are attached to the same employee. I can't imagine this would be your intention if making something like this for real and indeed it confuses active record into cascading the save back to the original object.

It's more likely that you want to make a new employee for each duplicated user so handle that step after duplication not before.

However, if all users really should belong to the same employee (or you needed to make an association with some more credible template value like the company) then you can create that database record up-front then refer to it explicitly as a record rather than as a ruby object.

 company = Company.new
 employee = Employee.create!(company: company)
 user = User.new(name: 'John', 
                 email: 'example@gmail.com',
                 password: 'password', 
                 employee_id: employee.id)

 u = user.dup

 u.save!
Adamantish
  • 1,888
  • 2
  • 20
  • 23