I have several nested classes that look like so:
class Presentation < ActiveRecord::Base
has_many :campaign_records, :as => :campaignable
def campaign_records_text(joiner)
return '' if self.campaign_records.blank?
self.campaign_records.map {|c| c.to_s}.join(joiner)
end
end
class CampaignRecord < ActiveRecord::Base
belongs_to :campaignable, :polymorphic => true
has_one :campaign
has_one :tier_one
has_one :tier_two
def to_s
"#{campaign.name} - #{tier_one.name} - #{tier_two.name}"
end
end
class Campaign < ActiveRecord::Base
has_many :tier_ones
attr_accessible :name
end
class TierOne < ActiveRecord::Base
has_many :tier_twos
belongs_to :campaign
attr_accessible :name
end
class TierTwo < ActiveRecord::Base
belongs_to :tier_one
attr_accessible :name
end
In summary, a Campaign
has many associated TierOne
s and every TierOne
has it's own set of TierTwo
s. A Presentation
has a set of CampaignRecord
s which link a Campaign
,TierOne
, and TierTwo
together. Note though that a Campaign
does not belong_to a CampaignRecord
because many CampaignRecord
s can refer to it.
So here's the problem: I want to change the CampaignRecord.to_s
method to return "campaign.name
- tier_one.name
- tier_two.name
" (like shown above) but doing so results in an error when I try to call some_campaign_record.to_s
:
ActionView::Template::Error (Mysql2::Error: Unknown column 'campaigns.campaign_record_id' in 'where clause': SELECT 'campaigns'.* FROM 'campaigns' WHERE 'campaigns'.'campaign_record_id' = # LIMIT 1)
Where did I go wrong here? I know that rails auto generates a lot of getters and setters for me, but the default to_s
method is just the usual so how do I override it in the proper rails way? Does a has_one
require a belongs_to
or is there a belongs_to_many
hiding out there somewhere that I should have used instead?
Any help would be very much appreciated! Thanks in advance!
(Also, I saw that my question is very similar to this unanswered question)
EDIT
I'm seeing a bit of confusion about the model structure here so let me try to explain it differently in a way that will hopefully be clearer.
First off, just to be clear a Campaign
is very different from a CampaignRecord
.
Think of the Campaign-TierOne-TierTwo relationship like a three layered list:
- Campaign 1
- TierOne 1.1
- TierTwo 1.1.1
- TierTwo 1.1.2
- ...
- TierOne 1.2
- TierTwo 1.2.1
- TierTwo 1.2.2
- ...
- ...
- TierOne 1.1
- Campaign 2
- TierOne 2.1
- TierTwo 2.1.1
- TierTwo 2.1.2
- ...
- TierOne 2.2
- TierTwo 2.2.1
- TierTwo 2.2.2
- ...
- ...
- TierOne 2.1
- Campaign 3 ...
The CampaignRecord model is a representation of a Campaign, TierOne, TierTwo tuple. When its first created, you select a Campaign. Then select a TierOne from that Campaign's set of TierOnes. Then a TierTwo from that TierOne's set of TierTwos. In other words, the CampaignRecord model is a path which traverses a Campaign-TierOne-TierTwo tree.
The set of presentation.campaign_records
is the set of valid Campaign-TierOne-TierTwo paths which a user has previously associated with that presentation instance. (A Presentation will have zero or more of these paths associated with it.)
The important bit of functionality is that a Presentation should have a variable size set of Campaign-TierOne-TierTwo linkages. While modifying any given Presentation, I need to be able to modify/add/remove Campaign-TierOne-TierTwo linkages to/from a Presentation. I chose to represent those Campaign-TierOne-TierTwo linkages as CampaignRecords
. A Presentation can have a bunch of these CampaignRecords
, but no Campaign, TierOne, or TierTwo will ever belong_to
a CampaignRecord.
So, my question becomes: Why is my Campaign
model throwing a "can't find specified column" error when it was never supposed to be looking for that column in the first place?
@presentations = Presentations.all
@presentations.each do |presentation|
presentation.campaign_records.each do |campaign_record|
print campaign_record.to_s # Campaign model throws error here
end
end
Based on the comments above, one error I see is the following:
Take a look at the Rails Guide on Associations.. Campaign is going to expect to see a campaign_record_id in any ActiveRecord model that has a has_something association.
My best bet is that you'll want to add that column into the TierTwo database.
Alternately, if every TierTwo's CampaignRecord can be inferred through its TierOne, you could also hypothetically do:
However, that doesn't seem like the right option. You say a CampaignRecord has only one TierTwo, and TierOne can have many TierTwos.
Let me know if this helps. It's possible I'm missing some information about your business logic that would help clarify my recommendation.