Overwriting / Decorating ActiveRecord association accessor

Hi,
I am trying to overwrite the accessor of a has_many association.
Basically my class looks like this:

class Person
  has_many :emails
  has_one :link, :class_name => 'PersonProxy'

  def emails_with_link
     link.emails + emails_without_link
  end
  alias_method_chain :emails, :link
end

Now that works fine if I only access the collection like

Person.find(1).emails

=> [#<Email...]

But using any collection specific methods throw a NoMethodError

Person.find(1).emails.build

=> NoMethodError: undefined method `build' for #<Array:0x226c634>

which makes sense, as I return an array...

But how do I return the Association? Or are there any other tricks to
implement this decorator for associations?

Cheers
Marcel

Hi,
I am trying to overwrite the accessor of a has_many association.
Basically my class looks like this:

class Person
has_many :emails
has_one :link, :class_name => 'PersonProxy'

def emails_with_link
link.emails + emails_without_link
end
alias_method_chain :emails, :link
end

Now that works fine if I only access the collection like>> Person.find(1).emails

=> [#<Email...]

But using any collection specific methods throw a NoMethodError>> Person.find(1).emails.build

=> NoMethodError: undefined method `build' for #<Array:0x226c634>

which makes sense, as I return an array...

The trick is that link.emails isn't an array - it's an association
proxy.
I'm not sure what the write thing to do here is. Maybe something like

has_many :emails do
  def load_target
    super
    proxy_target += proxy_owner.link.emails
  end
end

might do the trick ?

Fred

The trick is that link.emails isn't an array - it's an association
proxy.
I'm not sure what the write thing to do here is. Maybe something like

Thanks so much for your input. You got me in the right direction:

has_many :emails do
    def load_target
      super
      if !loaded? and proxy_owner.link.respond_to?(:emails)
        @target += proxy_owner.link.emails
      end
      @target
    end
  end

This works like a charm :slight_smile: Thumbs up!

Marcel

I was a bit too fast and euphoric :slight_smile:
Now this works better:

  has_many :emails do
    def load_target
      super
      if not @loaded_link and proxy_owner.link.respond_to?(:emails)
        puts "loading link"
        @target += proxy_owner.link.emails
        @loaded_link = true
      end
      @target
    end
    def reset
      super
      @loaded_link = false
    end
  end