#190 ✓resolved
Daniel Parker

on-the-fly associations OR creating custom association accessor/setter methods

Reported by Daniel Parker | March 24th, 2008 @ 02:19 PM

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

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

People watching this ticket

Attachments

Pages