# Has\_many/belongs\_to relationship that doesn't use id

**URL:** <https://www.ruby-forum.com/t/has-many-belongs-to-relationship-that-doesnt-use-id/125630>\
**Category:** Rails\
**Created:** [January 10, 2008, 7:31pm UTC](https://www.ruby-forum.com/t/has-many-belongs-to-relationship-that-doesnt-use-id/125630 "2008-01-10T19:31:37Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Wildtangent](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/df788c/32.png) [@Wildtangent](https://www.ruby-forum.com/u/Wildtangent)\
**Post date:** [January 10, 2008, 7:31pm UTC](https://www.ruby-forum.com/t/has-many-belongs-to-relationship-that-doesnt-use-id/125630/1 "2008-01-10T19:31:37Z")

</div>

Hi,

Banging by head against a wall here, and i’m sure this is easy

I have a table called channel\_statistics and one called installations

in both there is a column called node\_identifier

I want to be able to do

ChannelStatistic.find(:all, :include =\> [:installations]) as this has  
a lot of data in it I want to eager load

so i have tried

class ChannelStatistic \< ActiveRecord::Base

belongs\_to :installation, :foreign\_key =\> ‘node\_identifier’

…  
end

class Installation \< ActiveRecord::Base

has\_many :channel\_statistics, :foreign\_key =\> ‘node\_identifier’

…  
end

but to no avail.

It always performs the “LEFT OUTER JOIN on installations.id =  
channel\_statistics.node\_identifier”

What I want it to do is “LEFT OUTER JOIN on  
installations.node\_identifier = channel\_statistics.node\_identifier”

Guess they might not be able to handle this but it seems unlikely  
somehow!  
Possibility that with\_scope might help but I have never got that  
working how I want either

Please help!!

Thanks

Joe

---

<div class="post-metadata">

**Author:** ![Wildtangent](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/df788c/32.png) [@Wildtangent](https://www.ruby-forum.com/u/Wildtangent)\
**Post date:** [January 11, 2008, 11:05am UTC](https://www.ruby-forum.com/t/has-many-belongs-to-relationship-that-doesnt-use-id/125630/2 "2008-01-11T11:05:23Z")

</div>

The association just needs to work with both keys being named  
node\_identifier  
It can’t use the normal rails \_id convention because the stats get  
dumped by a separate app and i am not able to perform a lookup on the  
node\_identifier to find the installation\_id before each stats update  
(would create too much db activity)

So the question is simply, how do i override rails’s usually magic  
presets and create an assocation between the two tables which uses the  
node\_identifier column in both tables as the join.

There is only ever one installation per channel statistic so it is not  
a HABTM problem

THanks again!

---

<div class="post-metadata">

**Author:** ![Wildtangent](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/df788c/32.png) [@Wildtangent](https://www.ruby-forum.com/u/Wildtangent)\
**Post date:** [January 10, 2008, 9:43pm UTC](https://www.ruby-forum.com/t/has-many-belongs-to-relationship-that-doesnt-use-id/125630/3 "2008-01-10T21:43:43Z")

</div>

So you want to define all channel statistics that belong to an  
installation  
and all installations that belong to a channel statistic? This sounds  
like a  
has and belongs to many, or has\_many through problem 🙂

On Jan 11, 2008 5:00 AM, Wildtangent [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> end  
> It always performs the "LEFT OUTER JOIN on installations.id =
> 
> Please help!!
> 
> Thanks
> 
> Joe
> 
> >

–  
Ryan B.

> **[frozenplague.net](http://www.frozenplague.net)**
>
> This domain may be for sale!

Feel free to add me to MSN and/or GTalk as this email.

---

<div class="post-metadata">

**Author:** ![Wildtangent](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/df788c/32.png) [@Wildtangent](https://www.ruby-forum.com/u/Wildtangent)\
**Post date:** [January 15, 2008, 1:45pm UTC](https://www.ruby-forum.com/t/has-many-belongs-to-relationship-that-doesnt-use-id/125630/4 "2008-01-15T13:45:00Z")

</div>

I’m going to answer my own question because I’m sure I’m not alone  
with this problem

The solution I came up with was to subclass the main ActiveRecord  
model and override the primary key and relationships in there

e.g.

(Main Model Class)  
class Installation \< ActiveRecord::Base  
#…some normal relationships here  
end

(subclassed)  
class InstallationStatistic \< Installation

```
set_primary_key 'node_identifier'

has_many :channel_statistics, :foreign_key => 'node_identifier'

```

def save  
do\_not\_save\_and\_warn  
end  
alias\_method :save!, :save  
alias\_method :create, :save  
alias\_method :create!, :save  
alias\_method :\<\<, :save

private  
def do\_not\_save\_and\_warn  
logger.warn(“Can’t save with this model for association only.  
Instantiate Installation instead.”)  
end

end

(association)  
class ChannelStatistic \< ActiveRecord::Base  
belongs\_to :installation, :class\_name =\>  
'InstallationStatistic, :foreign\_key =\> ‘node\_identifier’  
end

This seems to allow me to maintain my relationships with Installation  
and its other relationships, while creating a new one based on a  
different primary key. I have overridden the save methods so that we  
don’t mess up the installation table or try and create a subclassed  
entry.

Now i can do

> > channel\_statistic = ChannelStatistic.find(:first)  
> > channel\_statistic.installation  
> > \<#IInstallationStatistic id: 54, node\_identifier: blah, :user\_id: 75\>
> 
> > channel\_statistic.installation.user  
> > \<#User id: 75, login: blah\>

Great!!
