On Mon, Nov 15, 2021 at 11:50 AM Benjamin Hutton <benhut...@gmail.com>
wrote:

> Hey Jeremy,
>
> I am seeing some strange behavior with many_to_many associations,
> association cloning, and classes.
>
> I am building a set of sequel models to interact with a legacy database
> that we are slowly migrating away from, and trying to untangle some
> polymorphism in the old database.
>
> I started with a bunch of associations like the following:
>
> many_to_many :audios, class: 'Legacy::Models::SequelAudio', join_table:
> :content_syndications, left_key: :contentable_id, right_key: :content_id
> do |ds|
>    ds.where(:contents[:type] => 'Contents::Audio')
> end
>
> I then realized that I can do the following, in order to get rid of the
> block on the association:
>
> class Legacy::Models::SequelAudio < Legacy::Models::SequelContent
>   set_dataset LEGACY_DB[:contents].where(type: 'Contents::Audio')
> end
>
> Which leads to:
>
> many_to_many :audios, class: 'Legacy::Models::SequelAudio', join_table:
> :content_syndications, left_key: :contentable_id, right_key: :content_id
>
> At this point, I realize I am relying on something cool going on with the
> class argument.
>
> I then try to further DRY up my code by doing this:
>
> many_to_many :audios, clone: :contents, class:
> 'Legacy::Models::SequelAudio'
>
> Unfortunately, it seems like the class that I am specifying is no longer
> getting applied. The association returns records with the class that is
> on the cloned contents association, not the audios association. And it
> isn't using the correct dataset anymore.
>
> Is there something else that I need to be doing? Am I misunderstanding
> cloning?
>

I had trouble reproducing the example at first, using the following code:

 A = Class.new(Sequel::Model)
Content = Class.new(Sequel::Model(:contents))
Audio = Class.new(Sequel::Model(DB[:contents].where(:type=>'audio') ))
A.many_to_many :contents, :class=>Content, :join_table=>:x
A.many_to_many :audios, :clone=>:contents, :class=>Audio
DB.fetch = {:id=>2}
p A.association_reflection(:contents).associated_class
p A.association_reflection(:audios).associated_class
p A.load(:id=>1).contents_dataset.sql
p A.load(:id=>1).audios_dataset.sql
p A.load(:id=>1).contents.first
p A.load(:id=>1).audios.first

The output from that is:

Content
Audio
"SELECT contents.* FROM contents INNER JOIN x ON (x.content_id = contents.id)
WHERE (x.a_id = 1)"
"SELECT contents.* FROM contents INNER JOIN x ON (x.audio_id = contents.id)
WHERE ((type = 'audio') AND (x.a_id = 1))"
#<Content @values={:id=>2}>
#<Audio @values={:id=>2}>

However, I was able to reproduce this when using a symbol to the :class
option:

A.many_to_many :contents, :class=>:Content, :join_table=>:x
A.many_to_many :audios, :clone=>:contents, :class=>:Audio

With that change, the output is:

Content
Content
"SELECT contents.* FROM contents INNER JOIN x ON (x.content_id = contents.id)
WHERE (x.a_id = 1)"
"SELECT contents.* FROM contents INNER JOIN x ON (x.audio_id = contents.id)
WHERE (x.a_id = 1)"
#<Content @values={:id=>2}>
#<Content @values={:id=>2}>

So this is definitely a bug, and it's related to the late binding of
classes by using a string or symbol, probably because the :class option is
renamed to :class_name in that case, but the cloning code doesn't handle
that.  I'll work on a fix for it shortly.

Thanks,
Jeremy

-- 
You received this message because you are subscribed to the Google Groups 
"sequel-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sequel-talk+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sequel-talk/CADGZSSdC2q-qaSBa2B8Z6uZDcvwNnh3NX%2B0YghNksD0VLXBjiA%40mail.gmail.com.

Reply via email to