Mongoid find_or_initialize_by embedded sublcass

Hi,
We use Mongoid v9 and embeds_many in classes & subclasses to embed objects like this:

module Product
class Base
embeds_many :variants, class_name: "Variant::Base"

module Product
class CustomProduct < Base
 
module Variant
class Base
embedded_in :product, class_name: "Product::Base"

module Variant
class CustomVariant < Base

This has been working perfectly.

However, we are having trouble using find_or_initialize_by on the embedded class

when we do this:

output_variant = product.variants.find_or_initialize_by(type_id: type_id)

we see output_variant is class Variant::Base. However, we can’t seem to cast it to Variant::CustomVariant

We tried

output_variant = output_variant.becomes(Variant::CustomVariant)
or
output_variant._type = "Variant::CustomVariant"

But nothing works. Any ideas?

I think the issue is that you’re lacking the polymorphic hints on the associations. The following works for me:

module Product
  class Base
    include Mongoid::Document

    embeds_many :variants, class_name: 'Variant::Base', as: :product
  end

  class Custom < Base
  end
end

module Variant
  class Base
    include Mongoid::Document

    embedded_in :product, polymorphic: true

    field :type_id, type: String
  end

  class Custom < Base
  end
end

product = Product::Custom.new
variant = product.variants.find_or_initialize_by(type_id: 'h', _type: 'Variant::Custom')

p product
p variant

product.save

product = Product::Base.find(product._id)
p product
p product.variants

The key is the as: :product option on embeds_many , and the polymorphic: true option on the embedded_in. Does this work for you?

Thanks @Jamis_Buck , this makes sense.
However, oddly, I get and Mongoid::Errors::UnknownAttribute error

     Attempted to set a value for '_type' which is not allowed on the model Variant::Base.

Can you share the code you’re using that results in that error? If you can boil it down to a script I can run locally, that’ll help a lot to troubleshoot this.

Hi @Jamis_Buck , sorry for the delayed response.

I couldn’t get find_or_initialize_by to work in my code, but was able to test it as a stand-alone .rb. So I need to dig deeper as to what’s going on. Thanks for your assistance!