# :has\_many :through Question

**URL:** <https://www.ruby-forum.com/t/has-many-through-question/82508>\
**Category:** Rails\
**Created:** [January 19, 2007, 4:30pm UTC](https://www.ruby-forum.com/t/has-many-through-question/82508 "2007-01-19T16:30:59Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![jcernelli](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/73ab20/32.png) [@jcernelli](https://www.ruby-forum.com/u/jcernelli)\
**Post date:** [January 19, 2007, 4:30pm UTC](https://www.ruby-forum.com/t/has-many-through-question/82508/1 "2007-01-19T16:30:59Z")

</div>

I have 3 tables that are forming a has\_many through relationship:

create\_table “sites”, :force =\> true do |t|  
t.column “account\_id”, :integer, :default =\> 0, :null =\> false  
t.column “created\_on”, :timestamp  
t.column “updated\_on”, :timestamp  
t.column “lock\_version”, :integer, :default =\> 0, :null =\> false  
t.column “deleted”, :string, :limit =\> 1, :default =\> “N”, :null =\>  
false  
end

create\_table “sites\_users”, :force =\> true do |t|  
t.column “created\_on”, :timestamp  
t.column “updated\_on”, :timestamp  
t.column “lock\_version”, :integer, :default =\> 0, :null =\> false  
t.column “deleted”, :string, :limit =\> 1, :default =\> “N”, :null =\>  
false  
t.column “site\_id”, :integer, :limit =\> 10, :default =\> 0, :null =\>  
false  
t.column “user\_id”, :integer, :limit =\> 10, :default =\> 0, :null =\>  
false  
t.column “activated”, :string, :limit =\> 1, :default =\> “N”, :null  
=\> false  
t.column “role”, :integer, :limit =\> 10, :default =\> 1, :null =\>  
false  
end

create\_table “users”, :force =\> true do |t|  
t.column “created\_on”, :timestamp  
t.column “updated\_on”, :timestamp  
t.column “lock\_version”, :integer, :default =\> 0, :null =\> false  
t.column “deleted”, :string, :limit =\> 1, :default =\> “N”, :null =\>  
false  
t.column “name”, :string, :limit =\> 100, :default =\> “”, :null =\>  
false  
t.column “login”, :string, :limit =\> 40, :default =\> “”, :null =\>  
false  
t.column “email”, :string, :limit =\> 100, :default =\> “”, :null =\>  
false  
t.column “hashed\_password”, :string, :limit =\> 40, :default =\> “”,  
:null =\> false  
t.column “salt”, :string, :limit =\> 40, :default =\> “”, :null =\>  
false  
end

My user model looks like this:  
require ‘digest/sha1’

class User \< ActiveRecord::Base  
has\_many :sites, :through =\> :sites\_users  
has\_many :sites\_users

validates\_length\_of :login, :within =\> 6…40  
validates\_length\_of :password, :within =\> 6…40  
validates\_presence\_of :login, :email, :password,  
:password\_confirmation, :salt  
validates\_uniqueness\_of :login, :email  
validates\_format\_of :email,  
:with =\>  
/^([^@\s]+)@((?:[-a-z0-9]+.)+[a-z]{2,})$/i,  
:message =\> “Invalid email”  
attr\_protected :id, :salt

attr\_accessor :password, :password\_confirmation

def self.authenticate(login, pass)  
u=find(:first, :conditions=\>[“login = ?”, login])  
return nil if u.nil?

```
su = su = u.sites_users.detect{ |su| su.site = session[:site].id

```

and su.active = ‘Y’ }  
return nil if su.nil?

```
return u if User.encrypt(pass, u.salt)==u.hashed_password
nil

```

end

end

The system is setup to have many users assigned to different sites.  
Sites\_users contains their role (dependent on site) and whether they  
are active on that site. When logging in the user needs to be  
authorized against the users table and the sites\_users.

The problem I’m getting is that the table name sites\_users is giving  
rails a fit. When I run the authenticate method I get the following  
error:  
…lib/active\_support/dependencies.rb:100:in `const\_missing’:  
uninitialized constant SitesUser

It’s looking for the wrong class, notice that “Sites” is still  
pluralized. Since the class name is SiteUser this is not working.

I’m assuming I’ve broken the naming convention someplace, but I’m not  
sure where. Do I rename my table? My class?

Any help would be… helpful!

Thanks!  
Joe

---

<div class="post-metadata">

**Author:** ![jcernelli](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/73ab20/32.png) [@jcernelli](https://www.ruby-forum.com/u/jcernelli)\
**Post date:** [September 25, 2007, 10:31pm UTC](https://www.ruby-forum.com/t/has-many-through-question/82508/2 "2007-09-25T22:31:35Z")

</div>

Hey Chris, perfect explanation yah, thanks for the help. I think I had  
habtm  
and has\_many through twisted together in my brain. So much for late  
nights,  
not enough caffeine, and staring at a problem too long.

In order to keep this from being completely confusing I ended up making  
the  
table name “Assignments” and renaming everything.

---

<div class="post-metadata">

**Author:** ![jcernelli](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/73ab20/32.png) [@jcernelli](https://www.ruby-forum.com/u/jcernelli)\
**Post date:** [September 25, 2007, 10:31pm UTC](https://www.ruby-forum.com/t/has-many-through-question/82508/3 "2007-09-25T22:31:48Z")

</div>

short answer: your class should be named SitesUser and not SiteUser,  
by default, this is what Rails expects.

the reason for this is because sites\_users is not an invisible join  
table like what you would use for a habtm relationship between sites  
and users. It’s actually a full on table that goes hand in hand with  
the SitesUser model. Rails doesn’t know to remove the pluralization  
of sites in the table name because of this.

you have 3 options

1. change the model name to SitesUser to correspond to your table name

2. change the table name to site\_users (and all your associations as  
well) to correspond to your model name

3. set the table\_name in the SiteUsers model to ‘sites\_users’

i recommend option 2.

did i explain that well enough?

---

<div class="post-metadata">

**Author:** ![jcernelli](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/73ab20/32.png) [@jcernelli](https://www.ruby-forum.com/u/jcernelli)\
**Post date:** [September 25, 2007, 10:34pm UTC](https://www.ruby-forum.com/t/has-many-through-question/82508/4 "2007-09-25T22:34:16Z")

</div>

Hi, I think I like your “user\_roles” name a lot better than the  
“Assignments” name I switched it to. I’ll end up going with that I  
think -  
thanks again!

---

<div class="post-metadata">

**Author:** ![jcernelli](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/73ab20/32.png) [@jcernelli](https://www.ruby-forum.com/u/jcernelli)\
**Post date:** [September 25, 2007, 10:45pm UTC](https://www.ruby-forum.com/t/has-many-through-question/82508/5 "2007-09-25T22:45:47Z")

</div>

as an afterthought…

rename the sites\_users table (and therefore the model and  
associations) to something more descriptive, perhaps something like  
‘site\_roles’. remember you’re not locked into the habtm table naming  
requirements.

class SiteRole \< ActiveRecord::Base  
belongs\_to :site  
belongs\_to :user  
end

class Site \< ActiveRecord::Base  
has\_many :roles  
has\_many :users, :through =\> :site\_roles  
end

class User \< ActiveRecord::Base  
has\_many :site\_roles  
has\_many :sites, :through =\> :site\_roles  
end
