Reputation: 1701
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
Upvotes: 7
Views: 3027
Reputation: 4114
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
Upvotes: 0
Reputation: 1302
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
Upvotes: 7