Делегировать все вызовы методов на модели на объединение - программирование
Подтвердить что ты не робот

Делегировать все вызовы методов на модели на объединение

У меня есть модель ActiveRecord с полиморфной ассоциацией вроде этого:

class Reach < ActiveRecord::Base
  belongs_to :reachable, :polymorphic => true
end

Эта модель действует как прокси. Что мне нужно сделать, это переслать все вызовы методов на этот объект на связанный объект :reachable. Я думаю, что delegate здесь не поможет, потому что я должен явно указать все методы, которые мне нужно делегировать. Мне нужно что-то вроде delegate :all делегировать все методы (не all).

4b9b3361

Ответ 1

Здесь вы можете сделать две вещи:

  • Более медленный (с точки зрения производительности), но более простой способ заключается в использовании метода_поиск:

    class Reach < ActiveRecord::Base
    
      def method_missing(method, *args)
        return reachable.send(method, *args) if reachable.respond_to?(method)
        super
      end
    end
    
  • Более быстрый способ заключается в том, чтобы определить каждый метод динамически, который вы хотите делегировать:

    class Reach < ActiveRecord::Base
    
      [:all, :my, :methods, :here].each do |m|
        define_method(m) do |*args|
          reachable.send(m, *args)
        end 
      end
    end
    

Вы могли бы даже использовать этот метод более динамично, если хотите, взяв класс Reach, найдя методы, которые определены на нем, и он один, и определяя только те, которые находятся на Reachable. Я сделал бы это вручную, потому что есть некоторые, которые вы, вероятно, не захотите включить.

Ответ 2

Для Rails я сделал следующее:

class User < ApplicationRecord
  has_one :member
  delegate (Member.new.attributes.keys - User.new.attributes.keys), to: :member
end

- User.new... должен не переопределять существующие атрибуты на User (например, created_at)

Я не уверен, как этот подход будет работать с полиморфизмом.

Ответ 3

Я нашел аккуратный способ подойти к проблеме, используя уточнения. В стандартной библиотеке уже есть класс, который позволяет делегировать вызов каждого метода целевому объекту. Delegator и по расширению SimpleDelegator Теперь есть способ вставить SimpleDelegator в цепочку наследования, не наследуя его напрямую, используя уточнения:

def self.include_delegator
  mod = Module.new do
    include refine(SimpleDelegator) { yield if block_given? }
  end
  self.send :include, mod
end
include_delegator

Теперь, чтобы воспользоваться SimpleDelegator, установите цель делегирования в после инициализации обратного вызова следующим образом:

after_initialize do |instance|
  __setobj__(instance.reachable)
end

Это эквивалентно наследованию непосредственно от SimpleDelegator и настройке делегирования в конструкции, нет ручного ведения методов для делегирования, и вы можете избежать использования метода.