I need to create a temporary array containing model objects to manipulate. I need the auto_increment primary key but I do not want the associations kept because when I remove the object from the array it removes it from the database as well (thanks rails, pretty inconvenient). The deep copies I create using object.dup have the id's marked as nil. How do I keep them in the copy?
-
_"thanks rails, pretty inconvenient"_ my interest in helping is waning fast. http://xyproblem.info/ – matthewd Aug 19 '18 at 10:52
-
You sound like you wrote the framework. Did you? – user58446 Aug 19 '18 at 10:54
-
I've been through a number of possible solutions and a number of hours troubleshooting, The xy problem sounds difficult to prevent, since I would just start trying to solve X if I didn't have reason to be believe it might be Y. – user58446 Aug 19 '18 at 10:58
-
I'm on the core team, yes. You want to call `to_a` on the relation, not copy the individual records. (If you do want to copy the records, you want `clone`. But you really don't need to do that.) – matthewd Aug 19 '18 at 10:58
-
Fine then, your waning interest is warranted. Call it frustration from my own not following all of the conventions and trying to configure. Thanks for your help, I'll try to_a. – user58446 Aug 19 '18 at 11:02
-
The question is **how** are you trying to remove the object from the collection? Is your collection an `ActiveRecord::Relation`, an `Array` or something else? – 3limin4t0r Aug 19 '18 at 11:07
-
Ultimately, I still think either [`reject`](https://stackoverflow.com/a/51916360/476979) or [a subquery](https://stackoverflow.com/a/51916880/476979) is a better solution to the actual "I want a list of records that excludes some of them" problem (the X to this question's Y) – matthewd Aug 19 '18 at 11:21
-
The collection is an array now that I am running .to_a on it and the id's are now preserved. I am trying to remove the object via whatever method works delete, delete_at, reject!, I've tried many. Something is wrong with my looping operation because I wind up with the wrong elements remaining in the end. Done this plenty of times in other languages, removing items from reversed lists, and this is just a nested loop search... So I really can't figure out what's wrong (aside from the id's being nil). Going on 10 hours now. Now I just feel tired _and_ stupid. – user58446 Aug 19 '18 at 11:26
-
Ask _that_ question: `delete` & friends are much too low-level... you're making it harder than it needs to be (and yes, the more low-level you go, the easier it is to get trapped among operations that do something other than what you expect). – matthewd Aug 19 '18 at 11:31
-
Pardon my blindness, which question are you suggesting I ask? A rewording of the comment above regarding the malformed nested loops? Looking into a subquery solution now. – user58446 Aug 19 '18 at 11:35
-
"I am trying to [exclude some objects from a collection] via whatever method works, I've tried [delete, ..]" -- move up one level of detail from "here's how my `delete` is misbehaving, what's wrong?" to "here's what I need to achieve, and how my current approach is failing, what should I do differently?". – matthewd Aug 19 '18 at 11:43
-
I'm not sure which other languages you're familiar with for a good analogy, but: solving this in Ruby with an explicit nested loop is a bit like doing it in C using only `if` and `goto`: you _can_, but the higher level `for` is easier, less error prone, and more idiomatic. Ruby just has more "higher levels" built in to the language core. – matthewd Aug 19 '18 at 11:51
1 Answers
dup
describes this behaviour:
Duped objects have no id assigned and are treated as new records.
The dup method does not preserve the timestamps (created|updated)_(at|on).
It does that because people almost always want to duplicate the record in order to save a new copy of it to the database.
If you need a truly identical copy, clone
will do that, but it's almost never what you need: you almost certainly just want another reference to the same object.
In this case, from context and other comments, I understand that your goal is a list of records, such that you can delete entries and not have it affect the database.
For that, you need only to_a
. It sounds like you currently have an ActiveRecord::Associations::CollectionProxy (or if not, an ActiveRecord::Relation), which acts like an array, but represents the associated set in the database: what manipulations it allows, will be immediately reflected in the database. to_a
will give you an ordinary Ruby Array representing that list; you can then manipulate that array however you like. (Per the first half of this answer, this is a situation where you do not need to copy the individual records... you just need them in a simple array.)

- 19,353
- 2
- 31
- 52

- 4,332
- 15
- 21
-
can you add the part about the effect of .to_a (other than converting to an array so I understand a little more) and I'll mark it as answered. thanks. – user58446 Aug 19 '18 at 11:28