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.
70777d0bc2330fcd4b9ac001009d1fc3?d=identicon&s=25 Thomas Jack (thomasjack)
on 2006-03-19 21: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?
5d15c6821f3c3054c04b85471824ba7c?d=identicon&s=25 adam ingramgoble (Guest)
on 2006-03-19 22: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
>Rails@lists.rubyonrails.org
>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
70777d0bc2330fcd4b9ac001009d1fc3?d=identicon&s=25 Thomas Jack (thomasjack)
on 2006-03-20 04: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.