# Has\_one :through

**URL:** <https://www.ruby-forum.com/t/has-one-through/176549>\
**Category:** Rails\
**Created:** [October 2, 2009, 12:18am UTC](https://www.ruby-forum.com/t/has-one-through/176549 "2009-10-02T00:18:55Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![mlittle](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/c4cdca/32.png) [@mlittle](https://www.ruby-forum.com/u/mlittle)\
**Post date:** [October 2, 2009, 12:18am UTC](https://www.ruby-forum.com/t/has-one-through/176549/1 "2009-10-02T00:18:55Z")

</div>

Another newbie question by me…

I have this:

class User \< ActiveRecord::Base  
…  
has\_one :book, :through =\> :library  
…  
end

class Library \< ActiveRecord::Base  
has\_one :book, :dependent =\> :destroy  
end

class Library \< ActiveRecord::Base  
belongs\_to :library  
validates\_existence\_of :library  
end

I just don’t know what my route will look like. Any help or  
suggestions? Are my models correct in how I used the has\_one :through

Mike

Thanks

---

<div class="post-metadata">

**Author:** ![mlittle](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/c4cdca/32.png) [@mlittle](https://www.ruby-forum.com/u/mlittle)\
**Post date:** [October 2, 2009, 2:19am UTC](https://www.ruby-forum.com/t/has-one-through/176549/2 "2009-10-02T02:19:42Z")

</div>

mlittle wrote:

> Another newbie question by me…

First, do yourself a favor and not start off by advertising your  
“newbie” status. Trust that experienced programmers will know right away  
where you are in your learning by reading your question.

Before attempting to answer this question I would like some  
confirmations. Read on…

> I have this:
> 
> class User \< ActiveRecord::Base  
> …  
> has\_one :book, :through =\> :library  
> …  
> end

Are you wanting to say here that a user can only check out one book at a  
time from the library?

> class Library \< ActiveRecord::Base  
> has\_one :book, :dependent =\> :destroy  
> end

And a library can only ever contain one book?

> class Library \< ActiveRecord::Base  
> belongs\_to :library  
> validates\_existence\_of :library  
> end

Did you mean to define Book here instead of reopening the Library class  
and adding stuff to it?

Assuming you meant Book it seems fine for a book to belong to a library.

There is no validates\_existence\_of. Assuming you meant  
validates\_presence\_of :library:  
I’m even a little bit torn on this one, but I validate the presence of  
the foreign key (:library\_id in this case) rather than validate the  
association. From my experience so far it seems to make for cleaner test  
scripts and also does not directly depend on the actual association  
object making model tests easier to manage.

> I just don’t know what my route will look like.

Once you get your model actually right your routes will make sense.

> Any help or suggestions? Are my models correct in how I used the has\_one :through

Keep this in mind as a general rule of thumb: The reason has\_one exists  
is for creating one-to-one associations. Thing A can have only one B and  
thing B can only ever have one A.

So why would you ever need one-to-one associations? Can’t you just add  
all the needed fields to one table? Technically the answer is “Yes you  
can.” However, there are some very useful and practical uses for  
one-to-one associations.

- Sometimes groups of fields, which actually are functionally depend on  
the primary key of a row, are related in other ways and are good  
candidate to be broken out into a separate table.

- Often a table may contain a set of “optional” fields that don’t need  
to have values for every row in a table. These can be broken out to a  
separate table for effeciency’s sake and to clean up all those NULLs you  
would see if there was only one table.

- There are also cases where a table may contain a large character or  
binary blob. Most of the time it’s convenient to just use the wildcard  
when selecting data: (select \* from my\_table;). If that table contained  
a column of type (TEXT or BLOB). Then you’re going to suffer a  
significant performance hit. That could be fixed by always specifying  
the list of columns with something like: (select Col1, Col2, Coln from  
my\_table;), but you could also use a one-to-many and put the TEXT or  
BLOB in a separate table. Then (select \* from my\_table;) would only  
fetch the foreign key (i.e. my\_blob\_id), which is a simple integer and  
you won’t suffer the performance hit. When you actually want to get the  
large TEXT or BLOB you can either grab them individually thought the  
association, or include them if you need to grab a list of objects:  
@posts = Post.find(:all, :include =\> :post\_narrative).

So why has\_one and not belongs\_to? Well to answer this you need to  
consider how a one-to-on association is built in Rails. It is really  
just like a one-to-many association with a validation that only allows  
one object to be associated on the “many” side. So think of has\_one as a  
“special” has\_many than includes the proper validation (to ensure  
one-to-one) and also provides the one object instead of an array  
containing the one object.

So which side gets the has\_one? Well that’s easy to answer as well: use  
belongs\_to on the model that contains the foreign key and use has\_one on  
the model that doesn’t. You get to decide which model should get the  
foreign key. Usually objects have a natural association that makes that  
fairly easy. Say that a Person can only have one Residence (within this  
design). You wouldn’t think about a Person belonging to the Residence.  
You would rather say the Residence belongs to the Person. So Residence  
would get the foreign key, an hence the belongs\_to :person. So then  
Person gets the has\_one: residence.

I apologize for the long reply. Maybe this belongs\_to :blog.

---

<div class="post-metadata">

**Author:** ![mlittle](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/c4cdca/32.png) [@mlittle](https://www.ruby-forum.com/u/mlittle)\
**Post date:** [October 2, 2009, 2:49am UTC](https://www.ruby-forum.com/t/has-one-through/176549/3 "2009-10-02T02:49:58Z")

</div>

Robert, thanks for the reply. validates\_existence\_of is a plugin →   
[GitHub - nilaccount/validates\_existence\_of: A small plugin to validate the existence of an AR record](http://github.com/bogdans83/validates_existence_of/). I’ll try to make  
this as simple as possible. Here is what i’m trying to do:

A’s has many B’s and B’s have 1 C.

A = Users  
B = Books  
C = Libraries

Hope this clarifies everything for you. Sorry about the mistakes in my  
first post. Thanks again for your help

On Oct 1, 5:19 pm, Robert W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![mlittle](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/c4cdca/32.png) [@mlittle](https://www.ruby-forum.com/u/mlittle)\
**Post date:** [October 2, 2009, 3:56am UTC](https://www.ruby-forum.com/t/has-one-through/176549/4 "2009-10-02T03:56:52Z")

</div>

mlittle wrote:

> Robert, thanks for the reply. validates\_existence\_of is a plugin →   
> [GitHub - nilaccount/validates\_existence\_of: A small plugin to validate the existence of an AR record](http://github.com/bogdans83/validates_existence_of/). I’ll try to make  
> this as simple as possible. Here is what i’m trying to do:
> 
> A’s has many B’s and B’s have 1 C.
> 
> A = Users  
> B = Books  
> C = Libraries

Then your associations will be as follows:  
class User \< AR::B  
has\_many :books  
end

class Book \< AR::B  
belongs\_to :user  
belongs\_to :library  
end

class Library \< AR::B  
has\_many :books  
end

> Hope this clarifies everything for you. Sorry about the mistakes in my  
> first post. Thanks again for your help
> 
> On Oct 1, 5:19ï¿½pm, Robert W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

## Best,

Marnen Laibow-Koser  
[http://www.marnen.org](http://www.marnen.org)  
removed\_email\_address@domain.invalid

---

<div class="post-metadata">

**Author:** ![mlittle](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/c4cdca/32.png) [@mlittle](https://www.ruby-forum.com/u/mlittle)\
**Post date:** [October 2, 2009, 4:20am UTC](https://www.ruby-forum.com/t/has-one-through/176549/5 "2009-10-02T04:20:46Z")

</div>

mlittle wrote:

> Robert, thanks for the reply. validates\_existence\_of is a plugin →   
> [GitHub - nilaccount/validates\_existence\_of: A small plugin to validate the existence of an AR record](http://github.com/bogdans83/validates_existence_of/). I’ll try to make  
> this as simple as possible. Here is what i’m trying to do:

Got it. I though maybe that was the case, and might explain some of my  
previous frustrations with testing these associations.

> A’s has many B’s and B’s have 1 C.
> 
> A = Users  
> B = Books  
> C = Libraries

Okay, That makes more sense. Let me first write this as a user story:

Users may check out many books from a library. Users may borrow from  
many libraries. Only one library may own a book (in this design let’s  
consider two books with the same title separate books). Books loaned to  
users must be returned to the owning library.

So I see four models here not three:

User  
Library  
Book  
Loan

Feature: Book check out  
In order to learn cool stuff, or be entertained  
As a user  
I want to be able to checkout many books from many libraries

Scenario: Check from 2 libraries  
Given I select ‘Programming Ruby’ from the Public Library  
And I select ‘The Rails Way’ from the University Library  
When I check out from the Public Library  
And I check out from the University Library  
Then I should have 2 books

Feature: Book check in  
In order to prevent late fees  
As a user  
I want to be able to check in books

Scenario: I must return a book to the correct library  
Given I have ‘Programming Ruby’  
When I check in to the University Library  
Then the check in should be denied  
And I should have 2 books

There may be other scenarios to consider, but I wanted to focus on these  
two to help describe the model:

It looks to me like you need a standard many-to-many association with  
some additional validation to make sure the books get returned back to  
the library that owns them.

class User \< ActiveRecord::Base  
has\_many :loans  
has\_many :books, :through =\> :loans  
end

class Loan \< ActiveRecord::Base  
belongs\_to :user  
belongs\_to :book  
end

class Book \< ActiveRecord::Base  
has\_many :loans  
has\_many :users, :through =\> :loans  
belongs\_to :library  
end

class Library \< ActiveRecord::Base  
has\_many :books  
end

loans\_controller.rb

# DELETE /loans/1

# DELETE /loans/1.xml

def destroy  
@loan = Loan.find(params[:id])  
@loan.destroy if @loan.book.library == current\_library

```
respond_to do |format|
  flash[:error] = "This book was
  format.html { redirect_to(loans_url) }
  format.xml { head :ok }
end

```

end

I’ll leave it as an exercise for you to figure out how to determine the  
“current library” that the user is attempting to return the book to.

Notice that in this design the act of checking in a book is to destroy  
the loan of the book. So loan is a resource in it’s own right. Of course  
checking out a book would be to create a new loan.

Note: this code is incomplete and untested with no warrantee of any  
kind. 🙂

---

<div class="post-metadata">

**Author:** ![mlittle](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/c4cdca/32.png) [@mlittle](https://www.ruby-forum.com/u/mlittle)\
**Post date:** [October 2, 2009, 6:50am UTC](https://www.ruby-forum.com/t/has-one-through/176549/6 "2009-10-02T06:50:33Z")

</div>

Robert,

Thanks so much for the help. Question, though, could you help with  
with the routing that would be involved?

On Oct 1, 7:20 pm, Robert W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![mlittle](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/c4cdca/32.png) [@mlittle](https://www.ruby-forum.com/u/mlittle)\
**Post date:** [October 2, 2009, 8:08am UTC](https://www.ruby-forum.com/t/has-one-through/176549/7 "2009-10-02T08:08:59Z")

</div>

mlittle wrote:

> Robert,
> 
> Thanks so much for the help. Question, though, could you help with  
> with the routing that would be involved?
> 
> On Oct 1, 7:20ï¿½pm, Robert W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

I can’t think of any “special” routing that would be required. This  
design uses all standard REST actions so you should need only the  
standard resource routes:

map.resources :users, :loans, :books, :libraries

I suppose you could use some nested routes, but that would not be  
required for this to work. You would need some way to let the  
loans\_controller know what library the book is attempting to be returned  
to, but I don’t think that should affect routing in any way.
