bigrecord 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -13,484 +13,8 @@ module BigRecord
13
13
  base.extend(ClassMethods)
14
14
  end
15
15
 
16
- # Associations are a set of macro-like class methods for tying objects together through foreign keys. They express relationships like
17
- # "Project has one Project Manager" or "Project belongs to a Portfolio". Each macro adds a number of methods to the class which are
18
- # specialized according to the collection or association symbol and the options hash. It works much the same way as Ruby's own attr*
19
- # methods. Example:
20
- #
21
- # class Project < BigRecord::Base
22
- # belongs_to :portfolio
23
- # has_one :project_manager
24
- # has_many :milestones
25
- # has_and_belongs_to_many :categories
26
- # end
27
- #
28
- # The project class now has the following methods (and more) to ease the traversal and manipulation of its relationships:
29
- # * <tt>Project#portfolio, Project#portfolio=(portfolio), Project#portfolio.nil?</tt>
30
- # * <tt>Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?,</tt>
31
- # * <tt>Project#milestones.empty?, Project#milestones.size, Project#milestones, Project#milestones<<(milestone),</tt>
32
- # <tt>Project#milestones.delete(milestone), Project#milestones.find(milestone_id), Project#milestones.find(:all, options),</tt>
33
- # <tt>Project#milestones.build, Project#milestones.create</tt>
34
- # * <tt>Project#categories.empty?, Project#categories.size, Project#categories, Project#categories<<(category1),</tt>
35
- # <tt>Project#categories.delete(category1)</tt>
36
- #
37
- # == Example
38
- #
39
- # link:files/examples/associations.png
40
- #
41
- # == Is it belongs_to or has_one?
42
- #
43
- # Both express a 1-1 relationship, the difference is mostly where to place the foreign key, which goes on the table for the class
44
- # saying belongs_to. Example:
45
- #
46
- # class User < BigRecord::Base
47
- # # I reference an account.
48
- # belongs_to :account
49
- # end
50
- #
51
- # class Account < BigRecord::Base
52
- # # One user references me.
53
- # has_one :user
54
- # end
55
- #
56
- # The tables for these classes could look something like:
57
- #
58
- # CREATE TABLE users (
59
- # id int(11) NOT NULL auto_increment,
60
- # account_id int(11) default NULL,
61
- # name varchar default NULL,
62
- # PRIMARY KEY (id)
63
- # )
64
- #
65
- # CREATE TABLE accounts (
66
- # id int(11) NOT NULL auto_increment,
67
- # name varchar default NULL,
68
- # PRIMARY KEY (id)
69
- # )
70
- #
71
- # == Unsaved objects and associations
72
- #
73
- # You can manipulate objects and associations before they are saved to the database, but there is some special behaviour you should be
74
- # aware of, mostly involving the saving of associated objects.
75
- #
76
- # === One-to-one associations
77
- #
78
- # * Assigning an object to a has_one association automatically saves that object and the object being replaced (if there is one), in
79
- # order to update their primary keys - except if the parent object is unsaved (new_record? == true).
80
- # * If either of these saves fail (due to one of the objects being invalid) the assignment statement returns false and the assignment
81
- # is cancelled.
82
- # * If you wish to assign an object to a has_one association without saving it, use the #association.build method (documented below).
83
- # * Assigning an object to a belongs_to association does not save the object, since the foreign key field belongs on the parent. It does
84
- # not save the parent either.
85
- #
86
- # === Collections
87
- #
88
- # * Adding an object to a collection (has_many or has_and_belongs_to_many) automatically saves that object, except if the parent object
89
- # (the owner of the collection) is not yet stored in the database.
90
- # * If saving any of the objects being added to a collection (via #push or similar) fails, then #push returns false.
91
- # * You can add an object to a collection without automatically saving it by using the #collection.build method (documented below).
92
- # * All unsaved (new_record? == true) members of the collection are automatically saved when the parent is saved.
93
- #
94
- # === Association callbacks
95
- #
96
- # Similiar to the normal callbacks that hook into the lifecycle of an Active Record object, you can also define callbacks that get
97
- # trigged when you add an object to or removing an object from a association collection. Example:
98
- #
99
- # class Project
100
- # has_and_belongs_to_many :developers, :after_add => :evaluate_velocity
101
- #
102
- # def evaluate_velocity(developer)
103
- # ...
104
- # end
105
- # end
106
- #
107
- # It's possible to stack callbacks by passing them as an array. Example:
108
- #
109
- # class Project
110
- # has_and_belongs_to_many :developers, :after_add => [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}]
111
- # end
112
- #
113
- # Possible callbacks are: before_add, after_add, before_remove and after_remove.
114
- #
115
- # Should any of the before_add callbacks throw an exception, the object does not get added to the collection. Same with
116
- # the before_remove callbacks, if an exception is thrown the object doesn't get removed.
117
- #
118
- # === Association extensions
119
- #
120
- # The proxy objects that controls the access to associations can be extended through anonymous modules. This is especially
121
- # beneficial for adding new finders, creators, and other factory-type methods that are only used as part of this association.
122
- # Example:
123
- #
124
- # class Account < BigRecord::Base
125
- # has_many :people do
126
- # def find_or_create_by_name(name)
127
- # first_name, last_name = name.split(" ", 2)
128
- # find_or_create_by_first_name_and_last_name(first_name, last_name)
129
- # end
130
- # end
131
- # end
132
- #
133
- # person = Account.find(:first).people.find_or_create_by_name("David Heinemeier Hansson")
134
- # person.first_name # => "David"
135
- # person.last_name # => "Heinemeier Hansson"
136
- #
137
- # If you need to share the same extensions between many associations, you can use a named extension module. Example:
138
- #
139
- # module FindOrCreateByNameExtension
140
- # def find_or_create_by_name(name)
141
- # first_name, last_name = name.split(" ", 2)
142
- # find_or_create_by_first_name_and_last_name(first_name, last_name)
143
- # end
144
- # end
145
- #
146
- # class Account < BigRecord::Base
147
- # has_many :people, :extend => FindOrCreateByNameExtension
148
- # end
149
- #
150
- # class Company < BigRecord::Base
151
- # has_many :people, :extend => FindOrCreateByNameExtension
152
- # end
153
- #
154
- # If you need to use multiple named extension modules, you can specify an array of modules with the :extend option.
155
- # In the case of name conflicts between methods in the modules, methods in modules later in the array supercede
156
- # those earlier in the array. Example:
157
- #
158
- # class Account < BigRecord::Base
159
- # has_many :people, :extend => [FindOrCreateByNameExtension, FindRecentExtension]
160
- # end
161
- #
162
- # Some extensions can only be made to work with knowledge of the association proxy's internals.
163
- # Extensions can access relevant state using accessors on the association proxy:
164
- #
165
- # * +proxy_owner+ - Returns the object the association is part of.
166
- # * +proxy_reflection+ - Returns the reflection object that describes the association.
167
- # * +proxy_target+ - Returns the associated object for belongs_to and has_one, or the collection of associated objects for has_many and has_and_belongs_to_many.
168
- #
169
- # === Association Join Models
170
- #
171
- # Has Many associations can be configured with the :through option to use an explicit join model to retrieve the data. This
172
- # operates similarly to a <tt>has_and_belongs_to_many</tt> association. The advantage is that you're able to add validations,
173
- # callbacks, and extra attributes on the join model. Consider the following schema:
174
- #
175
- # class Author < BigRecord::Base
176
- # has_many :authorships
177
- # has_many :books, :through => :authorships
178
- # end
179
- #
180
- # class Authorship < BigRecord::Base
181
- # belongs_to :author
182
- # belongs_to :book
183
- # end
184
- #
185
- # @author = Author.find :first
186
- # @author.authorships.collect { |a| a.book } # selects all books that the author's authorships belong to.
187
- # @author.books # selects all books by using the Authorship join model
188
- #
189
- # You can also go through a has_many association on the join model:
190
- #
191
- # class Firm < BigRecord::Base
192
- # has_many :clients
193
- # has_many :invoices, :through => :clients
194
- # end
195
- #
196
- # class Client < BigRecord::Base
197
- # belongs_to :firm
198
- # has_many :invoices
199
- # end
200
- #
201
- # class Invoice < BigRecord::Base
202
- # belongs_to :client
203
- # end
204
- #
205
- # @firm = Firm.find :first
206
- # @firm.clients.collect { |c| c.invoices }.flatten # select all invoices for all clients of the firm
207
- # @firm.invoices # selects all invoices by going through the Client join model.
208
- #
209
- # === Polymorphic Associations
210
- #
211
- # Polymorphic associations on models are not restricted on what types of models they can be associated with. Rather, they
212
- # specify an interface that a has_many association must adhere to.
213
- #
214
- # class Asset < BigRecord::Base
215
- # belongs_to :attachable, :polymorphic => true
216
- # end
217
- #
218
- # class Post < BigRecord::Base
219
- # has_many :assets, :as => :attachable # The <tt>:as</tt> option specifies the polymorphic interface to use.
220
- # end
221
- #
222
- # @asset.attachable = @post
223
- #
224
- # This works by using a type column in addition to a foreign key to specify the associated record. In the Asset example, you'd need
225
- # an attachable_id integer column and an attachable_type string column.
226
- #
227
- # Using polymorphic associations in combination with single table inheritance (STI) is a little tricky. In order
228
- # for the associations to work as expected, ensure that you store the base model for the STI models in the
229
- # type column of the polymorphic association. To continue with the asset example above, suppose there are guest posts
230
- # and member posts that use the posts table for STI. So there will be an additional 'type' column in the posts table.
231
- #
232
- # class Asset < BigRecord::Base
233
- # belongs_to :attachable, :polymorphic => true
234
- #
235
- # def attachable_type=(sType)
236
- # super(sType.to_s.classify.constantize.base_class.to_s)
237
- # end
238
- # end
239
- #
240
- # class Post < BigRecord::Base
241
- # # because we store "Post" in attachable_type now :dependent => :destroy will work
242
- # has_many :assets, :as => :attachable, :dependent => :destroy
243
- # end
244
- #
245
- # class GuestPost < BigRecord::Base
246
- # end
247
- #
248
- # class MemberPost < BigRecord::Base
249
- # end
250
- #
251
- # == Caching
252
- #
253
- # All of the methods are built on a simple caching principle that will keep the result of the last query around unless specifically
254
- # instructed not to. The cache is even shared across methods to make it even cheaper to use the macro-added methods without
255
- # worrying too much about performance at the first go. Example:
256
- #
257
- # project.milestones # fetches milestones from the database
258
- # project.milestones.size # uses the milestone cache
259
- # project.milestones.empty? # uses the milestone cache
260
- # project.milestones(true).size # fetches milestones from the database
261
- # project.milestones # uses the milestone cache
262
- #
263
- # == Eager loading of associations
264
- #
265
- # Eager loading is a way to find objects of a certain class and a number of named associations along with it in a single SQL call. This is
266
- # one of the easiest ways of to prevent the dreaded 1+N problem in which fetching 100 posts that each needs to display their author
267
- # triggers 101 database queries. Through the use of eager loading, the 101 queries can be reduced to 1. Example:
268
- #
269
- # class Post < BigRecord::Base
270
- # belongs_to :author
271
- # has_many :comments
272
- # end
273
- #
274
- # Consider the following loop using the class above:
275
- #
276
- # for post in Post.find(:all)
277
- # puts "Post: " + post.title
278
- # puts "Written by: " + post.author.name
279
- # puts "Last comment on: " + post.comments.first.created_on
280
- # end
281
- #
282
- # To iterate over these one hundred posts, we'll generate 201 database queries. Let's first just optimize it for retrieving the author:
283
- #
284
- # for post in Post.find(:all, :include => :author)
285
- #
286
- # This references the name of the belongs_to association that also used the :author symbol, so the find will now weave in a join something
287
- # like this: LEFT OUTER JOIN authors ON authors.id = posts.author_id. Doing so will cut down the number of queries from 201 to 101.
288
- #
289
- # We can improve upon the situation further by referencing both associations in the finder with:
290
- #
291
- # for post in Post.find(:all, :include => [ :author, :comments ])
292
- #
293
- # That'll add another join along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id. And we'll be down to 1 query.
294
- # But that shouldn't fool you to think that you can pull out huge amounts of data with no performance penalty just because you've reduced
295
- # the number of queries. The database still needs to send all the data to Active Record and it still needs to be processed. So it's no
296
- # catch-all for performance problems, but it's a great way to cut down on the number of queries in a situation as the one described above.
297
- #
298
- # Since the eager loading pulls from multiple tables, you'll have to disambiguate any column references in both conditions and orders. So
299
- # :order => "posts.id DESC" will work while :order => "id DESC" will not. Because eager loading generates the SELECT statement too, the
300
- # :select option is ignored.
301
- #
302
- # You can use eager loading on multiple associations from the same table, but you cannot use those associations in orders and conditions
303
- # as there is currently not any way to disambiguate them. Eager loading will not pull additional attributes on join tables, so "rich
304
- # associations" with has_and_belongs_to_many are not a good fit for eager loading.
305
- #
306
- # When eager loaded, conditions are interpolated in the context of the model class, not the model instance. Conditions are lazily interpolated
307
- # before the actual model exists.
308
- #
309
- # == Table Aliasing
310
- #
311
- # BigRecord uses table aliasing in the case that a table is referenced multiple times in a join. If a table is referenced only once,
312
- # the standard table name is used. The second time, the table is aliased as #{reflection_name}_#{parent_table_name}. Indexes are appended
313
- # for any more successive uses of the table name.
314
- #
315
- # Post.find :all, :include => :comments
316
- # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ...
317
- # Post.find :all, :include => :special_comments # STI
318
- # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... AND comments.type = 'SpecialComment'
319
- # Post.find :all, :include => [:comments, :special_comments] # special_comments is the reflection name, posts is the parent table name
320
- # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... LEFT OUTER JOIN comments special_comments_posts
321
- #
322
- # Acts as tree example:
323
- #
324
- # TreeMixin.find :all, :include => :children
325
- # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
326
- # TreeMixin.find :all, :include => {:children => :parent} # using cascading eager includes
327
- # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
328
- # LEFT OUTER JOIN parents_mixins ...
329
- # TreeMixin.find :all, :include => {:children => {:parent => :children}}
330
- # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
331
- # LEFT OUTER JOIN parents_mixins ...
332
- # LEFT OUTER JOIN mixins childrens_mixins_2
333
- #
334
- # Has and Belongs to Many join tables use the same idea, but add a _join suffix:
335
- #
336
- # Post.find :all, :include => :categories
337
- # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ...
338
- # Post.find :all, :include => {:categories => :posts}
339
- # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ...
340
- # LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories
341
- # Post.find :all, :include => {:categories => {:posts => :categories}}
342
- # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ...
343
- # LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories
344
- # LEFT OUTER JOIN categories_posts categories_posts_join LEFT OUTER JOIN categories categories_posts
345
- #
346
- # If you wish to specify your own custom joins using a :joins option, those table names will take precedence over the eager associations..
347
- #
348
- # Post.find :all, :include => :comments, :joins => "inner join comments ..."
349
- # # => SELECT ... FROM posts LEFT OUTER JOIN comments_posts ON ... INNER JOIN comments ...
350
- # Post.find :all, :include => [:comments, :special_comments], :joins => "inner join comments ..."
351
- # # => SELECT ... FROM posts LEFT OUTER JOIN comments comments_posts ON ...
352
- # LEFT OUTER JOIN comments special_comments_posts ...
353
- # INNER JOIN comments ...
354
- #
355
- # Table aliases are automatically truncated according to the maximum length of table identifiers according to the specific database.
356
- #
357
- # == Modules
358
- #
359
- # By default, associations will look for objects within the current module scope. Consider:
360
- #
361
- # module MyApplication
362
- # module Business
363
- # class Firm < BigRecord::Base
364
- # has_many :clients
365
- # end
366
- #
367
- # class Company < BigRecord::Base; end
368
- # end
369
- # end
370
- #
371
- # When Firm#clients is called, it'll in turn call <tt>MyApplication::Business::Company.find(firm.id)</tt>. If you want to associate
372
- # with a class in another module scope this can be done by specifying the complete class name, such as:
373
- #
374
- # module MyApplication
375
- # module Business
376
- # class Firm < BigRecord::Base; end
377
- # end
378
- #
379
- # module Billing
380
- # class Account < BigRecord::Base
381
- # belongs_to :firm, :class_name => "MyApplication::Business::Firm"
382
- # end
383
- # end
384
- # end
385
- #
386
- # == Type safety with BigRecord::AssociationTypeMismatch
387
- #
388
- # If you attempt to assign an object to an association that doesn't match the inferred or specified <tt>:class_name</tt>, you'll
389
- # get a BigRecord::AssociationTypeMismatch.
390
- #
391
- # == Options
392
- #
393
- # All of the association macros can be specialized through options which makes more complex cases than the simple and guessable ones
394
- # possible.
395
16
  module ClassMethods
396
- # Adds the following methods for retrieval and query of collections of associated objects.
397
- # +collection+ is replaced with the symbol passed as the first argument, so
398
- # <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.
399
- # * <tt>collection(force_reload = false)</tt> - returns an array of all the associated objects.
400
- # An empty array is returned if none are found.
401
- # * <tt>collection<<(object, ...)</tt> - adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
402
- # * <tt>collection.delete(object, ...)</tt> - removes one or more objects from the collection by setting their foreign keys to NULL.
403
- # This will also destroy the objects if they're declared as belongs_to and dependent on this model.
404
- # * <tt>collection=objects</tt> - replaces the collections content by deleting and adding objects as appropriate.
405
- # * <tt>collection_singular_ids</tt> - returns an array of the associated objects ids
406
- # * <tt>collection_singular_ids=ids</tt> - replace the collection by the objects identified by the primary keys in +ids+
407
- # * <tt>collection.clear</tt> - removes every object from the collection. This destroys the associated objects if they
408
- # are <tt>:dependent</tt>, deletes them directly from the database if they are <tt>:dependent => :delete_all</tt>,
409
- # and sets their foreign keys to NULL otherwise.
410
- # * <tt>collection.empty?</tt> - returns true if there are no associated objects.
411
- # * <tt>collection.size</tt> - returns the number of associated objects.
412
- # * <tt>collection.find</tt> - finds an associated object according to the same rules as Base.find.
413
- # * <tt>collection.build(attributes = {})</tt> - returns a new object of the collection type that has been instantiated
414
- # with +attributes+ and linked to this object through a foreign key but has not yet been saved. *Note:* This only works if an
415
- # associated object already exists, not if it's nil!
416
- # * <tt>collection.create(attributes = {})</tt> - returns a new object of the collection type that has been instantiated
417
- # with +attributes+ and linked to this object through a foreign key and that has already been saved (if it passed the validation).
418
- # *Note:* This only works if an associated object already exists, not if it's nil!
419
- #
420
- # Example: A Firm class declares <tt>has_many :clients</tt>, which will add:
421
- # * <tt>Firm#clients</tt> (similar to <tt>Clients.find :all, :conditions => "firm_id = #{id}"</tt>)
422
- # * <tt>Firm#clients<<</tt>
423
- # * <tt>Firm#clients.delete</tt>
424
- # * <tt>Firm#clients=</tt>
425
- # * <tt>Firm#client_ids</tt>
426
- # * <tt>Firm#client_ids=</tt>
427
- # * <tt>Firm#clients.clear</tt>
428
- # * <tt>Firm#clients.empty?</tt> (similar to <tt>firm.clients.size == 0</tt>)
429
- # * <tt>Firm#clients.size</tt> (similar to <tt>Client.count "firm_id = #{id}"</tt>)
430
- # * <tt>Firm#clients.find</tt> (similar to <tt>Client.find(id, :conditions => "firm_id = #{id}")</tt>)
431
- # * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>)
432
- # * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>)
433
- # The declaration can also include an options hash to specialize the behavior of the association.
434
- #
435
- # Options are:
436
- # * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred
437
- # from the association name. So <tt>has_many :products</tt> will by default be linked to the +Product+ class, but
438
- # if the real class name is +SpecialProduct+, you'll have to specify it with this option.
439
- # * <tt>:conditions</tt> - specify the conditions that the associated objects must meet in order to be included as a "WHERE"
440
- # sql fragment, such as "price > 5 AND name LIKE 'B%'".
441
- # * <tt>:order</tt> - specify the order in which the associated objects are returned as a "ORDER BY" sql fragment,
442
- # such as "last_name, first_name DESC"
443
- # * <tt>:group</tt> - specify the attribute by which the associated objects are returned as a "GROUP BY" sql fragment,
444
- # such as "category"
445
- # * <tt>:foreign_key</tt> - specify the foreign key used for the association. By default this is guessed to be the name
446
- # of this class in lower-case and "_id" suffixed. So a +Person+ class that makes a has_many association will use "person_id"
447
- # as the default foreign_key.
448
- # * <tt>:dependent</tt> - if set to :destroy all the associated objects are destroyed
449
- # alongside this object by calling their destroy method. If set to :delete_all all associated
450
- # objects are deleted *without* calling their destroy method. If set to :nullify all associated
451
- # objects' foreign keys are set to NULL *without* calling their save callbacks.
452
- # NOTE: :dependent => true is deprecated and has been replaced with :dependent => :destroy.
453
- # May not be set if :exclusively_dependent is also set.
454
- # * <tt>:exclusively_dependent</tt> - Deprecated; equivalent to :dependent => :delete_all. If set to true all
455
- # the associated object are deleted in one SQL statement without having their
456
- # before_destroy callback run. This should only be used on associations that depend solely on this class and don't need to do any
457
- # clean-up in before_destroy. The upside is that it's much faster, especially if there's a counter_cache involved.
458
- # May not be set if :dependent is also set.
459
- # * <tt>:finder_sql</tt> - specify a complete SQL statement to fetch the association. This is a good way to go for complex
460
- # associations that depend on multiple tables. Note: When this option is used, +find_in_collection+ is _not_ added.
461
- # * <tt>:counter_sql</tt> - specify a complete SQL statement to fetch the size of the association. If +:finder_sql+ is
462
- # specified but +:counter_sql+, +:counter_sql+ will be generated by replacing SELECT ... FROM with SELECT COUNT(*) FROM.
463
- # * <tt>:extend</tt> - specify a named module for extending the proxy, see "Association extensions".
464
- # * <tt>:include</tt> - specify second-order associations that should be eager loaded when the collection is loaded.
465
- # * <tt>:group</tt>: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
466
- # * <tt>:limit</tt>: An integer determining the limit on the number of rows that should be returned.
467
- # * <tt>:offset</tt>: An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows.
468
- # * <tt>:select</tt>: By default, this is * as in SELECT * FROM, but can be changed if you for example want to do a join, but not
469
- # include the joined columns.
470
- # * <tt>:as</tt>: Specifies a polymorphic interface (See #belongs_to).
471
- # * <tt>:through</tt>: Specifies a Join Model to perform the query through. Options for <tt>:class_name</tt> and <tt>:foreign_key</tt>
472
- # are ignored, as the association uses the source reflection. You can only use a <tt>:through</tt> query through a <tt>belongs_to</tt>
473
- # or <tt>has_many</tt> association.
474
- # * <tt>:source</tt>: Specifies the source association name used by <tt>has_many :through</tt> queries. Only use it if the name cannot be
475
- # inferred from the association. <tt>has_many :subscribers, :through => :subscriptions</tt> will look for either +:subscribers+ or
476
- # +:subscriber+ on +Subscription+, unless a +:source+ is given.
477
- # * <tt>:source_type</tt>: Specifies type of the source association used by <tt>has_many :through</tt> queries where the source association
478
- # is a polymorphic belongs_to.
479
- # * <tt>:uniq</tt> - if set to true, duplicates will be omitted from the collection. Useful in conjunction with :through.
480
- #
481
- # Option examples:
482
- # has_many :comments, :order => "posted_on"
483
- # has_many :comments, :include => :author
484
- # has_many :people, :class_name => "Person", :conditions => "deleted = 0", :order => "name"
485
- # has_many :tracks, :order => "position", :dependent => :destroy
486
- # has_many :comments, :dependent => :nullify
487
- # has_many :tags, :as => :taggable
488
- # has_many :subscribers, :through => :subscriptions, :source => :user
489
- # has_many :subscribers, :class_name => "Person", :finder_sql =>
490
- # 'SELECT DISTINCT people.* ' +
491
- # 'FROM people p, post_subscriptions ps ' +
492
- # 'WHERE ps.post_id = #{id} AND ps.person_id = p.id ' +
493
- # 'ORDER BY p.first_name'
17
+
494
18
  def has_many_big_records(association_id, options = {}, &extension)
495
19
  reflection = create_has_many_big_records_reflection(association_id, options, &extension)
496
20
 
@@ -502,57 +26,11 @@ module BigRecord
502
26
  add_association_callbacks(reflection.name, reflection.options)
503
27
  collection_accessor_methods(reflection, HasManyAssociation)
504
28
  end
505
-
506
- # add_deprecated_api_for_has_many(reflection.name)
507
29
  end
508
30
 
509
31
  alias_method :has_many_bigrecords, :has_many_big_records
510
32
 
511
- # Adds the following methods for retrieval and query of a single associated object.
512
- # +association+ is replaced with the symbol passed as the first argument, so
513
- # <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.
514
- # * <tt>association(force_reload = false)</tt> - returns the associated object. Nil is returned if none is found.
515
- # * <tt>association=(associate)</tt> - assigns the associate object, extracts the primary key, sets it as the foreign key,
516
- # and saves the associate object.
517
- # * <tt>association.nil?</tt> - returns true if there is no associated object.
518
- # * <tt>build_association(attributes = {})</tt> - returns a new object of the associated type that has been instantiated
519
- # with +attributes+ and linked to this object through a foreign key but has not yet been saved. Note: This ONLY works if
520
- # an association already exists. It will NOT work if the association is nil.
521
- # * <tt>create_association(attributes = {})</tt> - returns a new object of the associated type that has been instantiated
522
- # with +attributes+ and linked to this object through a foreign key and that has already been saved (if it passed the validation).
523
- #
524
- # Example: An Account class declares <tt>has_one :beneficiary</tt>, which will add:
525
- # * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.find(:first, :conditions => "account_id = #{id}")</tt>)
526
- # * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>)
527
- # * <tt>Account#beneficiary.nil?</tt>
528
- # * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>)
529
- # * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>)
530
- #
531
- # The declaration can also include an options hash to specialize the behavior of the association.
532
- #
533
- # Options are:
534
- # * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred
535
- # from the association name. So <tt>has_one :manager</tt> will by default be linked to the +Manager+ class, but
536
- # if the real class name is +Person+, you'll have to specify it with this option.
537
- # * <tt>:conditions</tt> - specify the conditions that the associated object must meet in order to be included as a "WHERE"
538
- # sql fragment, such as "rank = 5".
539
- # * <tt>:order</tt> - specify the order from which the associated object will be picked at the top. Specified as
540
- # an "ORDER BY" sql fragment, such as "last_name, first_name DESC"
541
- # * <tt>:dependent</tt> - if set to :destroy (or true) the associated object is destroyed when this object is. If set to
542
- # :delete the associated object is deleted *without* calling its destroy method. If set to :nullify the associated
543
- # object's foreign key is set to NULL. Also, association is assigned.
544
- # * <tt>:foreign_key</tt> - specify the foreign key used for the association. By default this is guessed to be the name
545
- # of this class in lower-case and "_id" suffixed. So a +Person+ class that makes a has_one association will use "person_id"
546
- # as the default foreign_key.
547
- # * <tt>:include</tt> - specify second-order associations that should be eager loaded when this object is loaded.
548
- # * <tt>:as</tt>: Specifies a polymorphic interface (See #belongs_to).
549
- #
550
- # Option examples:
551
- # has_one :credit_card, :dependent => :destroy # destroys the associated credit card
552
- # has_one :credit_card, :dependent => :nullify # updates the associated records foriegn key value to null rather than destroying it
553
- # has_one :last_comment, :class_name => "Comment", :order => "posted_on"
554
- # has_one :project_manager, :class_name => "Person", :conditions => "role = 'project_manager'"
555
- # has_one :attachment, :as => :attachable
33
+
556
34
  def has_one_big_record(association_id, options = {})
557
35
  reflection = create_has_one_big_record_reflection(association_id, options)
558
36
 
@@ -571,59 +49,11 @@ module BigRecord
571
49
  association_constructor_method_big_record(:create, reflection, HasOneAssociation)
572
50
 
573
51
  configure_dependency_for_has_one(reflection)
574
-
575
- # deprecated api
576
- # deprecated_has_association_method(reflection.name)
577
- # deprecated_association_comparison_method(reflection.name, reflection.class_name)
578
52
  end
579
53
 
580
54
  alias_method :has_one_bigrecord, :has_one_big_record
581
55
 
582
- # Adds the following methods for retrieval and query for a single associated object that this object holds an id to.
583
- # +association+ is replaced with the symbol passed as the first argument, so
584
- # <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.
585
- # * <tt>association(force_reload = false)</tt> - returns the associated object. Nil is returned if none is found.
586
- # * <tt>association=(associate)</tt> - assigns the associate object, extracts the primary key, and sets it as the foreign key.
587
- # * <tt>association.nil?</tt> - returns true if there is no associated object.
588
- # * <tt>build_association(attributes = {})</tt> - returns a new object of the associated type that has been instantiated
589
- # with +attributes+ and linked to this object through a foreign key but has not yet been saved.
590
- # * <tt>create_association(attributes = {})</tt> - returns a new object of the associated type that has been instantiated
591
- # with +attributes+ and linked to this object through a foreign key and that has already been saved (if it passed the validation).
592
- #
593
- # Example: A Post class declares <tt>belongs_to :author</tt>, which will add:
594
- # * <tt>Post#author</tt> (similar to <tt>Author.find(author_id)</tt>)
595
- # * <tt>Post#author=(author)</tt> (similar to <tt>post.author_id = author.id</tt>)
596
- # * <tt>Post#author?</tt> (similar to <tt>post.author == some_author</tt>)
597
- # * <tt>Post#author.nil?</tt>
598
- # * <tt>Post#build_author</tt> (similar to <tt>post.author = Author.new</tt>)
599
- # * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>)
600
- # The declaration can also include an options hash to specialize the behavior of the association.
601
- #
602
- # Options are:
603
- # * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred
604
- # from the association name. So <tt>has_one :author</tt> will by default be linked to the +Author+ class, but
605
- # if the real class name is +Person+, you'll have to specify it with this option.
606
- # * <tt>:conditions</tt> - specify the conditions that the associated object must meet in order to be included as a "WHERE"
607
- # sql fragment, such as "authorized = 1".
608
- # * <tt>:order</tt> - specify the order from which the associated object will be picked at the top. Specified as
609
- # an "ORDER BY" sql fragment, such as "last_name, first_name DESC"
610
- # * <tt>:foreign_key</tt> - specify the foreign key used for the association. By default this is guessed to be the name
611
- # of the associated class in lower-case and "_id" suffixed. So a +Person+ class that makes a belongs_to association to a
612
- # +Boss+ class will use "boss_id" as the default foreign_key.
613
- # * <tt>:counter_cache</tt> - caches the number of belonging objects on the associate class through use of increment_counter
614
- # and decrement_counter. The counter cache is incremented when an object of this class is created and decremented when it's
615
- # destroyed. This requires that a column named "#{table_name}_count" (such as comments_count for a belonging Comment class)
616
- # is used on the associate class (such as a Post class). You can also specify a custom counter cache column by given that
617
- # name instead of a true/false value to this option (e.g., <tt>:counter_cache => :my_custom_counter</tt>.)
618
- # * <tt>:include</tt> - specify second-order associations that should be eager loaded when this object is loaded.
619
- # * <tt>:polymorphic</tt> - specify this association is a polymorphic association by passing true.
620
- #
621
- # Option examples:
622
- # belongs_to :firm, :foreign_key => "client_of"
623
- # belongs_to :author, :class_name => "Person", :foreign_key => "author_id"
624
- # belongs_to :valid_coupon, :class_name => "Coupon", :foreign_key => "coupon_id",
625
- # :conditions => 'discounts > #{payments_count}'
626
- # belongs_to :attachable, :polymorphic => true
56
+
627
57
  def belongs_to_big_record(association_id, options = {})
628
58
  if options.include?(:class_name) && !options.include?(:foreign_key)
629
59
  ::ActiveSupport::Deprecation.warn(
@@ -670,10 +100,6 @@ module BigRecord
670
100
  end
671
101
  EOF
672
102
  end
673
-
674
- # deprecated api
675
- # deprecated_has_association_method(reflection.name)
676
- # deprecated_association_comparison_method(reflection.name, reflection.class_name)
677
103
  end
678
104
 
679
105
  if options[:counter_cache]
@@ -695,6 +121,7 @@ module BigRecord
695
121
 
696
122
  alias_method :belongs_to_bigrecord, :belongs_to_big_record
697
123
 
124
+
698
125
  def belongs_to_many(association_id, options = {})
699
126
  if options.include?(:class_name) && !options.include?(:foreign_key)
700
127
  ::ActiveSupport::Deprecation.warn(
@@ -725,99 +152,7 @@ module BigRecord
725
152
 
726
153
  end
727
154
 
728
- # Associates two classes via an intermediate join table. Unless the join table is explicitly specified as
729
- # an option, it is guessed using the lexical order of the class names. So a join between Developer and Project
730
- # will give the default join table name of "developers_projects" because "D" outranks "P". Note that this precedence
731
- # is calculated using the <tt><</tt> operator for <tt>String</tt>. This means that if the strings are of different lengths,
732
- # and the strings are equal when compared up to the shortest length, then the longer string is considered of higher
733
- # lexical precedence than the shorter one. For example, one would expect the tables <tt>paper_boxes</tt> and <tt>papers</tt>
734
- # to generate a join table name of <tt>papers_paper_boxes</tt> because of the length of the name <tt>paper_boxes</tt>,
735
- # but it in fact generates a join table name of <tt>paper_boxes_papers</tt>. Be aware of this caveat, and use the
736
- # custom <tt>join_table</tt> option if you need to.
737
- #
738
- # Deprecated: Any additional fields added to the join table will be placed as attributes when pulling records out through
739
- # has_and_belongs_to_many associations. Records returned from join tables with additional attributes will be marked as
740
- # ReadOnly (because we can't save changes to the additional attrbutes). It's strongly recommended that you upgrade any
741
- # associations with attributes to a real join model (see introduction).
742
- #
743
- # Adds the following methods for retrieval and query.
744
- # +collection+ is replaced with the symbol passed as the first argument, so
745
- # <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.
746
- # * <tt>collection(force_reload = false)</tt> - returns an array of all the associated objects.
747
- # An empty array is returned if none is found.
748
- # * <tt>collection<<(object, ...)</tt> - adds one or more objects to the collection by creating associations in the join table
749
- # (collection.push and collection.concat are aliases to this method).
750
- # * <tt>collection.push_with_attributes(object, join_attributes)</tt> - adds one to the collection by creating an association in the join table that
751
- # also holds the attributes from <tt>join_attributes</tt> (should be a hash with the column names as keys). This can be used to have additional
752
- # attributes on the join, which will be injected into the associated objects when they are retrieved through the collection.
753
- # (collection.concat_with_attributes is an alias to this method). This method is now deprecated.
754
- # * <tt>collection.delete(object, ...)</tt> - removes one or more objects from the collection by removing their associations from the join table.
755
- # This does not destroy the objects.
756
- # * <tt>collection=objects</tt> - replaces the collections content by deleting and adding objects as appropriate.
757
- # * <tt>collection_singular_ids</tt> - returns an array of the associated objects ids
758
- # * <tt>collection_singular_ids=ids</tt> - replace the collection by the objects identified by the primary keys in +ids+
759
- # * <tt>collection.clear</tt> - removes every object from the collection. This does not destroy the objects.
760
- # * <tt>collection.empty?</tt> - returns true if there are no associated objects.
761
- # * <tt>collection.size</tt> - returns the number of associated objects.
762
- # * <tt>collection.find(id)</tt> - finds an associated object responding to the +id+ and that
763
- # meets the condition that it has to be associated with this object.
764
- # * <tt>collection.build(attributes = {})</tt> - returns a new object of the collection type that has been instantiated
765
- # with +attributes+ and linked to this object through the join table but has not yet been saved.
766
- # * <tt>collection.create(attributes = {})</tt> - returns a new object of the collection type that has been instantiated
767
- # with +attributes+ and linked to this object through the join table and that has already been saved (if it passed the validation).
768
- #
769
- # Example: An Developer class declares <tt>has_and_belongs_to_many :projects</tt>, which will add:
770
- # * <tt>Developer#projects</tt>
771
- # * <tt>Developer#projects<<</tt>
772
- # * <tt>Developer#projects.delete</tt>
773
- # * <tt>Developer#projects=</tt>
774
- # * <tt>Developer#project_ids</tt>
775
- # * <tt>Developer#project_ids=</tt>
776
- # * <tt>Developer#projects.clear</tt>
777
- # * <tt>Developer#projects.empty?</tt>
778
- # * <tt>Developer#projects.size</tt>
779
- # * <tt>Developer#projects.find(id)</tt>
780
- # * <tt>Developer#projects.build</tt> (similar to <tt>Project.new("project_id" => id)</tt>)
781
- # * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("project_id" => id); c.save; c</tt>)
782
- # The declaration may include an options hash to specialize the behavior of the association.
783
- #
784
- # Options are:
785
- # * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred
786
- # from the association name. So <tt>has_and_belongs_to_many :projects</tt> will by default be linked to the
787
- # +Project+ class, but if the real class name is +SuperProject+, you'll have to specify it with this option.
788
- # * <tt>:join_table</tt> - specify the name of the join table if the default based on lexical order isn't what you want.
789
- # WARNING: If you're overwriting the table name of either class, the table_name method MUST be declared underneath any
790
- # has_and_belongs_to_many declaration in order to work.
791
- # * <tt>:foreign_key</tt> - specify the foreign key used for the association. By default this is guessed to be the name
792
- # of this class in lower-case and "_id" suffixed. So a +Person+ class that makes a has_and_belongs_to_many association
793
- # will use "person_id" as the default foreign_key.
794
- # * <tt>:association_foreign_key</tt> - specify the association foreign key used for the association. By default this is
795
- # guessed to be the name of the associated class in lower-case and "_id" suffixed. So if the associated class is +Project+,
796
- # the has_and_belongs_to_many association will use "project_id" as the default association foreign_key.
797
- # * <tt>:conditions</tt> - specify the conditions that the associated object must meet in order to be included as a "WHERE"
798
- # sql fragment, such as "authorized = 1".
799
- # * <tt>:order</tt> - specify the order in which the associated objects are returned as a "ORDER BY" sql fragment, such as "last_name, first_name DESC"
800
- # * <tt>:uniq</tt> - if set to true, duplicate associated objects will be ignored by accessors and query methods
801
- # * <tt>:finder_sql</tt> - overwrite the default generated SQL used to fetch the association with a manual one
802
- # * <tt>:delete_sql</tt> - overwrite the default generated SQL used to remove links between the associated
803
- # classes with a manual one
804
- # * <tt>:insert_sql</tt> - overwrite the default generated SQL used to add links between the associated classes
805
- # with a manual one
806
- # * <tt>:extend</tt> - anonymous module for extending the proxy, see "Association extensions".
807
- # * <tt>:include</tt> - specify second-order associations that should be eager loaded when the collection is loaded.
808
- # * <tt>:group</tt>: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
809
- # * <tt>:limit</tt>: An integer determining the limit on the number of rows that should be returned.
810
- # * <tt>:offset</tt>: An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows.
811
- # * <tt>:select</tt>: By default, this is * as in SELECT * FROM, but can be changed if you for example want to do a join, but not
812
- # include the joined columns.
813
- #
814
- # Option examples:
815
- # has_and_belongs_to_many :projects
816
- # has_and_belongs_to_many :projects, :include => [ :milestones, :manager ]
817
- # has_and_belongs_to_many :nations, :class_name => "Country"
818
- # has_and_belongs_to_many :categories, :join_table => "prods_cats"
819
- # has_and_belongs_to_many :active_projects, :join_table => 'developers_projects', :delete_sql =>
820
- # 'DELETE FROM developers_projects WHERE active=1 AND developer_id = #{id} AND project_id = #{record.id}'
155
+
821
156
  def has_and_belongs_to_many_big_records(association_id, options = {}, &extension)
822
157
  reflection = create_has_and_belongs_to_many_big_records_reflection(association_id, options, &extension)
823
158
 
@@ -835,146 +170,138 @@ module BigRecord
835
170
  end_eval
836
171
 
837
172
  add_association_callbacks(reflection.name, options)
838
-
839
- # deprecated api
840
- # deprecated_collection_count_method(reflection.name)
841
- # deprecated_add_association_relation(reflection.name)
842
- # deprecated_remove_association_relation(reflection.name)
843
- # deprecated_has_collection_method(reflection.name)
844
173
  end
845
174
 
846
175
  alias_method :has_and_belongs_to_many_bigrecords, :has_and_belongs_to_many_big_records
847
176
 
848
- private
849
- def association_accessor_methods_big_record(reflection, association_proxy_class)
850
- define_method(reflection.name) do |*params|
851
- force_reload = params.first unless params.empty?
852
- association = instance_variable_get("@#{reflection.name}")
853
-
854
- if association.nil? || force_reload
855
- association = association_proxy_class.new(self, reflection)
856
- retval = association.reload
857
- if retval.nil? and association_proxy_class == BelongsToAssociation
858
- instance_variable_set("@#{reflection.name}", nil)
859
- return nil
860
- end
861
- instance_variable_set("@#{reflection.name}", association)
862
- end
863
-
864
- association.target.nil? ? nil : association
865
- end
866
177
 
867
- define_method("#{reflection.name}=") do |new_value|
868
- association = instance_variable_get("@#{reflection.name}")
869
- if association.nil?
870
- association = association_proxy_class.new(self, reflection)
871
- end
178
+ private
872
179
 
873
- association.replace(new_value)
180
+ def association_accessor_methods_big_record(reflection, association_proxy_class)
181
+ define_method(reflection.name) do |*params|
182
+ force_reload = params.first unless params.empty?
183
+ association = instance_variable_get("@#{reflection.name}")
874
184
 
875
- unless new_value.nil?
876
- instance_variable_set("@#{reflection.name}", association)
877
- else
185
+ if association.nil? || force_reload
186
+ association = association_proxy_class.new(self, reflection)
187
+ retval = association.reload
188
+ if retval.nil? and association_proxy_class == BelongsToAssociation
878
189
  instance_variable_set("@#{reflection.name}", nil)
879
190
  return nil
880
191
  end
881
-
882
- association
192
+ instance_variable_set("@#{reflection.name}", association)
883
193
  end
884
194
 
885
- define_method("set_#{reflection.name}_target") do |target|
886
- return if target.nil? and association_proxy_class == BelongsToAssociation
195
+ association.target.nil? ? nil : association
196
+ end
197
+
198
+ define_method("#{reflection.name}=") do |new_value|
199
+ association = instance_variable_get("@#{reflection.name}")
200
+ if association.nil?
887
201
  association = association_proxy_class.new(self, reflection)
888
- association.target = target
202
+ end
203
+
204
+ association.replace(new_value)
205
+
206
+ unless new_value.nil?
889
207
  instance_variable_set("@#{reflection.name}", association)
208
+ else
209
+ instance_variable_set("@#{reflection.name}", nil)
210
+ return nil
890
211
  end
212
+
213
+ association
891
214
  end
892
215
 
893
- def association_constructor_method_big_record(constructor, reflection, association_proxy_class)
894
- define_method("#{constructor}_#{reflection.name}") do |*params|
895
- attributees = params.first unless params.empty?
896
- replace_existing = params[1].nil? ? true : params[1]
897
- association = instance_variable_get("@#{reflection.name}")
216
+ define_method("set_#{reflection.name}_target") do |target|
217
+ return if target.nil? and association_proxy_class == BelongsToAssociation
218
+ association = association_proxy_class.new(self, reflection)
219
+ association.target = target
220
+ instance_variable_set("@#{reflection.name}", association)
221
+ end
222
+ end
898
223
 
899
- if association.nil?
900
- association = association_proxy_class.new(self, reflection)
901
- instance_variable_set("@#{reflection.name}", association)
902
- end
224
+ def association_constructor_method_big_record(constructor, reflection, association_proxy_class)
225
+ define_method("#{constructor}_#{reflection.name}") do |*params|
226
+ attributees = params.first unless params.empty?
227
+ replace_existing = params[1].nil? ? true : params[1]
228
+ association = instance_variable_get("@#{reflection.name}")
903
229
 
904
- if association_proxy_class == HasOneAssociation
905
- association.send(constructor, attributees, replace_existing)
906
- else
907
- association.send(constructor, attributees)
908
- end
230
+ if association.nil?
231
+ association = association_proxy_class.new(self, reflection)
232
+ instance_variable_set("@#{reflection.name}", association)
909
233
  end
910
- end
911
234
 
912
- def create_has_many_big_records_reflection(association_id, options, &extension)
913
- options.assert_valid_keys(
914
- :class_name, :table_name, :foreign_key,
915
- :exclusively_dependent, :dependent,
916
- :select, :conditions, :include, :order, :group, :limit, :offset,
917
- :as, :through, :source, :source_type,
918
- :uniq,
919
- :finder_sql, :counter_sql,
920
- :before_add, :after_add, :before_remove, :after_remove,
921
- :extend
922
- )
235
+ if association_proxy_class == HasOneAssociation
236
+ association.send(constructor, attributees, replace_existing)
237
+ else
238
+ association.send(constructor, attributees)
239
+ end
240
+ end
241
+ end
923
242
 
924
- options[:extend] = create_extension_module(association_id, extension) if block_given?
243
+ def create_has_many_big_records_reflection(association_id, options, &extension)
244
+ options.assert_valid_keys(
245
+ :class_name, :table_name, :foreign_key, :exclusively_dependent, :dependent,
246
+ :select, :conditions, :include, :order, :group, :limit, :offset, :as,
247
+ :through, :source, :source_type, :uniq, :finder_sql, :counter_sql,
248
+ :before_add, :after_add, :before_remove, :after_remove, :extend
249
+ )
925
250
 
926
- create_reflection_big_record(:has_many_big_records, association_id, options, self)
927
- end
251
+ options[:extend] = create_extension_module(association_id, extension) if block_given?
928
252
 
929
- def create_has_one_big_record_reflection(association_id, options)
930
- options.assert_valid_keys(
931
- :class_name, :foreign_key, :remote, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as
932
- )
253
+ create_reflection_big_record(:has_many_big_records, association_id, options, self)
254
+ end
933
255
 
934
- create_reflection_big_record(:has_one_big_record, association_id, options, self)
935
- end
256
+ def create_has_one_big_record_reflection(association_id, options)
257
+ options.assert_valid_keys(
258
+ :class_name, :foreign_key, :remote, :conditions, :order, :include,
259
+ :dependent, :counter_cache, :extend, :as
260
+ )
936
261
 
937
- def create_belongs_to_big_record_reflection(association_id, options)
938
- options.assert_valid_keys(
939
- :class_name, :foreign_key, :foreign_type, :remote, :conditions, :order, :include, :dependent,
940
- :counter_cache, :extend, :polymorphic
941
- )
262
+ create_reflection_big_record(:has_one_big_record, association_id, options, self)
263
+ end
942
264
 
943
- reflection = create_reflection_big_record(:belongs_to_big_record, association_id, options, self)
265
+ def create_belongs_to_big_record_reflection(association_id, options)
266
+ options.assert_valid_keys(
267
+ :class_name, :foreign_key, :foreign_type, :remote, :conditions, :order,
268
+ :include, :dependent, :counter_cache, :extend, :polymorphic
269
+ )
944
270
 
945
- if options[:polymorphic]
946
- reflection.options[:foreign_type] ||= reflection.class_name.underscore + "_type"
947
- end
271
+ reflection = create_reflection_big_record(:belongs_to_big_record, association_id, options, self)
948
272
 
949
- reflection
273
+ if options[:polymorphic]
274
+ reflection.options[:foreign_type] ||= reflection.class_name.underscore + "_type"
950
275
  end
951
276
 
952
- def create_belongs_to_many_reflection(association_id, options)
953
- options.assert_valid_keys(
954
- :class_name, :foreign_key, :foreign_type, :remote, :conditions, :order, :include, :dependent, :extend, :cache
955
- )
277
+ reflection
278
+ end
956
279
 
957
- create_reflection_big_record(:belongs_to_many, association_id, options, self)
958
- end
280
+ def create_belongs_to_many_reflection(association_id, options)
281
+ options.assert_valid_keys(
282
+ :class_name, :foreign_key, :foreign_type, :remote, :conditions, :order,
283
+ :include, :dependent, :extend, :cache
284
+ )
959
285
 
960
- def create_has_and_belongs_to_many_big_records_reflection(association_id, options, &extension)
961
- options.assert_valid_keys(
962
- :class_name, :table_name, :join_table, :foreign_key, :association_foreign_key,
963
- :select, :conditions, :include, :order, :group, :limit, :offset,
964
- :uniq,
965
- :finder_sql, :delete_sql, :insert_sql,
966
- :before_add, :after_add, :before_remove, :after_remove,
967
- :extend
968
- )
286
+ create_reflection_big_record(:belongs_to_many, association_id, options, self)
287
+ end
969
288
 
970
- options[:extend] = create_extension_module(association_id, extension) if block_given?
289
+ def create_has_and_belongs_to_many_big_records_reflection(association_id, options, &extension)
290
+ options.assert_valid_keys(
291
+ :class_name, :table_name, :join_table, :foreign_key, :association_foreign_key,
292
+ :select, :conditions, :include, :order, :group, :limit, :offset, :uniq,
293
+ :finder_sql, :delete_sql, :insert_sql, :before_add, :after_add, :before_remove,
294
+ :after_remove, :extend
295
+ )
971
296
 
972
- reflection = create_reflection_big_record(:has_and_belongs_to_many_big_records, association_id, options, self)
297
+ options[:extend] = create_extension_module(association_id, extension) if block_given?
973
298
 
974
- reflection.options[:join_table] ||= join_table_name(undecorated_table_name(self.to_s), undecorated_table_name(reflection.class_name))
299
+ reflection = create_reflection_big_record(:has_and_belongs_to_many_big_records, association_id, options, self)
975
300
 
976
- reflection
977
- end
301
+ reflection.options[:join_table] ||= join_table_name(undecorated_table_name(self.to_s), undecorated_table_name(reflection.class_name))
302
+
303
+ reflection
304
+ end
978
305
  end
979
306
  end
980
307
  end