tenacity 0.4.1 → 0.5.0
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.
- data/.gitignore +1 -0
- data/EXTEND.rdoc +18 -21
- data/Gemfile +0 -2
- data/README.rdoc +3 -1
- data/Rakefile +7 -0
- data/history.txt +17 -0
- data/lib/tenacity.rb +4 -0
- data/lib/tenacity/associates_proxy.rb +5 -7
- data/lib/tenacity/association.rb +9 -47
- data/lib/tenacity/associations/belongs_to.rb +1 -2
- data/lib/tenacity/associations/has_many.rb +27 -21
- data/lib/tenacity/associations/has_one.rb +3 -2
- data/lib/tenacity/class_methods.rb +14 -60
- data/lib/tenacity/errors.rb +8 -0
- data/lib/tenacity/instance_methods.rb +42 -12
- data/lib/tenacity/orm_ext/activerecord.rb +11 -32
- data/lib/tenacity/orm_ext/couchrest.rb +14 -22
- data/lib/tenacity/orm_ext/datamapper.rb +14 -31
- data/lib/tenacity/orm_ext/helpers.rb +3 -3
- data/lib/tenacity/orm_ext/mongo_mapper.rb +16 -22
- data/lib/tenacity/orm_ext/mongoid.rb +10 -18
- data/lib/tenacity/orm_ext/ripple.rb +270 -0
- data/lib/tenacity/orm_ext/sequel.rb +21 -33
- data/lib/tenacity/orm_ext/toystore.rb +114 -0
- data/lib/tenacity/version.rb +1 -1
- data/tenacity.gemspec +10 -3
- data/test/association_features/belongs_to_test.rb +12 -0
- data/test/association_features/has_many_test.rb +32 -2
- data/test/association_features/has_one_test.rb +18 -4
- data/test/associations/has_one_test.rb +0 -1
- data/test/core/classmethods_test.rb +7 -0
- data/test/fixtures/active_record_has_many_target.rb +4 -0
- data/test/fixtures/active_record_has_one_target.rb +4 -0
- data/test/fixtures/active_record_object.rb +8 -0
- data/test/fixtures/couch_rest_has_many_target.rb +4 -0
- data/test/fixtures/couch_rest_has_one_target.rb +4 -0
- data/test/fixtures/couch_rest_object.rb +8 -0
- data/test/fixtures/data_mapper_has_many_target.rb +10 -0
- data/test/fixtures/data_mapper_has_one_target.rb +10 -0
- data/test/fixtures/data_mapper_object.rb +8 -0
- data/test/fixtures/mongo_mapper_has_many_target.rb +4 -0
- data/test/fixtures/mongo_mapper_has_one_target.rb +4 -0
- data/test/fixtures/mongo_mapper_object.rb +8 -0
- data/test/fixtures/mongoid_has_many_target.rb +4 -0
- data/test/fixtures/mongoid_has_one_target.rb +4 -0
- data/test/fixtures/mongoid_object.rb +8 -0
- data/test/fixtures/no_associations.rb +4 -0
- data/test/fixtures/ripple_has_many_target.rb +24 -0
- data/test/fixtures/ripple_has_one_target.rb +24 -0
- data/test/fixtures/ripple_object.rb +42 -0
- data/test/fixtures/sequel_has_many_target.rb +4 -0
- data/test/fixtures/sequel_has_one_target.rb +4 -0
- data/test/fixtures/sequel_object.rb +8 -0
- data/test/fixtures/toystore_has_many_target.rb +28 -0
- data/test/fixtures/toystore_has_one_target.rb +28 -0
- data/test/fixtures/toystore_object.rb +46 -0
- data/test/helpers/active_record_test_helper.rb +12 -95
- data/test/helpers/data_mapper_test_helper.rb +0 -64
- data/test/helpers/ripple_test_helper.rb +19 -0
- data/test/helpers/sequel_test_helper.rb +13 -60
- data/test/helpers/toystore_test_helper.rb +17 -0
- data/test/orm_ext/activerecord_test.rb +16 -26
- data/test/orm_ext/couchrest_test.rb +10 -29
- data/test/orm_ext/datamapper_test.rb +16 -29
- data/test/orm_ext/mongo_mapper_test.rb +11 -29
- data/test/orm_ext/mongoid_test.rb +11 -29
- data/test/orm_ext/ripple_test.rb +140 -0
- data/test/orm_ext/sequel_test.rb +15 -26
- data/test/orm_ext/toystore_test.rb +103 -0
- data/test/test_helper.rb +35 -23
- metadata +99 -133
data/.gitignore
CHANGED
data/EXTEND.rdoc
CHANGED
@@ -14,6 +14,11 @@ lib/tenacity/association.rb.
|
|
14
14
|
|
15
15
|
== Class Methods
|
16
16
|
|
17
|
+
_t_id_type
|
18
|
+
|
19
|
+
The type to use when storing instances of this class in a database.
|
20
|
+
Usually String or Integer.
|
21
|
+
|
17
22
|
_t_find(id)
|
18
23
|
|
19
24
|
Find an object by its id, and return it. If the object cannot be found,
|
@@ -34,8 +39,12 @@ and return it. If no object could be found, return nil.
|
|
34
39
|
|
35
40
|
Find all objects by the specified property name, with the specified id, and
|
36
41
|
return them in an array. If no objects could be found, return an empty array.
|
37
|
-
|
38
|
-
|
42
|
+
|
43
|
+
_t_find_all_ids_by_associate(property, id)
|
44
|
+
|
45
|
+
Find all ids of rows/documents/etc by the specified property name, with the
|
46
|
+
specified id, and return them in an array. If no data could be found, return
|
47
|
+
an empty array.
|
39
48
|
|
40
49
|
_t_delete(ids, run_callbacks=true)
|
41
50
|
|
@@ -44,6 +53,12 @@ objects should be deleted in such a way that their delete callback methods
|
|
44
53
|
are run. If false, the objects should be deleted in such a way that their
|
45
54
|
delete callback meethods are not run. Return nothing.
|
46
55
|
|
56
|
+
_t_initialize_tenacity
|
57
|
+
|
58
|
+
Perform any database client specific initialization necessary to support Tenacity
|
59
|
+
associations. This could include defining callbacks on the object required for
|
60
|
+
all association types.
|
61
|
+
|
47
62
|
_t_initialize_has_many_association(association)
|
48
63
|
|
49
64
|
Perform any database client specific initialization necessary to support a has
|
@@ -73,23 +88,5 @@ when the after the object has been deleted.
|
|
73
88
|
_t_reload
|
74
89
|
|
75
90
|
Reload the object from the database, overwriting the objects properties with
|
76
|
-
the data fetched from the database.
|
77
|
-
|
78
|
-
_t_associate_many(association, associate_ids)
|
79
|
-
|
80
|
-
Create has_many associations between this object and the objects with ids
|
81
|
-
specified in the array of associate_ids. This method could involve writing
|
82
|
-
the associate_ids into a join table, or into one of the object's properties.
|
83
|
-
Return nothing.
|
84
|
-
|
85
|
-
_t_get_associate_ids(association)
|
86
|
-
|
87
|
-
Get the ids of the objects associated with this object through the specified
|
88
|
-
association, and return them in an array. Return an empty array if there
|
89
|
-
are no associated objects.
|
90
|
-
|
91
|
-
_t_clear_associates(association)
|
92
|
-
|
93
|
-
Destroy the association between this object and its current associates through
|
94
|
-
the specified association. Return nothing.
|
91
|
+
the data fetched from the database. Returns the instance of the class (self).
|
95
92
|
|
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -87,7 +87,9 @@ much the same way, supporting many of the same options.
|
|
87
87
|
* DataMapper
|
88
88
|
* MongoMapper
|
89
89
|
* Mongoid
|
90
|
+
* Ripple
|
90
91
|
* Sequel
|
92
|
+
* Toystore
|
91
93
|
|
92
94
|
See EXTEND.rdoc for information on extending Tenacity to work with other database clients.
|
93
95
|
|
@@ -110,7 +112,7 @@ See EXTEND.rdoc for information on extending Tenacity to work with other databas
|
|
110
112
|
|
111
113
|
== Development
|
112
114
|
|
113
|
-
* SQLite, MongoDB, and CouchDB must be installed and
|
115
|
+
* SQLite, MongoDB, Riak, and CouchDB must be installed, configured, and running.
|
114
116
|
* Install the dependencies
|
115
117
|
|
116
118
|
bundle install
|
data/Rakefile
CHANGED
@@ -20,6 +20,7 @@ require 'yard'
|
|
20
20
|
task :default => :test
|
21
21
|
|
22
22
|
Rake::TestTask.new(:test) do |test|
|
23
|
+
ENV['TENACITY_TEST'] = 'true'
|
23
24
|
test.libs << 'lib' << 'test' << 'test/fixtures'
|
24
25
|
test.pattern = ENV['TEST'] || "test/**/*_test.rb"
|
25
26
|
test.verbose = true
|
@@ -31,6 +32,12 @@ task :quick_test do
|
|
31
32
|
Rake::Task["test"].invoke
|
32
33
|
end
|
33
34
|
|
35
|
+
desc 'Run the full test suite, testing all ORM/ODMs against each other'
|
36
|
+
task :long_test do
|
37
|
+
ENV['LONG'] = 'true'
|
38
|
+
Rake::Task["test"].invoke
|
39
|
+
end
|
40
|
+
|
34
41
|
Rcov::RcovTask.new do |test|
|
35
42
|
test.libs << 'test' << 'test/fixtures'
|
36
43
|
test.pattern = 'test/**/*_test.rb'
|
data/history.txt
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
== 0.5.0
|
2
|
+
|
3
|
+
* Major enhancements
|
4
|
+
|
5
|
+
* Added code to verify target object in a t_belongs_to association exists when
|
6
|
+
saving the source object
|
7
|
+
* Don't allow the source object in a t_has_one or t_has_many association to be
|
8
|
+
deleted if the target object in the association is holding its id
|
9
|
+
* Removed the need for join tables for t_has_many associations
|
10
|
+
* Added support for Ripple
|
11
|
+
* Added support for Toystore
|
12
|
+
|
13
|
+
* Bug fixes
|
14
|
+
|
15
|
+
* Fixed bug preventing an object including the Tenacity module from being saved
|
16
|
+
successfully if it had no associations
|
17
|
+
|
1
18
|
== 0.4.1
|
2
19
|
|
3
20
|
* Bug fixes
|
data/lib/tenacity.rb
CHANGED
@@ -15,7 +15,9 @@ require File.join(File.dirname(__FILE__), 'tenacity', 'orm_ext', 'couchrest')
|
|
15
15
|
require File.join(File.dirname(__FILE__), 'tenacity', 'orm_ext', 'datamapper')
|
16
16
|
require File.join(File.dirname(__FILE__), 'tenacity', 'orm_ext', 'mongo_mapper')
|
17
17
|
require File.join(File.dirname(__FILE__), 'tenacity', 'orm_ext', 'mongoid')
|
18
|
+
require File.join(File.dirname(__FILE__), 'tenacity', 'orm_ext', 'ripple')
|
18
19
|
require File.join(File.dirname(__FILE__), 'tenacity', 'orm_ext', 'sequel')
|
20
|
+
require File.join(File.dirname(__FILE__), 'tenacity', 'orm_ext', 'toystore')
|
19
21
|
|
20
22
|
module Tenacity #:nodoc:
|
21
23
|
include InstanceMethods
|
@@ -30,7 +32,9 @@ module Tenacity #:nodoc:
|
|
30
32
|
OrmExt::DataMapper.setup(model)
|
31
33
|
OrmExt::MongoMapper.setup(model)
|
32
34
|
OrmExt::Mongoid.setup(model)
|
35
|
+
OrmExt::Ripple.setup(model)
|
33
36
|
OrmExt::Sequel.setup(model)
|
37
|
+
OrmExt::Toystore.setup(model)
|
34
38
|
|
35
39
|
raise "Tenacity does not support the database client used by #{model}" unless model.respond_to?(:_t_find)
|
36
40
|
model.extend(ClassMethods)
|
@@ -36,13 +36,13 @@ module Tenacity
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def destroy_all
|
39
|
-
|
40
|
-
@association.associate_class._t_delete(
|
39
|
+
remove_associates_from_parent
|
40
|
+
@association.associate_class._t_delete(@parent._t_get_associate_ids(@association))
|
41
41
|
end
|
42
42
|
|
43
43
|
def delete_all
|
44
|
-
|
45
|
-
@association.associate_class._t_delete(
|
44
|
+
remove_associates_from_parent
|
45
|
+
@association.associate_class._t_delete(@parent._t_get_associate_ids(@association), false)
|
46
46
|
end
|
47
47
|
|
48
48
|
def inspect
|
@@ -51,11 +51,9 @@ module Tenacity
|
|
51
51
|
|
52
52
|
private
|
53
53
|
|
54
|
-
def
|
55
|
-
ids = @parent._t_get_associate_ids(@association)
|
54
|
+
def remove_associates_from_parent
|
56
55
|
@parent._t_remove_associates(@association)
|
57
56
|
@parent.save
|
58
|
-
ids
|
59
57
|
end
|
60
58
|
|
61
59
|
def method_missing(method, *args)
|
data/lib/tenacity/association.rb
CHANGED
@@ -35,6 +35,9 @@ module Tenacity
|
|
35
35
|
# Is this association a polymorphic association?
|
36
36
|
attr_reader :polymorphic
|
37
37
|
|
38
|
+
# Should this association disable foreign key like constraints
|
39
|
+
attr_reader :disable_foreign_key_constraints
|
40
|
+
|
38
41
|
def initialize(type, name, source, options={})
|
39
42
|
@type = type
|
40
43
|
@name = name
|
@@ -47,10 +50,6 @@ module Tenacity
|
|
47
50
|
end
|
48
51
|
|
49
52
|
@foreign_key = options[:foreign_key]
|
50
|
-
@foreign_keys_property = options[:foreign_keys_property]
|
51
|
-
@join_table = options[:join_table]
|
52
|
-
@association_key = options[:association_key]
|
53
|
-
@association_foreign_key = options[:association_foreign_key]
|
54
53
|
@dependent = options[:dependent]
|
55
54
|
@readonly = options[:readonly]
|
56
55
|
@limit = options[:limit]
|
@@ -58,12 +57,7 @@ module Tenacity
|
|
58
57
|
@autosave = options[:autosave]
|
59
58
|
@polymorphic = options[:polymorphic]
|
60
59
|
@as = options[:as]
|
61
|
-
|
62
|
-
if @foreign_keys_property
|
63
|
-
if @foreign_keys_property.to_s == ActiveSupport::Inflector.singularize(name) + "_ids"
|
64
|
-
raise "#{ActiveSupport::Inflector.singularize(name) + "_ids"} is an invalid foreign keys property name"
|
65
|
-
end
|
66
|
-
end
|
60
|
+
@disable_foreign_key_constraints = options[:disable_foreign_key_constraints]
|
67
61
|
end
|
68
62
|
|
69
63
|
# The name of the association
|
@@ -93,35 +87,6 @@ module Tenacity
|
|
93
87
|
end
|
94
88
|
end
|
95
89
|
|
96
|
-
# Get the property name used to store the foreign key
|
97
|
-
def foreign_keys_property
|
98
|
-
@foreign_keys_property || "t_" + ActiveSupport::Inflector.singularize(name) + "_ids"
|
99
|
-
end
|
100
|
-
|
101
|
-
# Get the name of the join table used by this association
|
102
|
-
def join_table
|
103
|
-
table_name = fetch_table_name
|
104
|
-
|
105
|
-
if @type == :t_has_many && polymorphic?
|
106
|
-
association_name_for_join_table = name.to_s.pluralize
|
107
|
-
else
|
108
|
-
association_name_for_join_table = name
|
109
|
-
end
|
110
|
-
|
111
|
-
@join_table || (name.to_s < table_name ? "#{association_name_for_join_table}_#{table_name}" : "#{table_name}_#{association_name_for_join_table}")
|
112
|
-
end
|
113
|
-
|
114
|
-
# Get the name of the column in the join table that represents this object
|
115
|
-
def association_key
|
116
|
-
table_name = fetch_table_name
|
117
|
-
@association_key || table_name.singularize + '_id'
|
118
|
-
end
|
119
|
-
|
120
|
-
# Get the name of the column in the join table that represents the associated object
|
121
|
-
def association_foreign_key
|
122
|
-
@association_foreign_key || name.to_s.singularize + '_id'
|
123
|
-
end
|
124
|
-
|
125
90
|
# Are the associated objects read only?
|
126
91
|
def readonly?
|
127
92
|
@readonly == true
|
@@ -137,16 +102,13 @@ module Tenacity
|
|
137
102
|
(name.to_s + "_type").to_sym
|
138
103
|
end
|
139
104
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
if @source.respond_to?(:table_name)
|
144
|
-
@source.table_name.to_s
|
145
|
-
else
|
146
|
-
"#{ActiveSupport::Inflector.underscore(@source)}s"
|
147
|
-
end
|
105
|
+
# Are foreign key constraints enabled for this association?
|
106
|
+
def foreign_key_constraints_enabled?
|
107
|
+
@disable_foreign_key_constraints != true
|
148
108
|
end
|
149
109
|
|
110
|
+
private
|
111
|
+
|
150
112
|
def belongs_to_foreign_key
|
151
113
|
if polymorphic?
|
152
114
|
(name.to_s + "_id").to_sym
|
@@ -18,8 +18,7 @@ module Tenacity
|
|
18
18
|
def belongs_to_associate(association)
|
19
19
|
associate_id = self.send(association.foreign_key)
|
20
20
|
clazz = association.associate_class(self)
|
21
|
-
|
22
|
-
associate
|
21
|
+
clazz._t_find(associate_id)
|
23
22
|
end
|
24
23
|
|
25
24
|
def set_belongs_to_associate(association, associate)
|
@@ -3,8 +3,7 @@ module Tenacity
|
|
3
3
|
module HasMany #:nodoc:
|
4
4
|
|
5
5
|
def _t_remove_associates(association)
|
6
|
-
instance_variable_set
|
7
|
-
_t_clear_associates(association)
|
6
|
+
instance_variable_set(_t_ivar_name(association), [])
|
8
7
|
end
|
9
8
|
|
10
9
|
def _t_cleanup_has_many_association(association)
|
@@ -19,10 +18,23 @@ module Tenacity
|
|
19
18
|
associate.send "#{association.foreign_key(self.class)}=", nil
|
20
19
|
associate.save
|
21
20
|
end
|
21
|
+
elsif association.foreign_key_constraints_enabled?
|
22
|
+
raise ObjectIdInUseError.new("Unable to delete #{self.class} with id of #{self.id} because its id is being referenced by instances of #{associates.first.class}(id: #{associates.map(&:id).join(',')})!")
|
22
23
|
end
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
27
|
+
def _t_get_associate_ids(association)
|
28
|
+
if self.id.nil?
|
29
|
+
[]
|
30
|
+
else
|
31
|
+
foreign_key = association.foreign_key(self.class)
|
32
|
+
associate_id = self.class._t_serialize_ids(self.id, association)
|
33
|
+
ids = association.associate_class._t_find_all_ids_by_associate(foreign_key, associate_id)
|
34
|
+
self.class._t_serialize_ids(ids, association)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
26
38
|
private
|
27
39
|
|
28
40
|
def has_many_associates(association)
|
@@ -43,7 +55,7 @@ module Tenacity
|
|
43
55
|
|
44
56
|
def set_has_many_associate_ids(association, associate_ids)
|
45
57
|
clazz = association.associate_class
|
46
|
-
instance_variable_set
|
58
|
+
instance_variable_set(_t_ivar_name(association), clazz._t_find_bulk(associate_ids))
|
47
59
|
end
|
48
60
|
|
49
61
|
def save_without_callback
|
@@ -81,24 +93,12 @@ module Tenacity
|
|
81
93
|
# place of the associated objects. The actual associated objects
|
82
94
|
# will be fetched the first time they are needed. So, force them to
|
83
95
|
# be fetched here, before we clear them out in the database.
|
84
|
-
old_associates.
|
96
|
+
old_associates.first
|
85
97
|
|
86
98
|
_t_clear_old_associations(record, association)
|
87
99
|
|
88
|
-
associates = (record.instance_variable_get
|
89
|
-
|
90
|
-
associate._t_reload
|
91
|
-
associate.send("#{association.foreign_key(record.class)}=", _t_serialize(record.id, association))
|
92
|
-
associate.send "#{association.polymorphic_type}=", self.to_s if association.polymorphic?
|
93
|
-
save_associate(associate)
|
94
|
-
end
|
95
|
-
|
96
|
-
unless associates.blank?
|
97
|
-
associate_ids = associates.map { |associate| _t_serialize(associate.id) }
|
98
|
-
record._t_associate_many(association, associate_ids)
|
99
|
-
save_associate(record)
|
100
|
-
end
|
101
|
-
|
100
|
+
associates = (record.instance_variable_get(record._t_ivar_name(association))) || []
|
101
|
+
establish_relationship_in_target_objects(record, association, associates)
|
102
102
|
destroy_orphaned_associates(association, old_associates, associates)
|
103
103
|
end
|
104
104
|
|
@@ -109,9 +109,6 @@ module Tenacity
|
|
109
109
|
old_associate.send("#{property_name}=", nil)
|
110
110
|
save_associate(old_associate)
|
111
111
|
end
|
112
|
-
|
113
|
-
record._t_clear_associates(association)
|
114
|
-
save_associate(record)
|
115
112
|
end
|
116
113
|
|
117
114
|
def save_associate(associate)
|
@@ -132,6 +129,15 @@ module Tenacity
|
|
132
129
|
end
|
133
130
|
end
|
134
131
|
end
|
132
|
+
|
133
|
+
def establish_relationship_in_target_objects(record, association, associates)
|
134
|
+
associates.each do |a|
|
135
|
+
associate = a._t_reload
|
136
|
+
associate.send("#{association.foreign_key(record.class)}=", _t_serialize(record.id, association))
|
137
|
+
associate.send "#{association.polymorphic_type}=", self.to_s if association.polymorphic?
|
138
|
+
save_associate(associate)
|
139
|
+
end
|
140
|
+
end
|
135
141
|
end
|
136
142
|
|
137
143
|
end
|
@@ -12,6 +12,8 @@ module Tenacity
|
|
12
12
|
elsif association.dependent == :nullify
|
13
13
|
associate.send "#{association.foreign_key(self.class)}=", nil
|
14
14
|
associate.save
|
15
|
+
elsif association.foreign_key_constraints_enabled?
|
16
|
+
raise ObjectIdInUseError.new("Unable to delete #{self.class} with id of #{self.id} because its id is being referenced by an instance of #{associate.class}(id: #{associate.id})!")
|
15
17
|
end
|
16
18
|
end
|
17
19
|
end
|
@@ -20,8 +22,7 @@ module Tenacity
|
|
20
22
|
|
21
23
|
def has_one_associate(association)
|
22
24
|
clazz = association.associate_class
|
23
|
-
|
24
|
-
associate
|
25
|
+
clazz._t_find_first_by_associate(association.foreign_key(self.class), _t_serialize(self.id, association))
|
25
26
|
end
|
26
27
|
|
27
28
|
def set_has_one_associate(association, associate)
|
@@ -140,34 +140,7 @@ module Tenacity
|
|
140
140
|
# project.milestones(true).size # fetches milestones from the database
|
141
141
|
# project.milestones # uses the milestone cache
|
142
142
|
#
|
143
|
-
# == Join Tables
|
144
|
-
#
|
145
|
-
# One-to-many assocations that contain a relational database backed object as one of
|
146
|
-
# the assocaites are implemented using an intermediate join table. This differs from
|
147
|
-
# ActiveRecord::Associations, where only many-to-many relationships are implemented
|
148
|
-
# using an intermediate join table.
|
149
|
-
#
|
150
|
-
# Tenacity will not create the join table. It assume one exists, and is named properly.
|
151
|
-
# Unless the join table is explicitly specified as an option, it is guessed using the
|
152
|
-
# lexical order of the class names. So a join between Developer and Project will give
|
153
|
-
# the default join table name of "developers_projects" because "D" outranks "P". Note
|
154
|
-
# that this precedence is calculated using the < operator for String. This means that
|
155
|
-
# if the strings are of different lengths, and the strings are equal when compared up
|
156
|
-
# to the shortest length, then the longer string is considered of higher lexical
|
157
|
-
# precedence than the shorter one. For example, one would expect the tables "paper_boxes"
|
158
|
-
# and "papers" to generate a join table name of "papers_paper_boxes" because of the
|
159
|
-
# length of the name "paper_boxes", but it in fact generates a join table name of
|
160
|
-
# "paper_boxes_papers". Be aware of this caveat, and use the custom :join_table option
|
161
|
-
# if you need to.
|
162
|
-
#
|
163
|
-
# The column names used in the join table are guessed to be the names of the associated
|
164
|
-
# classes, suffixed with "_id". For example, the "developers_projects" join table
|
165
|
-
# mentioned above is expected to have a column named "developer_id" and a column named
|
166
|
-
# "project_id". The <tt>:associate_key</tt> and <tt>:associate_foreign_key</tt> options
|
167
|
-
# can be used to override these defaults.
|
168
|
-
#
|
169
143
|
module ClassMethods
|
170
|
-
attr_reader :_tenacity_associations
|
171
144
|
|
172
145
|
# Specifies a one-to-one association with another class. This method should only be used
|
173
146
|
# if the other class contains the foreign key. If the current class contains the foreign key,
|
@@ -210,6 +183,9 @@ module Tenacity
|
|
210
183
|
# If true, always save the associated object or destroy it if marked for destruction, when saving the parent object. Off by default.
|
211
184
|
# [:as]
|
212
185
|
# Specifies a polymorphic interface (See <tt>t_belongs_to</tt>).
|
186
|
+
# [:disable_foreign_key_constraints]
|
187
|
+
# If true, bypass foreign key constraints, like verifying no other objects are storing the key of the source object
|
188
|
+
# before deleting it. Defaults to false.
|
213
189
|
#
|
214
190
|
# Option examples:
|
215
191
|
# t_has_one :credit_card, :dependent => :destroy # destroys the associated credit card
|
@@ -282,6 +258,9 @@ module Tenacity
|
|
282
258
|
# [:polymorphic]
|
283
259
|
# Specify this association is a polymorphic association by passing +true+. (*Note*: IDs for polymorphic associations are always
|
284
260
|
# stored as strings in the database.)
|
261
|
+
# [:disable_foreign_key_constraints]
|
262
|
+
# If true, bypass foreign key constraints, like verifying the target object exists when the relationship is created.
|
263
|
+
# Defaults to false.
|
285
264
|
#
|
286
265
|
# Option examples:
|
287
266
|
# t_belongs_to :project_manager, :class_name => "Person"
|
@@ -307,10 +286,7 @@ module Tenacity
|
|
307
286
|
end
|
308
287
|
end
|
309
288
|
|
310
|
-
# Specifies a one-to-many association.
|
311
|
-
# relational database backed object as one of the associates are implemented
|
312
|
-
# using an intermediate join table. See the Join Tables section at the top
|
313
|
-
# for more information.
|
289
|
+
# Specifies a one-to-many association.
|
314
290
|
#
|
315
291
|
# The following methods for retrieval and query of collections of associated objects will be added:
|
316
292
|
#
|
@@ -375,37 +351,12 @@ module Tenacity
|
|
375
351
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
376
352
|
# of this class in lower-case and "_id" suffixed. So a Person class that makes a +t_has_many+
|
377
353
|
# association will use "person_id" as the default <tt>:foreign_key</tt>.
|
378
|
-
# [:foreign_keys_property]
|
379
|
-
# Specify the name of the property that stores the ids of the associated objects. By default
|
380
|
-
# this is guessed to be the name of the association with a "t_" prefix and an "_ids" suffix.
|
381
|
-
# So a class that defines a <tt>t_has_many :people</tt> association will use t_people_ids as
|
382
|
-
# the property to store the ids of the associated People objects. This option is only valid
|
383
|
-
# for objects that store associated ids in an array instaed of a join table (CouchRest,
|
384
|
-
# MongoMapper, etc). <b>WARNING:</b> The name of the association with an "_ids" suffix should
|
385
|
-
# not be used as the property name, since tenacity adds a method with this name to the object.
|
386
354
|
# [:dependent]
|
387
355
|
# If set to <tt>:destroy</tt> all the associated objects are deleted alongside this object
|
388
356
|
# in addition to calling their delete callbacks. If set to <tt>:delete_all</tt> all
|
389
357
|
# associated objects are deleted *without* calling their delete callbacks. If set to
|
390
358
|
# <tt>:nullify</tt> all associated objects' foreign keys are set to +NULL+ *without* calling
|
391
359
|
# their save backs.
|
392
|
-
# [:join_table]
|
393
|
-
# Specify the name of the join table if the default based on lexical order isn't what you want.
|
394
|
-
# This option is only valid if one of the models in the association is backed by a relational
|
395
|
-
# database.
|
396
|
-
# [:association_foreign_key]
|
397
|
-
# Specify the foreign key in the join table used for the association on the receiving side of
|
398
|
-
# the association. By default this is guessed to be the name of the associated class in
|
399
|
-
# lower-case and "_id" suffixed. So if a Person class makes a +t_has_many+ association to
|
400
|
-
# Project, the association will use "project_id" as the default <tt>:association_foreign_key</tt>.
|
401
|
-
# This option is only valid if one of the associated objects is backed by a relational
|
402
|
-
# database.
|
403
|
-
# [:association_key]
|
404
|
-
# Specify the key in the join table used for the association on the declaring side of
|
405
|
-
# the association. By default this is guessed to be the name of this class in lower-case and
|
406
|
-
# "_id" suffixed. So if a Person class makes a +t_has_many+ association to Project, the
|
407
|
-
# association will use "person_id" as the default <tt>:association_key</tt>. This option is
|
408
|
-
# only valid if one of the associated objects is backed by a relational database.
|
409
360
|
# [:readonly]
|
410
361
|
# If true, all the associated objects are readonly through the association.
|
411
362
|
# [:limit]
|
@@ -418,14 +369,13 @@ module Tenacity
|
|
418
369
|
# If true, always save any loaded members and destroy members marked for destruction, when saving the parent object. Off by default.
|
419
370
|
# [:as]
|
420
371
|
# Specifies a polymorphic interface (See <tt>t_belongs_to</tt>).
|
372
|
+
# [:disable_foreign_key_constraints]
|
373
|
+
# If true, bypass foreign key constraints, like verifying no other objects are storing the key of the source object
|
374
|
+
# before deleting it. Defaults to false.
|
421
375
|
#
|
422
376
|
# Option examples:
|
423
377
|
# t_has_many :products, :class_name => "SpecialProduct"
|
424
378
|
# t_has_many :engineers, :foreign_key => "project_id" # within class named SecretProject
|
425
|
-
# t_has_many :engineers, :foreign_keys_property => "worker_ids"
|
426
|
-
# t_has_many :managers, :join_table => "project_managers_and_projects"
|
427
|
-
# t_has_many :managers, :join_table => "project_managers_and_projects",
|
428
|
-
# :association_foreign_key => "mgr_id", :association_key => "proj_id"
|
429
379
|
# t_has_many :tasks, :dependent => :destroy
|
430
380
|
# t_has_many :reports, :readonly => true
|
431
381
|
# t_has_many :tags, :as => :taggable
|
@@ -474,6 +424,10 @@ module Tenacity
|
|
474
424
|
end
|
475
425
|
end
|
476
426
|
|
427
|
+
def _tenacity_associations
|
428
|
+
@_tenacity_associations || []
|
429
|
+
end
|
430
|
+
|
477
431
|
private
|
478
432
|
|
479
433
|
def _t_create_association(type, name, options) #:nococ:
|