# Inheritance via Though Associations?

**URL:** <https://www.ruby-forum.com/t/inheritance-via-though-associations/57314>\
**Category:** Rails\
**Created:** [April 9, 2006, 5:28pm UTC](https://www.ruby-forum.com/t/inheritance-via-though-associations/57314 "2006-04-09T17:28:25Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Bruce\_DSArcus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/b5a626/32.png) [@Bruce\_DSArcus](https://www.ruby-forum.com/u/Bruce_DSArcus)\
**Post date:** [April 9, 2006, 5:28pm UTC](https://www.ruby-forum.com/t/inheritance-via-though-associations/57314/1 "2006-04-09T17:28:25Z")

</div>

I posted something about this a week ago wihtout response, but have made  
some  
progress since. However, I’m still not getting exactly what I want.

OK, three core tables:

```
create_table :reference_items do |t|
  t.column :title, :string, :limit => 255
  t.column :year, :integer, :limit => 4
  t.column :type, :string
  t.column :container_id, :integer
  t.column :collection_id, :integer
  t.column :original_id, :integer
  t.column :event_id, :integer
end

create_table :contributors do |t|
  t.column :type, :string, :default => "Person"
  t.column :sort_name, :string, :limit => 255, :null => 

```

false  
end

```
create_table :contributions do |t|
  t.column :reference_item_id, :integer
  t.column :agent_id, :integer
  t.column :type, :string
  t.column :position, :integer
end

```

Drawing on this article …

[http://blog.hasmanythrough.com/articles/2006/02/28/association-goodness](http://blog.hasmanythrough.com/articles/2006/02/28/association-goodness)

… I have no problem using the through relation to be able to do stuff  
like:

some\_refitem.contributors.first.sort\_name

Where I get stuck is that I need to be able to subclass contributions so  
that I  
can do stuff like:

some\_refitem.authors  
some\_refitem.translators

So I need to be able to essentially treat each subclass as a list.

Can STI + through associations currently handle this, and is yes, how?

If not, any suggestions on how to achieve what I’m after?

Bruce

---

<div class="post-metadata">

**Author:** ![Bruce\_DSArcus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/b5a626/32.png) [@Bruce\_DSArcus](https://www.ruby-forum.com/u/Bruce_DSArcus)\
**Post date:** [April 9, 2006, 7:11pm UTC](https://www.ruby-forum.com/t/inheritance-via-though-associations/57314/2 "2006-04-09T19:11:10Z")

</div>

Bruce D’Arcus wrote:

> Where I get stuck is that I need to be able to subclass contributions so  
> that I can do stuff like:
> 
> some\_refitem.authors  
> some\_refitem.translators
> 
> So I need to be able to essentially treat each subclass as a list.
> 
> Can STI + through associations currently handle this, and is yes, how?
> 
> If not, any suggestions on how to achieve what I’m after?

Glad my blog was useful for you. I think the entry on working with  
polymorphic :through associations should be useful as well.  
[http://blog.hasmanythrough.com/articles/2006/04/03/polymorphic-through](http://blog.hasmanythrough.com/articles/2006/04/03/polymorphic-through)  
Now that I think of it, you can adapt that technique to work with  
concrete classes in STI too. Just define an association with a condition  
specifying the concrete class in the type field. Something like:

has\_many :contributors, :through =\> :contributions  
has\_many :authors, : through =\> :contributions, :condition =\> “type =  
‘Author’”  
has\_many : translators, : through =\> :contributions, :condition =\>  
“type = ‘Translator’”

I notice you have a ‘type’ in contributions and contributors both. You  
really need both of those? I’m not sure which type you want to make the  
different associations based on. You may need to change my example  
around depending on which. (Including your model class code in the  
question would be helpful.)

Also, it looks like contributions has a position for acting as a list.  
If you really want each concrete class to act as a different list, you  
might try defining the acts\_as\_list using a :scope that includes the  
‘type’ of the record. See the docs on acts\_as\_list for creating scopes  
as conditions.

–  
Josh S.  
[http://blog.hasmanythrough.com](http://blog.hasmanythrough.com)

---

<div class="post-metadata">

**Author:** ![Bruce\_DSArcus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/b5a626/32.png) [@Bruce\_DSArcus](https://www.ruby-forum.com/u/Bruce_DSArcus)\
**Post date:** [April 10, 2006, 6:40pm UTC](https://www.ruby-forum.com/t/inheritance-via-though-associations/57314/3 "2006-04-10T18:40:21Z")

</div>

Josh S. \<josh@…\> writes:

> Now that I think of it, you can adapt that technique to work with  
> concrete classes in STI too. Just define an association with a condition  
> specifying the concrete class in the type field. Something like:
> 
> has\_many :contributors, :through =\> :contributions  
> has\_many :authors, : through =\> :contributions, :condition =\> “type =  
> ‘Author’”  
> has\_many : translators, : through =\> :contributions, :condition =\>  
> “type = ‘Translator’”

Not quite working.

Schema:

create\_table “contributions”, :force =\> true do |t|  
t.column “reference\_item\_id”, :integer  
t.column “contributor\_id”, :integer  
t.column “type”, :string  
t.column “position”, :integer  
end

create\_table “contributors”, :force =\> true do |t|  
t.column “name”, :string  
t.column “type”, :string, :default =\> “Person”  
end

create\_table “reference\_items”, :force =\> true do |t|  
t.column “title”, :string  
t.column “type”, :string  
end

Models:

class Contributor \< ActiveRecord::Base  
has\_many :contributions, :dependent =\> true  
has\_many :reference\_items, :through =\> :contributions  
end

class Contribution \< ActiveRecord::Base  
belongs\_to :reference\_item  
belongs\_to :contributor  
end

class Author \< Contribution  
acts\_as\_list :scope =\> “type = ‘Author’”  
end

class ReferenceItem \< ActiveRecord::Base  
has\_many :contributors,  
:through =\> :contributions  
has\_many :authors,  
:through =\> :contributions,  
:condition =\> “type = ‘Author’”  
end

Book and Person are just straight subclasses of ReferenceItem and  
Contributor  
respectively.

So now on the console:

> > book = Book.new(:title =\> “Book Title”)  
> > =\> #\<Book:0x247d2d0 @attributes={“title”=\>“Book Title”, “type”=\>“Book”},  
> > @new\_record=true\>
> 
> > book.save  
> > =\> true
> 
> > jd = Person.new(:name =\> “Jane Doe”)  
> > =\> #\<Person:0x25f85c4 @attributes={“name”=\>“Jane Doe”,  
> > “type”=\>“Person”},  
> > @new\_record=true\>
> 
> > jd.save  
> > =\> true
> 
> > author = Author.new(:reference\_item\_id =\> 1, :contributor\_id =\> 1)  
> > =\> #\<Author:0x25e40ec @attributes={“reference\_item\_id”=\>1,  
> > “type”=\>“Author”,  
> > “position”=\>nil,  
> > “contributor\_id”=\>1}, @new\_record=true\>
> 
> > author.save  
> > =\> true
> 
> > x = Book.find(1)  
> > =\> #\<Book:0x25be888 @attributes={“title”=\>“Book Title”, “type”=\>“Book”,  
> > “id”=\>“1”}\>
> 
> > x.authors  
> > NoMethodError: undefined method `authors’ for #Book:0x25be888
> 
> > x.contributors  
> > ActiveRecord::HasManyThroughAssociationNotFoundError:  
> > ActiveRecord::HasManyThroughAssociationNotFoundError

I get the same error if I am using the main ReferenceItem class. Am I  
missing  
something obvious?

Bruce

---

<div class="post-metadata">

**Author:** ![Bruce\_DSArcus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/b5a626/32.png) [@Bruce\_DSArcus](https://www.ruby-forum.com/u/Bruce_DSArcus)\
**Post date:** [April 11, 2006, 12:45am UTC](https://www.ruby-forum.com/t/inheritance-via-though-associations/57314/4 "2006-04-11T00:45:21Z")

</div>

Bruce D’Arcus \<bdarcus.lists@…\> writes:

> Not quite working.

For benefit of the archives, the solution is …

> class ReferenceItem \< ActiveRecord::Base  
> has\_many :contributors,  
> :through =\> :contributions  
> has\_many :authors,  
> :through =\> :contributions,  
> :condition =\> “type = ‘Author’”  
> end

To replace the “condition” with “:source =\> :contributor”.

This now works correctly:

x.authors.first.name

Bruce

---

<div class="post-metadata">

**Author:** ![Bruce\_DSArcus](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/b5a626/32.png) [@Bruce\_DSArcus](https://www.ruby-forum.com/u/Bruce_DSArcus)\
**Post date:** [April 9, 2006, 7:34pm UTC](https://www.ruby-forum.com/t/inheritance-via-though-associations/57314/5 "2006-04-09T19:34:40Z")

</div>

Josh S. \<josh@…\> writes:

[… snip …]

> Now that I think of it, you can adapt that technique to work with  
> concrete classes in STI too. Just define an association with a condition  
> specifying the concrete class in the type field. Something like:
> 
> has\_many :contributors, :through =\> :contributions  
> has\_many :authors, : through =\> :contributions, :condition =\> “type =  
> ‘Author’”  
> has\_many : translators, : through =\> :contributions, :condition =\>  
> “type = ‘Translator’”

Thanks. I was missing the :condition; will give it a go.

> I notice you have a ‘type’ in contributions and contributors both. You  
> really need both of those? I’m not sure which type you want to make the  
> different associations based on. You may need to change my example  
> around depending on which. (Including your model class code in the  
> question would be helpful.)

The way I have it now (not including any associations) is:

Contributor \< ActiveRecord::Base  
end

Person \< Contributor  
end

Organization \< Contributor  
end

[aside: it would be nice if AR would allow me to store types in separate  
tables  
by default]

But a given contributor can play different roles in different  
circumstances, so  
they are not subclasses of Contributor. For example, I can be a  
translator and  
an author, and an editor.

So I have then have that captured in the Contribution class:

Contribution \< ActiveRecord::Base  
end

Authorship \< Contribution  
end

Editorship \< Contribution  
end

Translation \< Contribution  
end

So the idea is that translators, authors, editors, publishers, etc. (all  
of  
which I need to handle) are each different roles that associate a  
contributor to  
an item.

I’m not sure that’s the best way to do that (am new to this), but it  
seems like  
it is to me (?).

> Also, it looks like contributions has a position for acting as a list.

Correct. I need to treat each subclass as a separate list.

> If you really want each concrete class to act as a different list, you  
> might try defining the acts\_as\_list using a :scope that includes the  
> ‘type’ of the record.

OK, thanks!

Bruce
