Ruby on Rails - How to delegate to polymorphic associations?
Asked Answered
D

2

7

Is it possible to use delegate with has_many or has_one association in a polymorphic model? How does that work?

class Generic < ActiveRecord::Base
    ...

  belongs_to :generable, polymorphic: true

  delegate :file_url, to: :image, allow_nil: true
  delegate :type_cat, to: :cat, allow_nil: true
end

class Image < ActiveRecord::Base
   ...
  has_one :generic, as: generable, dependent: :destroy
end


class Cat < ActiveRecord::Base
   ...
  has_one :generic, as: generable, dependent: :destroy
end
Dortheydorthy answered 1/11, 2012 at 15:52 Comment(1)
Take a look about delegateDeadwood
T
7

Not sure if this exactly matches what you're looking to do, as it's tough to tell from your example but...

class Generic < ActiveRecord::Base
  ...
  belongs_to :generable, polymorphic: true
  ...
  delegate :common_method, to: :generable, prefix: true
end

class Cat
  def common_method
    ...
  end
end

class Image
  def common_method
    ...
  end
end

Allows you to say the following:

generic.generable_common_method
Turquoise answered 14/8, 2013 at 17:22 Comment(0)
D
0

Unfortunately, the delegate macro simply doesn't cut it for polymorphic associations – unless, of course, you can ensure that all of your polymorphic associations have the delegated method implemented (which kind of defeats the purpose).

And the allow_nil option is only going to prevent NoMethodError from occurring if there isn't a generable present. If, however, a generable is present but the generable doesn't have the delegated method implemented, you're still going to get a NoMethodError.

Your best bet is to implement delegation like so:

class Generic < ActiveRecord::Base
  ...

  belongs_to :generable, polymorphic: true


  def file_url
    generable.try(:file_url)
  end

  def type_cat
    generable.try(:type_cat)
  end

  ...
end

Using this implementation, @generic.file_url will simply return nil if the generable doesn't respond to that method.


Another option, to give you DRYer code and avoid having a bunch of methods that just say "try the same method name on the polymorphic association", you could define all of them on one line and have them generated dynamically like so:

class Generic < ActiveRecord::Base
  ...

  belongs_to :generable, polymorphic: true

  METHODS_FOR_POLYMORPHIC_DELEGATION = %i(
    file_url
    type_cat
    something_else
    and_another_something_else
  )

  METHODS_FOR_POLYMORPHIC_DELEGATION.each do |method_name|
    define_method(method_name) { generable.try(method_name) }
  end

  ...
end
Domett answered 28/6, 2018 at 20:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.