SystemStackError trying to call `.to_yaml` in a cequel object

93 Views Asked by At

I started to work in a legacy project and if I try to find a cequel record and then convert it to yaml:

fj = FullJob.find(1)
fj.to_yaml

I'm getting a stack level too deep error. Checking deeper, there's a @record_collection instance variable defined in the cequel record, which it brings a copy of the same object and inside of this, another copy of the same and so on...:

[7] pry(main)> fj.instance_variables
=> [:@record_collection, :@cequel_attributes, :@collection_proxies, :@loaded, :@persisted]
[8] pry(main)> fj.instance_variable_get(:@record_collection)
=> [#<FullJob id: 1, #...
[9] pry(main)> fj.instance_variable_get(:@record_collection).first.instance_variable_get(:@record_collection)
=> [#<FullJob id: 1, #...

The problem is, the ruby yaml parser, at some point, tries to parse all the instance variables of an object, which eventually derives in the mentioned SystemStackError.
Worth to mention this is only happening in this specific model, I mean, as far as I've seen, the @record_collection variable comes nil for another cequel models present in this project.
Not sure at all how this works, if this is a cequel bug or something not properly configured in the model, but... maybe has to do with cequel lazy loading?, anyway I'm running out of ideas here :(

1

There are 1 best solutions below

1
On

Worth to mention this is only happening in this specific model

It's not, actually. I think it happens to any record that was lazily instantiated as "unloaded" first and then loaded later - its @record_collection stays there even after loading (at least, I reproduced the same failure this way easily).

I can't find any single place in cequel source code where they drop this instance variable value (it doesn't happen on load for sure). On the other hand, it seems this value is not being used anywhere else except this lazy load behavior (so it's kind of "useless" after the record is loaded), so it might be safe to go with ugly monkey-patching workaround helper like

def cequel_to_yaml(record)
  record.load unless record.loaded?
  record.instance_variable_set(:@record_collection, nil)
  record.to_yaml
end