on-the-fly associations OR creating custom association accessor/setter methods
Reported by Daniel Parker | March 24th, 2008 @ 02:10 PM | in 1.x
Associations are always set statically and associated with the model class. This is not always the way the developer would like it to work. Many times I find myself wishing I could create accessor methods that would access a subset of an association.
Currently there are a couple ways to do this: 1) Create another association with some more finder options, or 2) Create an accessor method to grab the whole set but filter out the ones I don't want. Neither of those are satisfactory -- the first because it's not really a separate association, it's the same association with a more precise scope; the second because it grabs unnecessary objects from the database.
Example: Person model.. I need a phone_numbers association, but I need to be able to access cell numbers, work numbers, home numbers or fax numbers, separately. In reality, there may be more types, and I need to be able to grab whichever type with the option :context => 'cell', etc. A syntax such as Person.phone_numbers.find(:context => 'cell') would be satisfactory, but that method must return an association_collection, with the finder options all ready to apply to new objects I might build or << into that collection.
I propose separating the association definitions from the accessor/setter methods, and opening up the association set to be a little more publicly usable. Attached is a quick working "plugin" -- just require it after DataMapper is loaded, and the following code should work:
class Email < DataMapper::Base
property :person_id, :integer
property :context, :string
end
class Person < DataMapper::Base
def phone_numbers
@phone_numbers || begin
@phone_numbers = associated_records(:class => :PhoneNumber, :foreign_key => :person_id)
def @phone_numbers.[](k)
@phone_numbers_by_context ||= {}
@phone_numbers_by_context[k] ||= @items ? @items.reject {|e| e.context != k} : find(:context=>k)
end
@phone_numbers
end
end
end
p = Person.first
p.phone_numbers['cell'] # does a sql request for just the :context => 'cell' records, saves them,
# but not into the whole association set.
p.phone_numbers['home'] # does another sql request
p.phone_numbers # sql request for all associated records
p.phone_numbers['work'] # since all records are loaded, just filters them in ruby.
I'm not hoping my code is used, I'm just hoping to get my case across -- I believe it'd allow for much easier use of associations.
Comments and changes to this ticket
-
Dan Kubb April 15th, 2008 @ 03:36 AM
- → Milestone changed from to 0.9.0
-
Sam Smoot April 27th, 2008 @ 10:49 PM
- → State changed from new to open
- → Assigned user changed from to David Leal
I think I get the point... this is what we're going for basically with the finders returning the Collection class directly. So I believe this is basically a done deal. Just the same, we'll make sure and spec the use cases before marking this resolved.
-
Sam Smoot June 2nd, 2008 @ 04:56 PM
- → Milestone changed from 0.9.0 to 1.x
Please Login or create a free account to add a new comment.
You can update this ticket by sending an email to from your email client. (help)
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
