Reputation: 473
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: '[email protected]',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: '[email protected]',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.
Upvotes: 1
Views: 1405
Reputation: 1999
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: '[email protected]',
password: 'password',
employee_id: employee.id)
u = user.dup
u.save!
Upvotes: 1