tenacity 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/.gitignore +1 -0
  2. data/EXTEND.rdoc +18 -21
  3. data/Gemfile +0 -2
  4. data/README.rdoc +3 -1
  5. data/Rakefile +7 -0
  6. data/history.txt +17 -0
  7. data/lib/tenacity.rb +4 -0
  8. data/lib/tenacity/associates_proxy.rb +5 -7
  9. data/lib/tenacity/association.rb +9 -47
  10. data/lib/tenacity/associations/belongs_to.rb +1 -2
  11. data/lib/tenacity/associations/has_many.rb +27 -21
  12. data/lib/tenacity/associations/has_one.rb +3 -2
  13. data/lib/tenacity/class_methods.rb +14 -60
  14. data/lib/tenacity/errors.rb +8 -0
  15. data/lib/tenacity/instance_methods.rb +42 -12
  16. data/lib/tenacity/orm_ext/activerecord.rb +11 -32
  17. data/lib/tenacity/orm_ext/couchrest.rb +14 -22
  18. data/lib/tenacity/orm_ext/datamapper.rb +14 -31
  19. data/lib/tenacity/orm_ext/helpers.rb +3 -3
  20. data/lib/tenacity/orm_ext/mongo_mapper.rb +16 -22
  21. data/lib/tenacity/orm_ext/mongoid.rb +10 -18
  22. data/lib/tenacity/orm_ext/ripple.rb +270 -0
  23. data/lib/tenacity/orm_ext/sequel.rb +21 -33
  24. data/lib/tenacity/orm_ext/toystore.rb +114 -0
  25. data/lib/tenacity/version.rb +1 -1
  26. data/tenacity.gemspec +10 -3
  27. data/test/association_features/belongs_to_test.rb +12 -0
  28. data/test/association_features/has_many_test.rb +32 -2
  29. data/test/association_features/has_one_test.rb +18 -4
  30. data/test/associations/has_one_test.rb +0 -1
  31. data/test/core/classmethods_test.rb +7 -0
  32. data/test/fixtures/active_record_has_many_target.rb +4 -0
  33. data/test/fixtures/active_record_has_one_target.rb +4 -0
  34. data/test/fixtures/active_record_object.rb +8 -0
  35. data/test/fixtures/couch_rest_has_many_target.rb +4 -0
  36. data/test/fixtures/couch_rest_has_one_target.rb +4 -0
  37. data/test/fixtures/couch_rest_object.rb +8 -0
  38. data/test/fixtures/data_mapper_has_many_target.rb +10 -0
  39. data/test/fixtures/data_mapper_has_one_target.rb +10 -0
  40. data/test/fixtures/data_mapper_object.rb +8 -0
  41. data/test/fixtures/mongo_mapper_has_many_target.rb +4 -0
  42. data/test/fixtures/mongo_mapper_has_one_target.rb +4 -0
  43. data/test/fixtures/mongo_mapper_object.rb +8 -0
  44. data/test/fixtures/mongoid_has_many_target.rb +4 -0
  45. data/test/fixtures/mongoid_has_one_target.rb +4 -0
  46. data/test/fixtures/mongoid_object.rb +8 -0
  47. data/test/fixtures/no_associations.rb +4 -0
  48. data/test/fixtures/ripple_has_many_target.rb +24 -0
  49. data/test/fixtures/ripple_has_one_target.rb +24 -0
  50. data/test/fixtures/ripple_object.rb +42 -0
  51. data/test/fixtures/sequel_has_many_target.rb +4 -0
  52. data/test/fixtures/sequel_has_one_target.rb +4 -0
  53. data/test/fixtures/sequel_object.rb +8 -0
  54. data/test/fixtures/toystore_has_many_target.rb +28 -0
  55. data/test/fixtures/toystore_has_one_target.rb +28 -0
  56. data/test/fixtures/toystore_object.rb +46 -0
  57. data/test/helpers/active_record_test_helper.rb +12 -95
  58. data/test/helpers/data_mapper_test_helper.rb +0 -64
  59. data/test/helpers/ripple_test_helper.rb +19 -0
  60. data/test/helpers/sequel_test_helper.rb +13 -60
  61. data/test/helpers/toystore_test_helper.rb +17 -0
  62. data/test/orm_ext/activerecord_test.rb +16 -26
  63. data/test/orm_ext/couchrest_test.rb +10 -29
  64. data/test/orm_ext/datamapper_test.rb +16 -29
  65. data/test/orm_ext/mongo_mapper_test.rb +11 -29
  66. data/test/orm_ext/mongoid_test.rb +11 -29
  67. data/test/orm_ext/ripple_test.rb +140 -0
  68. data/test/orm_ext/sequel_test.rb +15 -26
  69. data/test/orm_ext/toystore_test.rb +103 -0
  70. data/test/test_helper.rb +35 -23
  71. metadata +99 -133
data/.gitignore CHANGED
@@ -8,3 +8,4 @@ doc/
8
8
  coverage/
9
9
  pkg/
10
10
  Gemfile.lock
11
+ log/
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
- If only some of the objects could be found, then simply return those objects
38
- in the array.
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. Return nothing.
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
@@ -1,6 +1,4 @@
1
1
  source "http://rubygems.org"
2
2
  source :gemcutter
3
3
 
4
- gem 'mongo_mapper', :git => 'git://github.com/jnunemaker/mongomapper.git'
5
-
6
4
  gemspec
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 configured.
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
- ids = prepare_for_delete
40
- @association.associate_class._t_delete(ids)
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
- ids = prepare_for_delete
45
- @association.associate_class._t_delete(ids, false)
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 prepare_for_delete
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)
@@ -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
- private
141
-
142
- def fetch_table_name
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
- associate = clazz._t_find(associate_id)
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 _t_ivar_name(association), []
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 _t_ivar_name(association), clazz._t_find_bulk(associate_ids)
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.inspect
96
+ old_associates.first
85
97
 
86
98
  _t_clear_old_associations(record, association)
87
99
 
88
- associates = (record.instance_variable_get record._t_ivar_name(association)) || []
89
- associates.each do |associate|
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
- associate = clazz._t_find_first_by_associate(association.foreign_key(self.class), _t_serialize(self.id, association))
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. One-to-many associations that contain a
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: