Multiple polymorphic belongs_to declarations

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?

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
[email protected]
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

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.