composite_primary_keys 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'redcloth'
4
+ require 'syntax/convertors/html'
5
+ require 'erb'
6
+ require '../lib/composite_primary_keys/version.rb'
7
+
8
+ version = CompositePrimaryKeys::VERSION::STRING
9
+ download = 'http://rubyforge.org/projects/compositekeys'
10
+
11
+ class Fixnum
12
+ def ordinal
13
+ # teens
14
+ return 'th' if (10..19).include?(self % 100)
15
+ # others
16
+ case self % 10
17
+ when 1: return 'st'
18
+ when 2: return 'nd'
19
+ when 3: return 'rd'
20
+ else return 'th'
21
+ end
22
+ end
23
+ end
24
+
25
+ class Time
26
+ def pretty
27
+ return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
28
+ end
29
+ end
30
+
31
+ def convert_syntax(syntax, source)
32
+ return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
33
+ end
34
+
35
+ if ARGV.length >= 1
36
+ src, template = ARGV
37
+ template ||= 'template.rhtml'
38
+ else
39
+ puts("Usage: #{File.split($0).last} source.txt [template.rhtml] > output.html")
40
+ exit!
41
+ end
42
+
43
+ template = ERB.new(File.open(template).read)
44
+
45
+ title = nil
46
+ body = nil
47
+ File.open(src) do |fsrc|
48
+ title_text = fsrc.readline
49
+ body_text = fsrc.read
50
+ syntax_items = []
51
+ body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
52
+ ident = syntax_items.length
53
+ element, syntax, source = $1, $2, $3
54
+ syntax_items << "<#{element} class=\"syntax\">#{convert_syntax(syntax, source)}</#{element}>"
55
+ "syntax-temp-#{ident}"
56
+ }
57
+ title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
58
+ body = RedCloth.new(body_text).to_html
59
+ body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
60
+ end
61
+ stat = File.stat(src)
62
+ created = stat.ctime
63
+ modified = stat.mtime
64
+
65
+ $stdout << template.result(binding)
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'redcloth'
4
+ require 'syntax/convertors/html'
5
+ require 'erb'
6
+ require 'active_support'
7
+ require '../lib/composite_primary_keys/version.rb'
8
+
9
+ version = CompositePrimaryKeys::VERSION::STRING
10
+ download = 'http://rubyforge.org/projects/compositekeys'
11
+
12
+ class Fixnum
13
+ def ordinal
14
+ # teens
15
+ return 'th' if (10..19).include?(self % 100)
16
+ # others
17
+ case self % 10
18
+ when 1: return 'st'
19
+ when 2: return 'nd'
20
+ when 3: return 'rd'
21
+ else return 'th'
22
+ end
23
+ end
24
+ end
25
+
26
+ class Time
27
+ def pretty
28
+ return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
29
+ end
30
+ end
31
+
32
+ def convert_syntax(syntax, source)
33
+ return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
34
+ end
35
+
36
+ if ARGV.length >= 1
37
+ src, template = ARGV
38
+ template ||= 'template.js'
39
+ else
40
+ puts("Usage: #{File.split($0).last} source.txt [template.js] > output.html")
41
+ exit!
42
+ end
43
+
44
+ template = ERB.new(File.open(template).read)
45
+
46
+ title = nil
47
+ body = nil
48
+ File.open(src) do |fsrc|
49
+ title_text = fsrc.readline
50
+ body_text = fsrc.read
51
+ title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
52
+ body = RedCloth.new(body_text)
53
+ end
54
+ stat = File.stat(src)
55
+ created = stat.ctime
56
+ modified = stat.mtime
57
+
58
+ $stdout << template.result(binding)
@@ -0,0 +1,201 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" />
6
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
7
+ <title>
8
+ Composite Primary Keys for Ruby on Rails/ActiveRecords
9
+ </title>
10
+ <script src="javascripts/rounded_corners_lite.inc.js" type="text/javascript"></script>
11
+ <style>
12
+
13
+ </style>
14
+ <script type="text/javascript">
15
+ window.onload = function() {
16
+ settings = {
17
+ tl: { radius: 10 },
18
+ tr: { radius: 10 },
19
+ bl: { radius: 10 },
20
+ br: { radius: 10 },
21
+ antiAlias: true,
22
+ autoPad: true,
23
+ validTags: ["div"]
24
+ }
25
+ var versionBox = new curvyCorners(settings, document.getElementById("version"));
26
+ versionBox.applyCornersToAll();
27
+ }
28
+ </script>
29
+ </head>
30
+ <body>
31
+ <div id="main">
32
+
33
+ <h1>Composite Primary Keys for Ruby on Rails/ActiveRecords</h1>
34
+ <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/compositekeys"; return false'>
35
+ Get Version
36
+ <a href="http://rubyforge.org/projects/compositekeys" class="numbers">0.7.1</a>
37
+ </div>
38
+ <h2>What</h2>
39
+
40
+
41
+ <p>Ruby on Rails does not support composite primary keys. This free software is an extension
42
+ to the database layer of Rails &#8211; ActiveRecords &#8211; to support composite primary keys
43
+ as transparently as possible.</p>
44
+
45
+
46
+ <h2>Installing</h2>
47
+
48
+
49
+ <p><pre class="syntax"><span class="ident">gem</span> <span class="ident">install</span> <span class="ident">composite_primary_keys</span></pre></p>
50
+
51
+
52
+ <p>To prepare ActiveRecords for composite primary keys&#8230;</p>
53
+
54
+
55
+ <p><pre class="syntax"><span class="ident">require</span> <span class="punct">'</span><span class="string">composite_primary_keys</span><span class="punct">'</span></pre></p>
56
+
57
+
58
+ <p>A class with composite primary keys would look like&#8230;</p>
59
+
60
+
61
+ <p><pre class="syntax"><span class="keyword">class </span><span class="class">ReferenceCode</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
62
+ <span class="comment"># set_primary_keys *keys - turns on composite key functionality</span>
63
+ <span class="ident">set_primary_keys</span> <span class="symbol">:reference_type_id</span><span class="punct">,</span> <span class="symbol">:reference_code</span>
64
+ <span class="ident">belongs_to</span> <span class="symbol">:reference_type</span><span class="punct">,</span> <span class="symbol">:foreign_key</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">reference_type_id</span><span class="punct">&quot;</span>
65
+ <span class="keyword">end</span></pre></p>
66
+
67
+
68
+ <p>Take two classes &#8211; <code class="syntax"><span class="constant">ReferenceType</span></code> and <code class="syntax"><span class="constant">ReferenceCode</span></code>
69
+ &#8211; where ReferenceCode has a <strong>composite primary key</strong>,
70
+ one of which is a foreign key to a parent ReferenceType.</p>
71
+
72
+
73
+ <p><pre class="syntax"><span class="constant">ReferenceType</span><span class="punct">.</span><span class="ident">primary_key</span>
74
+ <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">reference_type_id</span><span class="punct">&quot;</span> <span class="comment"># normal single key</span>
75
+ <span class="constant">ReferenceCode</span><span class="punct">.</span><span class="ident">primary_key</span>
76
+ <span class="punct">=&gt;</span> <span class="punct">[</span><span class="symbol">:reference_type_id</span><span class="punct">,</span> <span class="symbol">:reference_code</span><span class="punct">]</span> <span class="comment"># composite keys</span>
77
+ <span class="constant">ReferenceCode</span><span class="punct">.</span><span class="ident">primary_key</span><span class="punct">.</span><span class="ident">to_s</span>
78
+ <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">reference_type_id,reference_code</span><span class="punct">&quot;</span></pre></p>
79
+
80
+
81
+ <p>Now we want to be able to find instances using the same syntax we always use for ActiveRecords&#8230;</p>
82
+
83
+
84
+ <p><pre class="syntax"><span class="constant">ReferenceType</span><span class="punct">.</span><span class="ident">find</span> <span class="number">1</span> <span class="comment"># single id returns single instance</span>
85
+ <span class="punct">=&gt;</span> <span class="punct">&lt;</span><span class="constant">ReferenceType</span><span class="punct">:</span><span class="number">0x392a8c8</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">reference_type_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;,</span>
86
+ <span class="punct">&quot;</span><span class="string">abbreviation</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">Name Prefix</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">type_label</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">NAME_PREFIX</span><span class="punct">&quot;}&gt;</span>
87
+ <span class="constant">ReferenceCode</span><span class="punct">.</span><span class="ident">find</span> <span class="number">1</span><span class="punct">,</span><span class="number">1</span> <span class="comment"># composite ids returns single instance</span>
88
+ <span class="punct">=&gt;</span> <span class="punct">&lt;</span><span class="constant">ReferenceCode</span><span class="punct">:</span><span class="number">0x39218b0</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">reference_type_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;,</span>
89
+ <span class="punct">&quot;</span><span class="string">code_label</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">MR</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">abbreviation</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">Mr</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">reference_code</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;}&gt;</span></pre></p>
90
+
91
+
92
+ <p>Using <a href="http://www.rubyonrails.org">Ruby on Rails</a>? You&#8217;ll want to your url_for helpers
93
+ to convert composite keys into strings and back again&#8230;</p>
94
+
95
+
96
+ <p><pre class="syntax"><span class="ident">param_id</span> <span class="punct">=</span> <span class="constant">ReferenceCode</span><span class="punct">.</span><span class="ident">find_first</span><span class="punct">.</span><span class="ident">to_param</span>
97
+ <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">1,1</span><span class="punct">&quot;</span>
98
+ <span class="constant">ReferenceCode</span><span class="punct">.</span><span class="ident">find</span> <span class="ident">param_id</span>
99
+ <span class="punct">=&gt;</span> <span class="punct">=&gt;</span> <span class="punct">&lt;</span><span class="constant">ReferenceCode</span><span class="punct">:</span><span class="number">0x3904288</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">reference_type_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;,</span>
100
+ <span class="punct">&quot;</span><span class="string">code_label</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">MR</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">abbreviation</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">Mr</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">reference_code</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;}&gt;</span></pre></p>
101
+
102
+
103
+ <p>That is, an ActiveRecord supporting composite keys should behave transparently
104
+ throughout your application.</p>
105
+
106
+
107
+ <h2>Associations/Composite Foreign Keys</h2>
108
+
109
+
110
+ <p>The <code class="syntax"><span class="ident">has_many</span><span class="punct">,</span> <span class="ident">has_one</span></code>, and <code class="syntax"><span class="ident">belongs_to</span></code>
111
+ associations allow for composite foreign keys.</p>
112
+
113
+
114
+ <p><pre class="syntax">
115
+ <span class="keyword">class </span><span class="class">Product</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
116
+ <span class="ident">set_primary_key</span> <span class="symbol">:id</span> <span class="comment"># redundant</span>
117
+ <span class="ident">has_many</span> <span class="symbol">:product_tariffs</span><span class="punct">,</span> <span class="symbol">:foreign_key</span> <span class="punct">=&gt;</span> <span class="symbol">:product_id</span>
118
+ <span class="ident">has_many</span> <span class="symbol">:tariffs</span><span class="punct">,</span> <span class="symbol">:through</span> <span class="punct">=&gt;</span> <span class="symbol">:product_tariffs</span><span class="punct">,</span> <span class="symbol">:foreign_key</span> <span class="punct">=&gt;</span> <span class="symbol">:product_id</span>
119
+ <span class="keyword">end</span>
120
+ <span class="keyword">class </span><span class="class">ProductTariff</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
121
+ <span class="ident">set_primary_keys</span> <span class="symbol">:product_id</span><span class="punct">,</span> <span class="symbol">:tariff_id</span><span class="punct">,</span> <span class="symbol">:tariff_start_date</span>
122
+ <span class="ident">belongs_to</span> <span class="symbol">:products</span><span class="punct">,</span> <span class="symbol">:foreign_key</span> <span class="punct">=&gt;</span> <span class="symbol">:product_id</span>
123
+ <span class="ident">belongs_to</span> <span class="symbol">:tariffs</span><span class="punct">,</span> <span class="symbol">:foreign_keys</span> <span class="punct">=&gt;</span> <span class="punct">[</span><span class="symbol">:tariff_id</span><span class="punct">,</span> <span class="symbol">:tariff_start_date</span><span class="punct">]</span>
124
+ <span class="keyword">end</span>
125
+ <span class="keyword">class </span><span class="class">Tariff</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
126
+ <span class="ident">set_primary_keys</span> <span class="punct">[</span><span class="symbol">:tariff_id</span><span class="punct">,</span> <span class="symbol">:start_date</span><span class="punct">]</span>
127
+ <span class="ident">has_many</span> <span class="symbol">:product_tariffs</span><span class="punct">,</span> <span class="symbol">:foreign_keys</span> <span class="punct">=&gt;</span> <span class="punct">[</span><span class="symbol">:tariff_id</span><span class="punct">,</span> <span class="symbol">:tariff_start_date</span><span class="punct">]</span>
128
+ <span class="keyword">end</span>
129
+ </pre></p>
130
+
131
+
132
+ <p>The Tariff table has a composite primary key. Hence, the
133
+ <code class="syntax"><span class="ident">belongs_to</span></code> association from ProductTariff to Tariff
134
+ (called :tariffs) must use a composite foreign key.</p>
135
+
136
+
137
+ <p>The expression can use either the
138
+ :foreign_key or :foreign_keys option to specific the ordered list of table
139
+ columns. If the column names in both tables match, then the :foreign_key(s)
140
+ option can be omitted.</p>
141
+
142
+
143
+ <p>Similarly, the <code class="syntax"><span class="ident">has_many</span></code> and <code class="syntax"><span class="ident">has_one</span></code>
144
+ commands require the same :foreign_key(s) options if the target table
145
+ doesn&#8217;t have column names that match its own primary key column names.</p>
146
+
147
+
148
+ <p>The order of foreign keys should match the order of the primary keys in the
149
+ parent table.</p>
150
+
151
+
152
+ <h2>Other tricks</h2>
153
+
154
+
155
+ <p><pre class="syntax"><span class="constant">ReferenceCode</span><span class="punct">.</span><span class="ident">find</span> <span class="punct">[</span><span class="number">2</span><span class="punct">,</span><span class="number">1</span><span class="punct">],</span> <span class="punct">[</span><span class="number">2</span><span class="punct">,</span><span class="number">2</span><span class="punct">]</span> <span class="comment"># list of composite ids</span>
156
+ <span class="punct">=&gt;</span> <span class="punct">[</span>
157
+ <span class="punct">&lt;</span><span class="constant">ReferenceCode</span><span class="punct">:</span><span class="number">0x394ade8</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">reference_type_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">2</span><span class="punct">&quot;,</span>
158
+ <span class="punct">&quot;</span><span class="string">code_label</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">MALE</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">abbreviation</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">Male</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">reference_code</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;}&gt;,</span>
159
+ <span class="punct">&lt;</span><span class="constant">ReferenceCode</span><span class="punct">:</span><span class="number">0x394ada0</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">reference_type_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">2</span><span class="punct">&quot;,</span>
160
+ <span class="punct">&quot;</span><span class="string">code_label</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">FEMALE</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">abbreviation</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">Female</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">reference_code</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">2</span><span class="punct">&quot;}&gt;</span>
161
+ <span class="punct">]</span></pre></p>
162
+
163
+
164
+ <h2>Dr Nic&#8217;s Blog</h2>
165
+
166
+
167
+ <p><a href="http://www.drnicwilliams.com">http://www.drnicwilliams.com</a> &#8211; for future announcements and
168
+ other stories and things.</p>
169
+
170
+
171
+ <h2>Forum</h2>
172
+
173
+
174
+ <p><a href="http://groups.google.com/group/compositekeys">http://groups.google.com/group/compositekeys</a></p>
175
+
176
+
177
+ <h2>Licence</h2>
178
+
179
+
180
+ <p>This code is free to use under the terms of the <span class="caps">MIT</span> licence.</p>
181
+
182
+
183
+ <h2>Contact</h2>
184
+
185
+
186
+ <p>Comments are welcome. Send an email to <a href="mailto:drnicwilliams@gmail.com">Dr Nic Williams</a>.</p>
187
+ <p class="coda">
188
+ <a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>, 1st September 2006<br>
189
+ Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
190
+ </p>
191
+ </div>
192
+
193
+ <script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
194
+ </script>
195
+ <script type="text/javascript">
196
+ _uacct = "UA-567811-2";
197
+ urchinTracker();
198
+ </script>
199
+
200
+ </body>
201
+ </html>
@@ -0,0 +1,123 @@
1
+ h1. Composite Primary Keys for Ruby on Rails/ActiveRecords
2
+
3
+ h2. What
4
+
5
+ Ruby on Rails does not support composite primary keys. This free software is an extension
6
+ to the database layer of Rails - ActiveRecords - to support composite primary keys
7
+ as transparently as possible.
8
+
9
+ h2. Installing
10
+
11
+ <pre syntax="ruby">gem install composite_primary_keys</pre>
12
+
13
+ To prepare ActiveRecords for composite primary keys...
14
+
15
+ <pre syntax="ruby">require 'composite_primary_keys'</pre>
16
+
17
+ A class with composite primary keys would look like...
18
+
19
+ <pre syntax="ruby">class ReferenceCode < ActiveRecord::Base
20
+ # set_primary_keys *keys - turns on composite key functionality
21
+ set_primary_keys :reference_type_id, :reference_code
22
+ belongs_to :reference_type, :foreign_key => "reference_type_id"
23
+ end</pre>
24
+
25
+
26
+ Take two classes - <code syntax="ruby">ReferenceType</code> and <code syntax="ruby">ReferenceCode</code>
27
+ - where ReferenceCode has a *composite primary key*,
28
+ one of which is a foreign key to a parent ReferenceType.
29
+
30
+ <pre syntax="ruby">ReferenceType.primary_key
31
+ => "reference_type_id" # normal single key
32
+ ReferenceCode.primary_key
33
+ => [:reference_type_id, :reference_code] # composite keys
34
+ ReferenceCode.primary_key.to_s
35
+ => "reference_type_id,reference_code"</pre>
36
+
37
+ Now we want to be able to find instances using the same syntax we always use for ActiveRecords...
38
+
39
+ <pre syntax="ruby">ReferenceType.find 1 # single id returns single instance
40
+ => <ReferenceType:0x392a8c8 @attributes={"reference_type_id"=>"1",
41
+ "abbreviation"=>"Name Prefix", "type_label"=>"NAME_PREFIX"}>
42
+ ReferenceCode.find 1,1 # composite ids returns single instance
43
+ => <ReferenceCode:0x39218b0 @attributes={"reference_type_id"=>"1",
44
+ "code_label"=>"MR", "abbreviation"=>"Mr", "reference_code"=>"1"}></pre>
45
+
46
+ Using "Ruby on Rails":http://www.rubyonrails.org? You'll want to your url_for helpers
47
+ to convert composite keys into strings and back again...
48
+
49
+ <pre syntax="ruby">param_id = ReferenceCode.find_first.to_param
50
+ => "1,1"
51
+ ReferenceCode.find param_id
52
+ => => <ReferenceCode:0x3904288 @attributes={"reference_type_id"=>"1",
53
+ "code_label"=>"MR", "abbreviation"=>"Mr", "reference_code"=>"1"}></pre>
54
+
55
+ That is, an ActiveRecord supporting composite keys should behave transparently
56
+ throughout your application.
57
+
58
+
59
+
60
+ h2. Associations/Composite Foreign Keys
61
+
62
+ The <code syntax="ruby">has_many, has_one</code>, and <code syntax="ruby">belongs_to</code>
63
+ associations allow for composite foreign keys.
64
+
65
+ <pre syntax="ruby">
66
+ class Product < ActiveRecord::Base
67
+ set_primary_key :id # redundant
68
+ has_many :product_tariffs, :foreign_key => :product_id
69
+ has_many :tariffs, :through => :product_tariffs, :foreign_key => :product_id
70
+ end
71
+ class ProductTariff < ActiveRecord::Base
72
+ set_primary_keys :product_id, :tariff_id, :tariff_start_date
73
+ belongs_to :products, :foreign_key => :product_id
74
+ belongs_to :tariffs, :foreign_keys => [:tariff_id, :tariff_start_date]
75
+ end
76
+ class Tariff < ActiveRecord::Base
77
+ set_primary_keys [:tariff_id, :start_date]
78
+ has_many :product_tariffs, :foreign_keys => [:tariff_id, :tariff_start_date]
79
+ end
80
+ </pre>
81
+
82
+ The Tariff table has a composite primary key. Hence, the
83
+ <code syntax="ruby">belongs_to</code> association from ProductTariff to Tariff
84
+ (called :tariffs) must use a composite foreign key.
85
+
86
+ The expression can use either the
87
+ :foreign_key or :foreign_keys option to specific the ordered list of table
88
+ columns. If the column names in both tables match, then the :foreign_key(s)
89
+ option can be omitted.
90
+
91
+ Similarly, the <code syntax="ruby">has_many</code> and <code syntax="ruby">has_one</code>
92
+ commands require the same :foreign_key(s) options if the target table
93
+ doesn't have column names that match its own primary key column names.
94
+
95
+ The order of foreign keys should match the order of the primary keys in the
96
+ parent table.
97
+
98
+ h2. Other tricks
99
+
100
+ <pre syntax="ruby">ReferenceCode.find [2,1], [2,2] # list of composite ids
101
+ => [
102
+ <ReferenceCode:0x394ade8 @attributes={"reference_type_id"=>"2",
103
+ "code_label"=>"MALE", "abbreviation"=>"Male", "reference_code"=>"1"}>,
104
+ <ReferenceCode:0x394ada0 @attributes={"reference_type_id"=>"2",
105
+ "code_label"=>"FEMALE", "abbreviation"=>"Female", "reference_code"=>"2"}>
106
+ ]</pre>
107
+
108
+ h2. Dr Nic's Blog
109
+
110
+ "http://www.drnicwilliams.com":http://www.drnicwilliams.com - for future announcements and
111
+ other stories and things.
112
+
113
+ h2. Forum
114
+
115
+ "http://groups.google.com/group/compositekeys":http://groups.google.com/group/compositekeys
116
+
117
+ h2. Licence
118
+
119
+ This code is free to use under the terms of the MIT licence.
120
+
121
+ h2. Contact
122
+
123
+ Comments are welcome. Send an email to "Dr Nic Williams":mailto:drnicwilliams@gmail.com.