Forum: Ruby on Rails Multiple polymorphic belongs_to declarations

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Thomas J. (Guest)
on 2006-03-19 22:52
I have the following models:

    class Card < ActiveRecord::Base
      belongs_to :deck
      belongs_to :front, :polymorphic => true
      belongs_to :back, :polymorphic => true
    end

    class TextContent < ActiveRecord::Base
      has_one :card, :as => :front
      has_one :card, :as => :back
    end

The conflicting has_one declarations don't work. What I need is a way to
name the belongs_to associations 'front' and 'back', but have them go
through a single interface, which the TextContent model can reference,
like:

    class Card < ActiveRecord::Base
      belongs_to :deck
      belongs_to :front, :polymorphic => true, :interface => :content
      belongs_to :back, :polymorphic => true, :interface => :content
    end

    class TextContent < ActiveRecord::Base
      has_one :card, :as => :content
    end

Is this possible? Or is there some other way I should relate these
models?
adam ingramgoble (Guest)
on 2006-03-19 23:36
(Received via mailing list)
On Sunday, March 19, 2006, at 9:52 PM, Thomas Jack wrote:
>      has_one :card, :as => :back
>      belongs_to :back, :polymorphic => true, :interface => :content
>Posted via http://www.ruby-forum.com/.
>_______________________________________________
>Rails mailing list
>removed_email_address@domain.invalid
>http://lists.rubyonrails.org/mailman/listinfo/rails

Could you supply the following to help with the discussion:
a) your schema for these tables,
b) what do you mean by "doesn't work"? are you getting an error, or the
behavior isn't what you expect, etc.

adam
Thomas J. (Guest)
on 2006-03-20 05:33
adam ingramgoble wrote:
> Could you supply the following to help with the discussion:
> a) your schema for these tables,

    create_table :cards do |t|
      t.column :deck_id, :integer, :null => false
      t.column :front_id, :integer, :null => false
      t.column :front_type, :string, :null => false
      t.column :back_id, :integer, :null => false
      t.column :back_type, :string, :null => false
    end

    create_table :decks do |t|
      t.column :title, :string, :null => false
      t.column :created_at, :datetime, :null => false
    end

    create_table :text_contents do |t|
      t.column :content, :text, :null => false
    end

> b) what do you mean by "doesn't work"? are you getting an error, or the
> behavior isn't what you expect, etc.

The polymorphic belongs_to declarations work fine. I can do things like
@card.front = TextContent.new(:content => "some text") and the
front_type and front_id work properly.

However, the two has_one declarations conflict. They both expose a card
attribute, so the second has_one just overrides the first. Consider the
following console session, for example:

    Loading development environment.
    >> front = TextContent.new(:content => 'front of card')
    => #<TextContent:0x382a800 @new_record=true,
@attributes={"content"=>"front of card"}>
    >> back = TextContent.new(:content => 'back of card')
    => #<TextContent:0x381e908 @new_record=true,
@attributes={"content"=>"back of card"}>
    >> card = Card.new(:front => front, :back => back)
    => #<Card:0x3817870 @new_record=true, @front=#<TextContent:0x382a800
@new_record=true, @attributes={"content"=>"front of card"}>,
#attributes={"front_id"=>0, "deck_id"=>0, "back_type"=>"", "back_id"=>0,
"front_type"=>""}, @back=#<TextContent:0x381e908 @new_record=true,
@attributes={"content"=>"back of card"}>>
    >> card.save
    => true
    >> card.front
    => #<TextContent:0x382a800 @new_record=true,
@attributes={"content"=>"front of card"}>
    >> card.back
    => #<TextContent:0x381e908 @new_record=true,
@attributes={"content"=>"back of card"}>
    >> card.front.card
    => nil
    >> card.back.card
    => #<Card:0x37e5698 @attributes={"id"=>"2", "front_id"=>"3",
"deck_id"=>"0", "back_type"=>"TextContent", "back_id"=>"4",
"front_type"=>"TextContent"}>

Note that the .front and .back attributes of the Card model work fine,
but that only the second has_one works for the TextContent model.
This topic is locked and can not be replied to.