composite_primary_keys 2.3.5.1 → 3.0.0.b2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. data/History.txt +26 -0
  2. data/README.txt +1 -1
  3. data/Rakefile +41 -51
  4. data/lib/composite_primary_keys.rb +19 -7
  5. data/lib/composite_primary_keys/association_preload.rb +75 -170
  6. data/lib/composite_primary_keys/associations.rb +98 -400
  7. data/lib/composite_primary_keys/associations/association_proxy.rb +32 -0
  8. data/lib/composite_primary_keys/associations/has_and_belongs_to_many_association.rb +30 -0
  9. data/lib/composite_primary_keys/associations/has_many_association.rb +72 -0
  10. data/lib/composite_primary_keys/associations/has_one_association.rb +19 -0
  11. data/lib/composite_primary_keys/associations/through_association_scope.rb +103 -0
  12. data/lib/composite_primary_keys/base.rb +148 -305
  13. data/lib/composite_primary_keys/calculations.rb +22 -64
  14. data/lib/composite_primary_keys/composite_arrays.rb +3 -10
  15. data/lib/composite_primary_keys/connection_adapters/abstract_adapter.rb +9 -0
  16. data/lib/composite_primary_keys/connection_adapters/oracle_enhanced_adapter.rb +17 -0
  17. data/lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb +1 -1
  18. data/lib/composite_primary_keys/finder_methods.rb +71 -0
  19. data/lib/composite_primary_keys/fixtures.rb +1 -1
  20. data/lib/composite_primary_keys/read.rb +25 -0
  21. data/lib/composite_primary_keys/reflection.rb +30 -10
  22. data/lib/composite_primary_keys/relation.rb +31 -0
  23. data/lib/composite_primary_keys/validations/uniqueness.rb +106 -66
  24. data/lib/composite_primary_keys/version.rb +4 -4
  25. data/scripts/console.rb +1 -1
  26. data/tasks/Rakefile.rb +13 -0
  27. data/tasks/databases/mysql.rake +11 -15
  28. data/tasks/databases/oracle.rake +10 -11
  29. data/tasks/databases/postgresql.rake +10 -13
  30. data/tasks/databases/sqlite3.rake +9 -9
  31. data/test/README_tests.txt +1 -45
  32. data/test/abstract_unit.rb +17 -14
  33. data/test/connections/connection_spec.rb +19 -0
  34. data/test/connections/databases.example.yml +11 -0
  35. data/test/connections/databases.yml +13 -0
  36. data/test/connections/native_mysql/connection.rb +10 -2
  37. data/test/connections/native_oracle/connection.rb +7 -4
  38. data/test/connections/native_oracle_enhanced/connection.rb +23 -0
  39. data/test/connections/native_postgresql/connection.rb +13 -5
  40. data/test/connections/native_sqlite/connection.rb +7 -3
  41. data/test/fixtures/article_group.rb +4 -0
  42. data/test/fixtures/article_groups.yml +7 -0
  43. data/test/fixtures/db_definitions/postgresql.sql +2 -1
  44. data/test/fixtures/debug.log +133 -0
  45. data/test/fixtures/dorm.rb +3 -0
  46. data/test/fixtures/dorms.yml +2 -0
  47. data/test/fixtures/kitchen_sink.rb +3 -0
  48. data/test/fixtures/kitchen_sinks.yml +5 -0
  49. data/test/fixtures/reference_codes.yml +2 -0
  50. data/test/fixtures/reference_type.rb +1 -1
  51. data/test/fixtures/restaurant.rb +6 -0
  52. data/test/fixtures/restaurants.yml +5 -0
  53. data/test/fixtures/restaurants_suburbs.yml +11 -0
  54. data/test/fixtures/room.rb +10 -0
  55. data/test/fixtures/room_assignment.rb +4 -0
  56. data/test/fixtures/room_assignments.yml +4 -0
  57. data/test/fixtures/room_attribute.rb +3 -0
  58. data/test/fixtures/room_attribute_assignment.rb +5 -0
  59. data/test/fixtures/room_attribute_assignments.yml +4 -0
  60. data/test/fixtures/room_attributes.yml +3 -0
  61. data/test/fixtures/rooms.yml +3 -0
  62. data/test/fixtures/seat.rb +5 -0
  63. data/test/fixtures/seats.yml +4 -0
  64. data/test/fixtures/student.rb +4 -0
  65. data/test/fixtures/students.yml +2 -0
  66. data/test/test_associations.rb +27 -50
  67. data/test/test_attributes.rb +15 -19
  68. data/test/test_composite_arrays.rb +2 -21
  69. data/test/test_create.rb +3 -3
  70. data/test/test_delete.rb +7 -20
  71. data/test/test_exists.rb +3 -7
  72. data/test/test_find.rb +0 -8
  73. data/test/test_ids.rb +3 -17
  74. data/test/test_polymorphic.rb +5 -4
  75. data/test/test_suite.rb +19 -0
  76. data/test/{test_tutorial_examle.rb → test_tutorial_example.rb} +0 -0
  77. metadata +110 -72
  78. data/Manifest.txt +0 -123
  79. data/lib/adapter_helper/base.rb +0 -63
  80. data/lib/adapter_helper/mysql.rb +0 -13
  81. data/lib/adapter_helper/oracle.rb +0 -12
  82. data/lib/adapter_helper/postgresql.rb +0 -13
  83. data/lib/adapter_helper/sqlite3.rb +0 -13
  84. data/lib/composite_primary_keys/migration.rb +0 -20
  85. data/local/database_connections.rb.sample +0 -12
  86. data/local/paths.rb.sample +0 -2
  87. data/local/tasks.rb.sample +0 -2
  88. data/tasks/activerecord_selection.rake +0 -43
  89. data/tasks/databases.rake +0 -12
  90. data/tasks/deployment.rake +0 -22
  91. data/tasks/local_setup.rake +0 -13
  92. data/test/test_dummy.rb +0 -28
  93. data/tmp/test.db +0 -0
  94. data/website/index.html +0 -195
  95. data/website/index.txt +0 -159
  96. data/website/javascripts/rounded_corners_lite.inc.js +0 -285
  97. data/website/stylesheets/screen.css +0 -126
  98. data/website/template.js +0 -3
  99. data/website/template.rhtml +0 -53
  100. data/website/version-raw.js +0 -3
  101. data/website/version-raw.txt +0 -2
  102. data/website/version.js +0 -4
  103. data/website/version.txt +0 -3
@@ -1,123 +0,0 @@
1
- History.txt
2
- Manifest.txt
3
- README.txt
4
- README_DB2.txt
5
- Rakefile
6
- init.rb
7
- install.rb
8
- lib/adapter_helper/base.rb
9
- lib/adapter_helper/mysql.rb
10
- lib/adapter_helper/oracle.rb
11
- lib/adapter_helper/postgresql.rb
12
- lib/adapter_helper/sqlite3.rb
13
- lib/composite_primary_keys.rb
14
- lib/composite_primary_keys/association_preload.rb
15
- lib/composite_primary_keys/associations.rb
16
- lib/composite_primary_keys/attribute_methods.rb
17
- lib/composite_primary_keys/base.rb
18
- lib/composite_primary_keys/calculations.rb
19
- lib/composite_primary_keys/composite_arrays.rb
20
- lib/composite_primary_keys/connection_adapters/ibm_db_adapter.rb
21
- lib/composite_primary_keys/connection_adapters/oracle_adapter.rb
22
- lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb
23
- lib/composite_primary_keys/connection_adapters/sqlite3_adapter.rb
24
- lib/composite_primary_keys/fixtures.rb
25
- lib/composite_primary_keys/migration.rb
26
- lib/composite_primary_keys/reflection.rb
27
- lib/composite_primary_keys/validations/uniqueness.rb
28
- lib/composite_primary_keys/version.rb
29
- loader.rb
30
- local/database_connections.rb.sample
31
- local/paths.rb.sample
32
- local/tasks.rb.sample
33
- scripts/console.rb
34
- scripts/txt2html
35
- scripts/txt2js
36
- tasks/activerecord_selection.rake
37
- tasks/databases.rake
38
- tasks/databases/mysql.rake
39
- tasks/databases/oracle.rake
40
- tasks/databases/postgresql.rake
41
- tasks/databases/sqlite3.rake
42
- tasks/deployment.rake
43
- tasks/local_setup.rake
44
- tasks/website.rake
45
- test/README_tests.txt
46
- test/abstract_unit.rb
47
- test/connections/native_ibm_db/connection.rb
48
- test/connections/native_mysql/connection.rb
49
- test/connections/native_oracle/connection.rb
50
- test/connections/native_postgresql/connection.rb
51
- test/connections/native_sqlite/connection.rb
52
- test/fixtures/article.rb
53
- test/fixtures/articles.yml
54
- test/fixtures/comment.rb
55
- test/fixtures/comments.yml
56
- test/fixtures/db_definitions/db2-create-tables.sql
57
- test/fixtures/db_definitions/db2-drop-tables.sql
58
- test/fixtures/db_definitions/mysql.sql
59
- test/fixtures/db_definitions/oracle.drop.sql
60
- test/fixtures/db_definitions/oracle.sql
61
- test/fixtures/db_definitions/postgresql.sql
62
- test/fixtures/db_definitions/sqlite.sql
63
- test/fixtures/department.rb
64
- test/fixtures/departments.yml
65
- test/fixtures/employee.rb
66
- test/fixtures/employees.yml
67
- test/fixtures/group.rb
68
- test/fixtures/groups.yml
69
- test/fixtures/hack.rb
70
- test/fixtures/hacks.yml
71
- test/fixtures/membership.rb
72
- test/fixtures/membership_status.rb
73
- test/fixtures/membership_statuses.yml
74
- test/fixtures/memberships.yml
75
- test/fixtures/product.rb
76
- test/fixtures/product_tariff.rb
77
- test/fixtures/product_tariffs.yml
78
- test/fixtures/products.yml
79
- test/fixtures/reading.rb
80
- test/fixtures/readings.yml
81
- test/fixtures/reference_code.rb
82
- test/fixtures/reference_codes.yml
83
- test/fixtures/reference_type.rb
84
- test/fixtures/reference_types.yml
85
- test/fixtures/street.rb
86
- test/fixtures/streets.yml
87
- test/fixtures/suburb.rb
88
- test/fixtures/suburbs.yml
89
- test/fixtures/tariff.rb
90
- test/fixtures/tariffs.yml
91
- test/fixtures/user.rb
92
- test/fixtures/users.yml
93
- test/hash_tricks.rb
94
- test/plugins/pagination.rb
95
- test/plugins/pagination_helper.rb
96
- test/test_associations.rb
97
- test/test_attribute_methods.rb
98
- test/test_attributes.rb
99
- test/test_clone.rb
100
- test/test_composite_arrays.rb
101
- test/test_create.rb
102
- test/test_delete.rb
103
- test/test_dummy.rb
104
- test/test_exists.rb
105
- test/test_find.rb
106
- test/test_ids.rb
107
- test/test_miscellaneous.rb
108
- test/test_pagination.rb
109
- test/test_polymorphic.rb
110
- test/test_santiago.rb
111
- test/test_tutorial_examle.rb
112
- test/test_update.rb
113
- tmp/test.db
114
- website/index.html
115
- website/index.txt
116
- website/javascripts/rounded_corners_lite.inc.js
117
- website/stylesheets/screen.css
118
- website/template.js
119
- website/template.rhtml
120
- website/version-raw.js
121
- website/version-raw.txt
122
- website/version.js
123
- website/version.txt
@@ -1,63 +0,0 @@
1
- module AdapterHelper
2
- class Base
3
- class << self
4
- attr_accessor :adapter
5
-
6
- def load_connection_from_env(adapter)
7
- self.adapter = adapter
8
- unless ENV['cpk_adapters']
9
- puts error_msg_setup_helper
10
- exit
11
- end
12
-
13
- ActiveRecord::Base.configurations = YAML.load(ENV['cpk_adapters'])
14
- unless spec = ActiveRecord::Base.configurations[adapter]
15
- puts error_msg_adapter_helper
16
- exit
17
- end
18
- spec[:adapter] = adapter
19
- spec
20
- end
21
-
22
- def error_msg_setup_helper
23
- <<-EOS
24
- Setup Helper:
25
- CPK now has a place for your individual testing configuration.
26
- That is, instead of hardcoding it in the Rakefile and test/connections files,
27
- there is now a local/database_connections.rb file that is NOT in the
28
- repository. Your personal DB information (username, password etc) can
29
- be stored here without making it difficult to submit patches etc.
30
-
31
- Installation:
32
- i) cp locals/database_connections.rb.sample locals/database_connections.rb
33
- ii) For #{adapter} connection details see "Adapter Setup Helper" below.
34
- iii) Rerun this task
35
-
36
- #{error_msg_adapter_helper}
37
-
38
- Current ENV:
39
- #{ENV.inspect}
40
- EOS
41
- end
42
-
43
- def error_msg_adapter_helper
44
- <<-EOS
45
- Adapter Setup Helper:
46
- To run #{adapter} tests, you need to setup your #{adapter} connections.
47
- In your local/database_connections.rb file, within the ENV['cpk_adapter'] hash, add:
48
- "#{adapter}" => { adapter settings }
49
-
50
- That is, it will look like:
51
- ENV['cpk_adapters'] = {
52
- "#{adapter}" => {
53
- :adapter => "#{adapter}",
54
- :username => "root",
55
- :password => "root",
56
- # ...
57
- }
58
- }.to_yaml
59
- EOS
60
- end
61
- end
62
- end
63
- end
@@ -1,13 +0,0 @@
1
- require File.join(File.dirname(__FILE__), 'base')
2
-
3
- module AdapterHelper
4
- class MySQL < Base
5
- class << self
6
- def load_connection_from_env
7
- spec = super('mysql')
8
- spec[:database] ||= 'composite_primary_keys_unittest'
9
- spec
10
- end
11
- end
12
- end
13
- end
@@ -1,12 +0,0 @@
1
- require File.join(File.dirname(__FILE__), 'base')
2
-
3
- module AdapterHelper
4
- class Oracle < Base
5
- class << self
6
- def load_connection_from_env
7
- spec = super('oracle')
8
- spec
9
- end
10
- end
11
- end
12
- end
@@ -1,13 +0,0 @@
1
- require File.join(File.dirname(__FILE__), 'base')
2
-
3
- module AdapterHelper
4
- class Postgresql < Base
5
- class << self
6
- def load_connection_from_env
7
- spec = super('postgresql')
8
- spec[:database] ||= 'composite_primary_keys_unittest'
9
- spec
10
- end
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- require File.join(File.dirname(__FILE__), 'base')
2
-
3
- module AdapterHelper
4
- class Sqlite3 < Base
5
- class << self
6
- def load_connection_from_env
7
- spec = super('sqlite3')
8
- spec[:dbfile] ||= "tmp/test.db"
9
- spec
10
- end
11
- end
12
- end
13
- end
@@ -1,20 +0,0 @@
1
- ActiveRecord::ConnectionAdapters::ColumnDefinition.send(:alias_method, :to_s_without_composite_keys, :to_s)
2
-
3
- ActiveRecord::ConnectionAdapters::ColumnDefinition.class_eval <<-'EOF'
4
- def to_s
5
- if name.is_a? Array
6
- "PRIMARY KEY (#{name.join(',')})"
7
- else
8
- to_s_without_composite_keys
9
- end
10
- end
11
- EOF
12
-
13
- ActiveRecord::ConnectionAdapters::TableDefinition.class_eval <<-'EOF'
14
- def [](name)
15
- @columns.find { |column|
16
- !column.name.is_a?(Array) && column.name.to_s == name.to_s
17
- }
18
- end
19
- EOF
20
-
@@ -1,12 +0,0 @@
1
- require 'yaml'
2
-
3
- ENV['cpk_adapters'] = {
4
- "mysql" => {
5
- :adapter => "mysql",
6
- :username => "root",
7
- },
8
-
9
- "sqlite3" => {
10
- :adapter => "sqlite3"
11
- }
12
- }.to_yaml
@@ -1,2 +0,0 @@
1
- # location of folder containing activerecord, railties, etc folders for each Rails gem
2
- ENV['EDGE_RAILS_DIR'] ||= "/path/to/copy/of/edge/rails"
@@ -1,2 +0,0 @@
1
- # This file loaded into Rakefile
2
- # Place any extra development tasks you want here
@@ -1,43 +0,0 @@
1
- namespace :ar do
2
- desc 'Pre-load edge rails ActiveRecord'
3
- task :edge do
4
- unless path = ENV['EDGE_RAILS_DIR'] || ENV['EDGE_RAILS']
5
- puts <<-EOS
6
-
7
- Need to define env var EDGE_RAILS_DIR or EDGE_RAILS- root of edge rails on your machine.
8
- i) Get copy of Edge Rails - http://dev.rubyonrails.org
9
- ii) Set EDGE_RAILS_DIR to this folder in local/paths.rb - see local/paths.rb.sample for example
10
- or
11
- a) Set folder from environment or command line (rake ar:edge EDGE_RAILS_DIR=/path/to/rails)
12
-
13
- EOS
14
- exit
15
- end
16
-
17
- ENV['AR_LOAD_PATH'] = File.join(path, "activerecord/lib")
18
- end
19
-
20
- desc 'Pre-load ActiveRecord using VERSION=X.Y.Z, instead of latest'
21
- task :set do
22
- unless version = ENV['VERSION']
23
- puts <<-EOS
24
- Usage: rake ar:get_version VERSION=1.15.3
25
- Specify the version number with VERSION=X.Y.Z; and make sure you have that activerecord gem version installed.
26
-
27
- EOS
28
- end
29
- version = nil if version == "" || version == []
30
- begin
31
- version ? gem('activerecord', version) : gem('activerecord')
32
- require 'active_record'
33
- ENV['AR_LOAD_PATH'] = $:.reverse.find { |path| /activerecord/ =~ path }
34
- rescue LoadError
35
- puts <<-EOS
36
- Missing: Cannot find activerecord #{version} installed.
37
- Install: gem install activerecord -v #{version}
38
-
39
- EOS
40
- exit
41
- end
42
- end
43
- end
@@ -1,12 +0,0 @@
1
- require 'active_record'
2
-
3
- # UNTESTED - firebird sqlserver sqlserver_odbc db2 sybase openbase
4
- for adapter in %w( mysql sqlite oracle oracle_enhanced postgresql ibm_db )
5
- Rake::TestTask.new("test_#{adapter}") { |t|
6
- t.libs << "test" << "test/connections/native_#{adapter}"
7
- t.pattern = "test/test_*.rb"
8
- t.verbose = true
9
- }
10
- end
11
-
12
- SCHEMA_PATH = File.join(PROJECT_ROOT, *%w(test fixtures db_definitions))
@@ -1,22 +0,0 @@
1
- desc 'Release the website and new gem version'
2
- task :deploy => [:check_version, :website, :release] do
3
- puts "Remember to create SVN tag:"
4
- puts "svn copy svn+ssh://#{RUBYFORGE_USERNAME}@rubyforge.org/var/svn/#{PATH}/trunk " +
5
- "svn+ssh://#{RUBYFORGE_USERNAME}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
6
- puts "Suggested comment:"
7
- puts "Tagging release #{CHANGES}"
8
- end
9
-
10
- desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
11
- task :local_deploy => [:website_generate, :install_gem]
12
-
13
- task :check_version do
14
- unless ENV['VERSION']
15
- puts 'Must pass a VERSION=x.y.z release version'
16
- exit
17
- end
18
- unless ENV['VERSION'] == VERS
19
- puts "Please update your version.rb to match the release version, currently #{VERS}"
20
- exit
21
- end
22
- end
@@ -1,13 +0,0 @@
1
- namespace :local do
2
- desc 'Copies over the same local files ready for editing'
3
- task :setup do
4
- sample_files = Dir[File.join(PROJECT_ROOT, "local/*.rb.sample")]
5
- sample_files.each do |sample_file|
6
- file = sample_file.sub(".sample","")
7
- unless File.exists?(file)
8
- puts "Copying #{sample_file} -> #{file}"
9
- sh %{ cp #{sample_file} #{file} }
10
- end
11
- end
12
- end
13
- end
@@ -1,28 +0,0 @@
1
- require 'abstract_unit'
2
- require 'fixtures/reference_type'
3
- require 'fixtures/reference_code'
4
-
5
- class TestDummy < ActiveSupport::TestCase
6
- fixtures :reference_types, :reference_codes
7
-
8
- classes = {
9
- :single => {
10
- :class => ReferenceType,
11
- :primary_keys => :reference_type_id,
12
- },
13
- :dual => {
14
- :class => ReferenceCode,
15
- :primary_keys => [:reference_type_id, :reference_code],
16
- },
17
- }
18
-
19
- def setup
20
- self.class.classes = classes
21
- end
22
-
23
- def test_truth
24
- testing_with do
25
- assert true
26
- end
27
- end
28
- end
Binary file
@@ -1,195 +0,0 @@
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
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</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">2.3.5.1</a>
37
- </div>
38
- <h1>&#8594; Ruby on Rails</h1>
39
- <h1>&#8594; ActiveRecords</h1>
40
- <h2>What</h2>
41
- <p>Ruby on Rails does not support composite primary keys. This free software is an extension <br />
42
- to the database layer of Rails &#8211; <a href="http://wiki.rubyonrails.com/rails/pages/ActiveRecord">ActiveRecords</a> &#8211; to support composite primary keys as transparently as possible.</p>
43
- <p>Any Ruby script using ActiveRecords can use Composite Primary Keys with this library.</p>
44
- <h2>Installing</h2>
45
- <p><pre class="syntax"><span class="ident">sudo</span> <span class="ident">gem</span> <span class="ident">install</span> <span class="ident">composite_primary_keys</span></pre></p>
46
- <p>Rails: Add the following to the bottom of your <code>environment.rb</code> file</p>
47
- <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>
48
- <p>Ruby scripts: Add the following to the top of your script</p>
49
- <p><pre class="syntax"><span class="ident">require</span> <span class="punct">'</span><span class="string">rubygems</span><span class="punct">'</span>
50
- <span class="ident">require</span> <span class="punct">'</span><span class="string">composite_primary_keys</span><span class="punct">'</span></pre></p>
51
- <h2>The basics</h2>
52
- <p>A model with composite primary keys would look like&#8230;</p>
53
- <p><pre class="syntax"><span class="keyword">class </span><span class="class">Membership</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
54
- <span class="comment"># set_primary_keys *keys - turns on composite key functionality</span>
55
- <span class="ident">set_primary_keys</span> <span class="symbol">:user_id</span><span class="punct">,</span> <span class="symbol">:group_id</span>
56
- <span class="ident">belongs_to</span> <span class="symbol">:user</span>
57
- <span class="ident">belongs_to</span> <span class="symbol">:group</span>
58
- <span class="ident">has_many</span> <span class="symbol">:statuses</span><span class="punct">,</span> <span class="symbol">:class_name</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">MembershipStatus</span><span class="punct">',</span> <span class="symbol">:foreign_key</span> <span class="punct">=&gt;</span> <span class="punct">[</span><span class="symbol">:user_id</span><span class="punct">,</span> <span class="symbol">:group_id</span><span class="punct">]</span>
59
- <span class="keyword">end</span></pre></p>
60
- <p>A model associated with a composite key model would be defined like&#8230;</p>
61
- <p><pre class="syntax"><span class="keyword">class </span><span class="class">MembershipStatus</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
62
- <span class="ident">belongs_to</span> <span class="symbol">:membership</span><span class="punct">,</span> <span class="symbol">:foreign_key</span> <span class="punct">=&gt;</span> <span class="punct">[</span><span class="symbol">:user_id</span><span class="punct">,</span> <span class="symbol">:group_id</span><span class="punct">]</span>
63
- <span class="keyword">end</span></pre></p>
64
- <p>That is, associations can include composite keys too. Nice.</p>
65
- <h2>Demonstration of usage</h2>
66
- <p>Once you&#8217;ve created your models to specify composite primary keys (such as the Membership class) and associations (such as MembershipStatus#membership), you can uses them like any normal model with associations.</p>
67
- <p>But first, lets check out our primary keys.</p>
68
- <p><pre class="syntax"><span class="constant">MembershipStatus</span><span class="punct">.</span><span class="ident">primary_key</span> <span class="comment"># =&gt; &quot;id&quot; # normal single key</span>
69
- <span class="constant">Membership</span><span class="punct">.</span><span class="ident">primary_key</span> <span class="comment"># =&gt; [:user_id, :group_id] # composite keys</span>
70
- <span class="constant">Membership</span><span class="punct">.</span><span class="ident">primary_key</span><span class="punct">.</span><span class="ident">to_s</span> <span class="comment"># =&gt; &quot;user_id,group_id&quot;</span></pre></p>
71
- <p>Now we want to be able to find instances using the same syntax we always use for ActiveRecords&#8230;</p>
72
- <p><pre class="syntax"><span class="constant">MembershipStatus</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="number">1</span><span class="punct">)</span> <span class="comment"># single id returns single instance</span>
73
- <span class="punct">=&gt;</span> <span class="punct">&lt;</span><span class="constant">MembershipStatus</span><span class="punct">:</span><span class="number">0x392a8c8</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">status</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">Active</span><span class="punct">&quot;}&gt;</span>
74
- <span class="constant">Membership</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="number">1</span><span class="punct">,</span><span class="number">1</span><span class="punct">)</span> <span class="comment"># composite ids returns single instance</span>
75
- <span class="punct">=&gt;</span> <span class="punct">&lt;</span><span class="constant">Membership</span><span class="punct">:</span><span class="number">0x39218b0</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">user_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">group_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;}&gt;</span></pre></p>
76
- <p>Using <a href="http://www.rubyonrails.org">Ruby on Rails</a>? You&#8217;ll want to your url_for helpers<br />
77
- to convert composite keys into strings and back again&#8230;</p>
78
- <p><pre class="syntax"><span class="constant">Membership</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="symbol">:first</span><span class="punct">).</span><span class="ident">to_param</span> <span class="comment"># =&gt; &quot;1,1&quot;</span></pre></p>
79
- <p>And then use the string id within your controller to find the object again</p>
80
- <p><pre class="syntax"><span class="ident">params</span><span class="punct">[</span><span class="symbol">:id</span><span class="punct">]</span> <span class="comment"># =&gt; '1,1'</span>
81
- <span class="constant">Membership</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="ident">params</span><span class="punct">[</span><span class="symbol">:id</span><span class="punct">])</span>
82
- <span class="punct">=&gt;</span> <span class="punct">&lt;</span><span class="constant">Membership</span><span class="punct">:</span><span class="number">0x3904288</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">user_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">group_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;}&gt;</span></pre></p>
83
- <p>That is, an ActiveRecord supporting composite keys behaves transparently<br />
84
- throughout your application. Just like a normal ActiveRecord.</p>
85
- <h2>Other tricks</h2>
86
- <h3>Pass a list of composite ids to the <code>#find</code> method</h3>
87
- <p><pre class="syntax"><span class="constant">Membership</span><span class="punct">.</span><span class="ident">find</span> <span class="punct">[</span><span class="number">1</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">1</span><span class="punct">]</span>
88
- <span class="punct">=&gt;</span> <span class="punct">[</span>
89
- <span class="punct">&lt;</span><span class="constant">Membership</span><span class="punct">:</span><span class="number">0x394ade8</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">user_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">group_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;}&gt;,</span>
90
- <span class="punct">&lt;</span><span class="constant">Membership</span><span class="punct">:</span><span class="number">0x394ada0</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">user_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">2</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">group_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;}&gt;</span>
91
- <span class="punct">]</span></pre></p>
92
- <p>Perform <code>#count</code> operations</p>
93
- <p><pre class="syntax"><span class="constant">MembershipStatus</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="symbol">:first</span><span class="punct">).</span><span class="ident">memberships</span><span class="punct">.</span><span class="ident">count</span> <span class="comment"># =&gt; 1</span></pre></p>
94
- <h3>Routes with Rails</h3>
95
- <p>From Pete Sumskas:</p>
96
- <blockquote>
97
- <p>I ran into one problem that I didn&#8217;t see mentioned on <a href="http://groups.google.com/group/compositekeys">this list</a> &#8211; <br />
98
- and I didn&#8217;t see any information about what I should do to address it in the<br />
99
- documentation (might have missed it).</p>
100
- <p>The problem was that the urls being generated for a &#8216;show&#8217; action (for<br />
101
- example) had a syntax like:</p>
102
- <p><pre>/controller/show/123000,Bu70</pre></p>
103
- <p>for a two-field composite PK. The default routing would not match that,<br />
104
- so after working out how to do the routing I added:</p>
105
- <p><pre class="syntax"><span class="ident">map</span><span class="punct">.</span><span class="ident">connect</span> <span class="punct">'</span><span class="string">:controller/:action/:id</span><span class="punct">',</span> <span class="symbol">:id</span> <span class="punct">=&gt;</span> <span class="punct">/</span><span class="regex"><span class="escape">\w</span>+(,<span class="escape">\w</span>+)*</span><span class="punct">/</span></pre></p>
106
- <p>to my <code>route.rb</code> file.</p>
107
- </blockquote>
108
- <p><a name="dbs"></a></p>
109
- <h2>Which databases?</h2>
110
- <p>A suite of unit tests have been run on the following databases supported by ActiveRecord:</p>
111
- <table>
112
- <tr>
113
- <th>Database</th>
114
- <th>Test Success</th>
115
- <th>User feedback</th>
116
- </tr>
117
- <tr>
118
- <td>mysql </td>
119
- <td><span class=success><span class="caps">YES</span></span></td>
120
- <td><span class=success><span class="caps">YES</span></span> (<a href="mailto:compositekeys@googlegroups.com?subject=Mysql+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=Mysql+is+failing">No&#8230;</a>)</td>
121
- </tr>
122
- <tr>
123
- <td>sqlite3 </td>
124
- <td><span class=success><span class="caps">YES</span></span></td>
125
- <td><span class=success><span class="caps">YES</span></span> (<a href="mailto:compositekeys@googlegroups.com?subject=Sqlite3+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=Sqlite3+is+failing">No&#8230;</a>)</td>
126
- </tr>
127
- <tr>
128
- <td>postgresql</td>
129
- <td><span class=success><span class="caps">YES</span></span></td>
130
- <td><span class=success><span class="caps">YES</span></span> (<a href="mailto:compositekeys@googlegroups.com?subject=Postgresql+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=Postgresql+is+failing">No&#8230;</a>)</td>
131
- </tr>
132
- <tr>
133
- <td>oracle </td>
134
- <td><span class=success><span class="caps">YES</span></span></td>
135
- <td><span class=success><span class="caps">YES</span></span> (<a href="mailto:compositekeys@googlegroups.com?subject=Oracle+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=Oracle+is+failing">No&#8230;</a>)</td>
136
- </tr>
137
- <tr>
138
- <td>sqlserver </td>
139
- <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+SQLServer">I can help</a>)</td>
140
- <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=SQLServer+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=SQLServer+is+failing">No&#8230;</a>)</td>
141
- </tr>
142
- <tr>
143
- <td>db2 </td>
144
- <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+DB2">I can help</a>)</td>
145
- <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=DB2+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=DB2+is+failing">No&#8230;</a>)</td>
146
- </tr>
147
- <tr>
148
- <td>firebird </td>
149
- <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+Firebird">I can help</a>)</td>
150
- <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Firebird+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=Firebird+is+failing">No&#8230;</a>)</td>
151
- </tr>
152
- <tr>
153
- <td>sybase </td>
154
- <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+Sybase">I can help</a>)</td>
155
- <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Sybase+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=Sybase+is+failing">No&#8230;</a>)</td>
156
- </tr>
157
- <tr>
158
- <td>openbase </td>
159
- <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+Openbase">I can help</a>)</td>
160
- <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Openbase+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=Openbase+is+failing">No&#8230;</a>)</td>
161
- </tr>
162
- <tr>
163
- <td>frontbase </td>
164
- <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+Frontbase">I can help</a>)</td>
165
- <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Frontbase+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=Frontbase+is+failing">No&#8230;</a>)</td>
166
- </tr>
167
- </table>
168
- <h2>Dr Nic&#8217;s Blog</h2>
169
- <p><a href="http://www.drnicwilliams.com">http://www.drnicwilliams.com</a> &#8211; for future announcements and<br />
170
- other stories and things.</p>
171
- <h2>Forum</h2>
172
- <p><a href="http://groups.google.com/group/compositekeys">http://groups.google.com/group/compositekeys</a></p>
173
- <h2>How to submit patches</h2>
174
- <p>Read the <a href="http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/">8 steps for fixing other people&#8217;s code</a> and for section <a href="http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/#8b-google-groups">8b: Submit patch to Google Groups</a>, use the Google Group above.</p>
175
- <p>The source for this project is available via git. You can <a href="http://github.com/drnic/composite_primary_keys/tree/master">browse and/or fork the source</a>, or to clone the project locally:</p>
176
- <pre>git clone git://github.com/drnic/composite_primary_keys.git</pre>
177
- <h2>Licence</h2>
178
- <p>This code is free to use under the terms of the <span class="caps">MIT</span> licence.</p>
179
- <h2>Contact</h2>
180
- <p>Comments are welcome. Send an email to <a href="mailto:drnicwilliams@gmail.com">Dr Nic Williams</a>.</p>
181
- <p class="coda">
182
- <a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>, 13th February 2010<br>
183
- Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
184
- </p>
185
- </div>
186
-
187
- <script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
188
- </script>
189
- <script type="text/javascript">
190
- _uacct = "UA-567811-2";
191
- urchinTracker();
192
- </script>
193
-
194
- </body>
195
- </html>