Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to have a compound foreign key in rails?

Suppose the following data schema:

Usage
======
client_id
resource
type
amount

Billing
======
client_id
usage_resource
usage_type
rate

In this example, suppose I have multiple resources, each of which can be used in many ways. For example, one resource is a widget. Widgets can be fooed and they can be bared. Gizmos can also be fooed and bared. These usage types are billed at different rates, possibly even different rates for different clients. Each occurence of a usage (of a resource) is recorded in the Usage table. Each billing rate (for client, resource, and type combination) is stored in the billing table.

(By the way, if this data schema is not the right way to approach this problem, please make suggestions.)

Is it possible, using Ruby on Rails and ActiveRecord, to create a has_many relationship from Billings to Usages so that I can get a list of usage instances for a given billing rate? Is there a syntax of the has_many, :through that I don't know?

Once again, I may be approaching this problem from the wrong angle, so if you can think of a better way, please speak up!

like image 241
pkaeding Avatar asked Nov 11 '08 01:11

pkaeding


1 Answers

There is apparently an project at sourceforge to extend Rails' ActiveRecord with support for Composite Primary Keys. I haven't used this extension, but it might help you. It's also a gem at rubyforge.

Plain Ruby on Rails, as of version 2.0, does not support compound primary keys (cf. HowToUseLegacySchemas). Every table must have a single-column, auto-increment key named "id".

The explanation I have seen is: "You only need compound primary keys if you want to use a legacy database." This is of course a ridiculously ignorant view of data modeling.

The solution I see would be:

  • Usage.client_id -> Client.id
  • Usage.type_id -> Usagetype.id
  • Usage.resource_id -> Resource.id
  • Billing.usage_id -> Usage.id
  • Billing.client_id -> Client.id
  • Billing.type_id -> Usagetype.id
  • Billing.resource_id -> Resource.id

The apparently redundant foreign keys in Billing attempt to enforce partial referential integrity. But it doesn't quite get there -- it does not prevent you from creating rows in Billing that reference a row in Usage with the wrong client/resource/usagetype combination, not matching those in the referencing row in the Billing table.

edit: @Yarik: yes, you're right. It makes more sense for Usage to reference Billing.

  • Usage.billing_id -> Billing.id

Hmm. I made an ER diagram but I'm having trouble inserting it as an image.

like image 158
8 revs, 2 users 98% Avatar answered Sep 25 '22 15:09

8 revs, 2 users 98%