moiristo / deep_cloneable Goto Github PK
View Code? Open in Web Editor NEWThis gem gives every ActiveRecord::Base object the possibility to do a deep clone that includes user specified associations.
License: MIT License
This gem gives every ActiveRecord::Base object the possibility to do a deep clone that includes user specified associations.
License: MIT License
Is it possible to pre-fill a simple_fields_for
input with datas from another object ?
I have a User
object. User
has_one Backpack
, Backpack
has many Pockets
, and Pocket
has_many Items
When building my form, i'm using
<%= f.simple_fields_for :backpack do |backpack| %>
<%= render 'backpack', f:backpack %>
<% end %>
Now, when I'm on users#new
, the whole form is empty. I would like to initialize the Backpack
fields with datas from another Backpack
object, is it possible ? I tried by doing this:
<%= f.simple_fields_for :backpack, @backpack do |backpack| %>
<%= render 'backpack', f:backpack %>
<% end %>
along with this in my UsersController
:
@user = User.new
@backpack = Backpack.find(1).deep_clone include: [ :pockets, { pockets: :items } ]
But this doesn't work: for some reason, the Backpack
fields are filled, but his Pockets
and their Items
are empty (Only the direct attributes of Backpack
are pre-filled).
Did I miss something ?
From the README:
Pass a block to deep_clone to modify a duped object after duplication
My assumption after reading the above was that my block would get executed right before the copy was returned.
In particular, properties excluded with the except
parameter would be gone and any value I wrote to those fields would be included in the copy.
This isn't the case, as exclusion happens after the block is invoked.
For now I suggest adding something like the following to the docs:
Note: The block is invoked before properties are excluded
In a future version, I think invoking the block after all other processing would be more valuable.
I have troubles with Rails 5 and postgres:
foreign key field is not a number and some other fields are invalid
, any ballpark date for Rails 5 compatibility ?
I am duplicating an existing object as part of a new object creation action as follows:
@structure = @old_structure.deep_clone include: :steps
It's a document with a sequence of steps. When the form renders the steps, they are scoped as follows:
scope :ordered_steps, -> {
order("position ASC")
}
And the form itself renders the steps as follows:
<%= f.fields_for :steps, @structure.steps.ordered_steps do |builder| %>
<%= render 'step_fields', f: builder %>
<% end %>
When I have the scoping in there, none of the steps are rendered. When I remove the scoping, the steps show up. Is this a problem with my implementation or the gem?
Thank you.
Installing the gem brings in gems like sqlite, jeweller (then git). These look like they're only needed for development and testing. Is that intentional?
The usage of the following isnot in 2.1.1, please add a new version
ship.deep_clone include: [
pirates: [ :treasures, :mateys, if: lambda {|pirate| pirate.name == 'Jack Sparrow' } ]
]
this maybe mislead others, sush as me
It would be nice to be able to clone only an association while excluding all parent attributes like so:
pirate.deep_clone only: :treasures
Obviously, this can be done by including the association and then explicitly excluding the parent attributes:
pirate.deep_clone include: :treasures, except: Pirate.column_names
but I expected only
to work properly for this.
Sorry for no specs. I'm hoping this is just a misunderstanding on my end.
The following will clone 2 of the total 28 child flight lessons and 0 scenarios.
Course.find(2).dup(include: {:flightlessons => :scenarios}).update_attribute(:farpart_id, Farpart.find(1).id)
updating the farpart_id is needed to pass a scoped unique validation
Course
has_many :flightlessons
has_many :scenarios, through: :flightlessons (I get more cloned flight lessons if I comment this out)
Flightlesson
has_many :scenarios, as: :lesson, dependent: :destroy # poly
How can I alter this to get an accurate clone of child flightlessons: :scenarios?
Hi,
I'm facing an issue when cloning an object and its associations which is explained here
http://stackoverflow.com/questions/32633130/deep-clonable-associated-records-validation-issue.
Can someone help me
if i want to version clones, do i give them a root_id or the same id? or make the primary key (id, clone_id)?
With Ruby 2.0 and Rails 3.2-STABLE, the :include isn't working:
> question.dup :include => :choices
ArgumentError: wrong number of arguments (1 for 0)
Maybe it's not removing the original dup
correctly?
Fwiw, I first thought it was a bug in Rails because even regular dup
didn't work
> p.dup
NoMethodError: private method `initialize_dup' called for #<Question:0x007fd6fb9d9a98>
But I just switched updated Rails past this bug in Rails 3.2.x with Ruby 2.0 that was fixed in 3.12.13.
I have my associations as
Report
has_many :projects
has_many :project_milestones, through: :projects
has_many :members, through: :projects
accepts_nested_attributes_for :key_activities , :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :risks , :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :projects , :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :project_milestones , :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :members , :reject_if => :all_blank, :allow_destroy => true
and i try to deep clone
r = Report.last.deep_clone :include => [:key_activities, :risks, {:projects => [:project_milestones, :members]}]
i am getting all attributes except project_milestones and members
r.projects.last.members.last
=> #<Member:0x007f8234394ed8 id: nil, name: "", worked_hrs: "", created_at: nil, updated_at: nil, project_id: nil>
what could be wrong here? :o
I have an object a
of class A
that I want to clone. a
has a relation to a b
of class B
and to a c
of class C
. When cloning a
I want to include both b
and c
relation objects. According to the documentation this can be done like so:
a.deep_clone :include => [:b, :c]
Everything seems fine at the first sight. But here's my problem:
The object b
has a relation to the same c
that a
is already related to. This means object a
has a field c_id
with value (say) 42
and object b
also has a c_id
field with the same value 42
. When I now run the above code this leads to the following cloned objects:
<A-Class-Object id: 100, b_id: 120, c_id: 140>,
<B-Class-Object id: 120, c_id: 160>,
<C-Class-Object id: 140>,
<C-Class-Object id: 160>
So as you can see this clones object c
twice and therefore creates two distinct objects although there was just one object that was used by multiple objects in the original relations.
What I would expect is to detect reused objects via equal _id
-fields and only create one object for them which would result to the following objects after cloning:
<A-Class-Object id: 100, b_id: 120, c_id: 140>,
<B-Class-Object id: 120, c_id: 140>,
<C-Class-Object id: 140>
Did I do something wrong or is this behavior just not implemented yet?
I would definitely expect this to be included within this gem so if it's not implemented yet, please don't just close the ticket, I'd love to help getting this done. What do you think, @moiristo?
Btw: I'm using deep_cloneable 2.1.1 in a Rails 3.2.x project.
When cloning a record, it loads old record using identity map instead so new records aren't created.
Also:
DEPRECATION WARNING: primary_key_name is deprecated and will be removed from Rails 3.2 (use foreign_key instead).
https://github.com/moiristo/deep_cloneable/blob/v2.0.0/test/test_deep_cloneable.rb#L298
https://github.com/moiristo/deep_cloneable/blob/v2.0.0/test/test_deep_cloneable.rb#L284
For me it is confusing as the method is replaced. Right ?
After update on Rails 3.2 method dup raise this error.
undefined local variable or method `attributes_from_column_definition'
Using this code on an Employer
model:
def duplicate(new_name, options = {})
include_employees = options[:include_employees] || true
new_employer = self.deep_clone include: [
employees: [if: lambda{ |x| include_employees }]
], validate: false
end
If include_employees
is false, employees are still included. Is my syntax incorrect, or is deep_cloneable just ignoring the condition?
class A < AR::Base
has_many :items
end
a = A.new
a.items.build(some pararms)
b = a.dup include: items
# b.items is empty here!
Any plans for support for the new activerecord release? I tested 4.1 in my app and got this stack trace for a dup of one of my HABTM associations:
/var/lib/gems/2.0.0/gems/deep_cloneable-1.6.0/lib/deep_cloneable.rb:137:in `block in dup_join_association': nil is not a symbol (TypeError)
from /var/lib/gems/2.0.0/gems/activerecord-4.1.0/lib/active_record/relation/delegation.rb:46:in `collect'
from /var/lib/gems/2.0.0/gems/activerecord-4.1.0/lib/active_record/relation/delegation.rb:46:in `collect'
from /var/lib/gems/2.0.0/gems/deep_cloneable-1.6.0/lib/deep_cloneable.rb:136:in `dup_join_association'
from /var/lib/gems/2.0.0/gems/deep_cloneable-1.6.0/lib/deep_cloneable.rb:120:in `dup_has_many_through'
from /var/lib/gems/2.0.0/gems/deep_cloneable-1.6.0/lib/deep_cloneable.rb:81:in `block in dup'
from /var/lib/gems/2.0.0/gems/deep_cloneable-1.6.0/lib/deep_cloneable.rb:57:in `each'
from /var/lib/gems/2.0.0/gems/deep_cloneable-1.6.0/lib/deep_cloneable.rb:57:in `dup'
Thanks for any info!
The 2.0.0 version in the gemspec apparently was never published. Was there a reason for this?
Described in detail here: rails/rails#26557
Hey,
If the record is not saved yet and you try to create a deep clone of it, it will result in false date offset
foo = Foo.new(param['foo']) # param['foo'] as bar_attributes in it
foo_cloned = foo.deep_clone include: :bar
>> foo_cloned.bar.first.start_at
=> Fri, 31 Jul 2015 14:00:00 CEST +02:00
>> foo.bar.first.start_at
=> Fri, 31 Jul 2015 12:00:00 CEST +02:00
For this to not happend I've to save the record and reload it.
foo = Foo.new(param['foo']) # param['foo'] as bar_attributes in it
foo.save
foo.reload
foo_cloned = foo.deep_clone include: :bar
>> foo_cloned.bar.first.start_at
=> Fri, 31 Jul 2015 12:00:00 CEST +02:00
>> foo.bar.first.start_at
=> Fri, 31 Jul 2015 12:00:00 CEST +02:00
Do you have an idea why this happen?
Alex
I am trying to follow your example. I have a set of objects arranged something like folders of forms.
So, each folder belongs to a user, and has_many forms, each form has_many answers.
When I try and clone using deep_cloneable, I don't get the parents set right. So for example:
new_folder = folder.clone :include=>[:user, {:forms => :answers}]
It populates the in-memory objects with all the cloned values correctly, except I get validation errors that the form's folder_id is nil but is required, and the answers' form_id is nil and is required. I recognize that I could remove those validation checks if I wanted, but it seems like an odd thing to fail on, given that I have :autosave=>true on the has_many relationships.
Conversely the user_id is likewise required ,but it does not throw a validation error, and that belongs_to attribute does not have autosave turned on.
Any ideas how to resolve this?
Hello,
Thank you for this gem :)
A little issue in version 2.2.1 of this gem.
With this code :
a = Product.create(title: 'demo')
b = a.deep_clone(except: [:title])
puts b.title.inspect #=> nil
puts b.title_was.inspect #=> nil
#with 2.2.0
puts b.title_changed?.to_s => false
#with 2.2.1
puts b.title_changed?.to_s => true
Context :
Ruby 2.3.1
Rails 4.2.6
Unable to get Gemfile.lock
to compile because of version restrictions
Hi,
I'm trying to deep clone my project, it has elements, and folders with experiments and elements also,
all has belongs_to and has_many relationships.
my code is this:
source_project = Projects::Project.find_by_id(params[:id])
cloned_project = source_project.deep_clone(include: [:elements, { folders: [:experiments, :elements] }])
the error I'm getting is this:
undefined method `each' for #Projects::Project:0x007fc9547a6730
and the full (relavent)trace is this:
NoMethodError - undefined method `each' for #<Projects::Project:0x007fc9547a6730>:
activemodel (4.2.5) lib/active_model/attribute_methods.rb:433:in `method_missing'
activerecord (4.2.5) lib/active_record/associations/collection_association.rb:365:in `replace'
activerecord (4.2.5) lib/active_record/associations/collection_association.rb:47:in `writer'
activerecord (4.2.5) lib/active_record/associations/builder/association.rb:123:in `samples='
deep_cloneable (2.2.0) lib/deep_cloneable.rb:123:in `block in dup_has_many_association'
activerecord (4.2.5) lib/active_record/relation/delegation.rb:46:in `collect'
deep_cloneable (2.2.0) lib/deep_cloneable.rb:120:in `dup_has_many_association'
deep_cloneable (2.2.0) lib/deep_cloneable.rb:76:in `block in deep_clone'
deep_cloneable (2.2.0) lib/deep_cloneable.rb:40:in `deep_clone'
app/controllers/knowledge/projects_controller.rb:363:in `duplicate'
What am I missing? Or doing wrong?
Please help....
RubyGems.org doesn't report a license for your gem. This is because it is not specified in the gemspec of your last release.
via e.g.
spec.license = 'MIT'
# or
spec.licenses = ['MIT', 'GPL-2']
Including a license in your gemspec is an easy way for rubygems.org and other tools to check how your gem is licensed. As you can imagine, scanning your repository for a LICENSE file or parsing the README, and then attempting to identify the license or licenses is much more difficult and more error prone. So, even for projects that already specify a license, including a license in your gemspec is a good practice. See, for example, how rubygems.org uses the gemspec to display the rails gem license.
There is even a License Finder gem to help companies/individuals ensure all gems they use meet their licensing needs. This tool depends on license information being available in the gemspec. This is an important enough issue that even Bundler now generates gems with a default 'MIT' license.
I hope you'll consider specifying a license in your gemspec. If not, please just close the issue with a nice message. In either case, I'll follow up. Thanks for your time!
Appendix:
If you need help choosing a license (sorry, I haven't checked your readme or looked for a license file), GitHub has created a license picker tool. Code without a license specified defaults to 'All rights reserved'-- denying others all rights to use of the code.
Here's a list of the license names I've found and their frequencies
p.s. In case you're wondering how I found you and why I made this issue, it's because I'm collecting stats on gems (I was originally looking for download data) and decided to collect license metadata,too, and make issues for gemspecs not specifying a license as a public service :). See the previous link or my blog post about this project for more information.
Hello!
I had some issues with cloning models with mounted uploaders, in my case Carrierwave.
Best solution i found was using a block when cloning and setting the attributes manually to get the files to copy together with the other data.
I think it could be good to add a note in the README regarding this to make the process smoother for others.
It would be nice to have one, preferably in markdown format. Thanks for the gem!
I have my model Customer which has many customer documents. Inside a document I am using carrierwave to save an attachment.
From looking at previous posts on how to properly copy carrierwave attachments I was able to get my documents and their attachments cloned from the code below.
new_cusotmer = self.dup include: [{ customer_documents: :document }], validate: false do |original, kopy|]
# Clone Attachments
kopy.attachment = original.attachment if kopy.is_a?(Document)
end
new_customer.save!
The problem I am getting is that when I included the gem pg_search under my customer model, it still clones the customer and all its documents but it doesn't create an attachment anymore. It copies the original.attachment to the kopy.attachment but if I was to run
document.attachment?
it returns false because no file was created.
I am only having this issue when I am including pg_search in my customer model and was just wondering why this could be happening and if anyone else has experianced this.
How would this work with STI associations that are not available on the parent?
class Road
end
class Expressway < Road
end
class Highway < Road
has_many :bridges
end
@new_highway = @road.deep_clone include: :bridges
This is failing for any non-highway roads.
ActiveRecord::Base::DeepCloneable::AssociationNotFoundException: Expressway#bridges
I'm using this method to deep_clone
items:
def copy_to(new_date)
self.deep_clone(include: [:photos, :variants]) do |original, copied_item|
copied_item.deal_at = new_date if copied_item.respond_to?(:deal_at)
copied_item.image = original.image if copied_item.respond_to?(:image)
end
end
Running rspec 3.1.0 against Rails 4.2.rc1 with deep_cloneable 2.0.0 fails on the deep_clone
line with:
NoMethodError: undefined method `dup_has_many_has_many' for #<Deal:0x007f9b07dc7a18>
Sometimes we not only clone the AR object and relationships, but also clone the files, like attachments, so it would be great if we can write some code to support the paperclip, carrierwave, attachment_fu or something else.
by using clone with :include for a rails 3.1 app
Here's my code, I want to skip any document without files on it
def dup_info
{
users: [
{ profile: [:model1, :model2] },
{ documents: [ if: lambda{|doc| doc.file.present?} ] }
]
}
end
kopy = original.deep_clone(include: dup_info)
only the first user of kopy is skipping the docs without a file on it, all other users still have all the documents on them. Am I doing anything wrong here?
I had tried put if: lambda{|doc| doc.file.present?}
into an array or a hash, got the same result.
It seems the DeepClone module is loaded in such a way as to be inaccessible through the ActiveRecord hierarchy using Rails 2.3.10. I see that this is tested only using Rails 3, 3.1, but with instructions for Rails 2 it seems that the intent is to continue to support it. FYI, I've been using an old version of the plugin and that works great.
Pete
Hi, I'm trying to figure out how do a really really really really deep dup with deep_clonable
... this is the example provided pirate.dup :include => {:treasures => :gold_pieces}
Is it possible include children of :gold_pieces ? thanks
Hello!
Here's my code:
@original_meal = Meal.find(params[:id])
@meal = @original_meal.deep_clone include: :meal_foods
This is fired off in a 'clone' action in a controller.
The meal has_many meal_foods. Each meal_foods belongs_to a meal. The meal that is being cloned has many meal_foods associated with it.
When I clone it, I do in fact see some foods in the controller before the new meal is saved, but the associations aren't saved. I see the meal itself has no id since it hasn't been saved yet, thus the meal_foods can't be associated to it.
With that said, must I clone the original meal, and then write my own code to save the meal_foods from the original meal to the new one, or is something that should be handled by this gem?
Is it possible to reject cloning certain objects in a relation by using a block? Something like:
.deep_clone(:include => {
:parameters => :details do |original, kopy|
# reject if details.somefield = "DontCopyThis"
end
})
?
please look into this.
https://github.com/stefankroes/ancestry
I would like to keep ancestry data as well when I am going to deep clone and ancestry column value should
be changed during deep cloning.
Please suggest me what should i do.
The README correctly shows that when using a block, the cloned object should be checked before performing some custom operation, to see if is is_a? certain type or respond_to? a particular method.
However, I learned that this is because the associated objects being cloned are also passed to this block and it would fail with a missing method error if the cloned associated object has no such method.
Could you add a note to the corresponding section so that this comes as less of a surprise?
Thanks in advance.
Hello,
Is it possible to select from associated records only some that e.g. match some criteria?
e.g. clone only associated records where some_value = x, skip the rest?
Thanks in advance
Hi there,
I would like to ask if you can spot something wrong in what I'm doing. I have an object, say User, who can have many FamilyName, and a FamilyName can be shared by many User.
So I have a linking table named UserFamilyName.
When I try to clone a user I want to clone the family name and so I'd expect to do:
u = User.first
u_new = u.clone(:include => :user_family_names)
u_new.save!
But when I do this it complains about the user_id being duplicated (in my UserFamilyName I state that a user_id, family_name_id pair can only occur once (a User can't have the same FamilyName twice)).
I would then expect that I should do:
u = User.first
u_new = u.clone(:include => :user_family_names, :except => [{:user_family_names => [:user_id]}])
u_new.save!
But I get the same error than before...
Can you spot something wrong?
This is on a Rails 3.0.5 application running on Ruby 1.9.2.
Thank you! =)
I am duplicating a rails object, it is duplicating fine with all details except the created_at value of the object.
Here is the code . I want created_at value of raw_materials and costing_items .
@costing = @old_costing.deep_clone :include => [{style: :images}, {raw_materials: :costing_items} , :other_cost_fixeds, :other_costs, :exchange_rates ], :use_dictionary => true do |original, kopy|
kopy.remote_picture_url = original.picture_url if kopy.is_a?(Image)
end
I'm trying to deep clone an object with several associations:
Poll has_many :questions
Question has_many :options
Option has_many :follow_up, :class_name => "Question", :foreign_key => "parent_option_id", :dependent => :destroy, :inverse_of => :option
When I try to deep clone a poll object, poll.deep_clone include: { questions: [ {options: :follow_up} ] }
, I get the error NoMethodError: undefined method 'each' for #<Option:0x007fd87d419490>
,
with the following trace:
activemodel-3.2.22.2/lib/active_model/attribute_methods.rb:407:in `method_missing'
activerecord-3.2.22.2/lib/active_record/attribute_methods.rb:149:in `method_missing'
activerecord-3.2.22.2/lib/active_record/associations/collection_association.rb:310:in `replace'
activerecord-3.2.22.2/lib/active_record/associations/collection_association.rb:41:in `writer'
activerecord-3.2.22.2/lib/active_record/associations/builder/association.rb:51:in `block in define_writers'
deep_cloneable-2.2.1/lib/deep_cloneable.rb:127:in `block in dup_has_many_association'
activerecord-3.2.22.2/lib/active_record/associations/collection_proxy.rb:91:in `collect'
activerecord-3.2.22.2/lib/active_record/associations/collection_proxy.rb:91:in `method_missing'
deep_cloneable-2.2.1/lib/deep_cloneable.rb:124:in `dup_has_many_association'
It seems to be an issue when the association doesn't use the same name as the class of the object, similar to #58
Any idea how to get around this?
Im cloning an event object with nested models like show here:
copied_object = self.deep_clone include: [
:alternative_tickettexts,
:conversion_script,
:event_email_description,
:memberships,
:performances,
:sponsor_images,
passe_partouts: [:performances, {categories: :products}],
categories: :products,
], use_dictionary: true, validate: false
The result is a cloned object, but misses the categories: :products
on the copy. The use of use_dictionary
doesn't seem to make a difference. I tried various alternatives, but never ended up with the required result. Can you give me some advice here?
How can I include a has_many relation but scoped?
For instance:
class Treasure < ActiveRecord::Base
scope :last_week, lambda { where("created_at >= ?", Time.zone.now - 1.week) }
end
dup = @jack.dup(:include => :treasures ) # but only from last_week !!!
it's trying to load id of the association in the target object instead of association.
Looks like a bug
I can't get this to work in a rails3 app - have you tried it for sure? i keep getting the ArgumentError (wrong number of arguments(1 for 0)): i.e. it is not accepting the options e.g. :except, :include
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.