DRY Несколько одинаковых ассоциаций в модели рельсов

В моей модели у меня есть несколько ассоциаций has_one, например

has_one  :t1_for_self_order, -> { t1_for_self_order }, as: :source, dependent: :destroy, inverse_of: :source,
          class_name: 'Spree::PriceMapping'
has_one  :shipping_charges_for_t1, -> { shipping_charges_for_t1 }, as: :source, dependent: :destroy, inverse_of: :source,
          class_name: 'Spree::PriceMapping'
has_one  :t2_for_self_order, -> { t2_for_self_order }, as: :source, dependent: :destroy, inverse_of: :source,
          class_name: 'Spree::PriceMapping'
has_one  :shipping_charges_for_t2, -> { shipping_charges_for_t2 }, as: :source, dependent: :destroy, inverse_of: :source,
          class_name: 'Spree::PriceMapping'
has_one  :minimum_value_for_gifting, -> { minimum_value_for_gifting }, as: :source, dependent: :destroy, inverse_of: :source,
          class_name: 'Spree::PriceMapping'
has_one  :international_fulfillment_fees, -> { international_fulfillment_fees }, as: :source, dependent: :destroy, inverse_of: :source,
          class_name: 'Spree::PriceMapping'

вы заметили, что во всех ассоциациях различается только имя ассоциации с одним и тем же именем области, но остальная часть содержимого одинакова.

Поэтому я хочу написать функцию, которая удалит все эти повторения. Я думаю, что это возможно с метапрограммированием, но я не уверен, как это сделать.

Кроме того, у меня также есть массив вложенных атрибутов, которые мы можем использовать.

    THRESHOLD_INTENT = ["t1_for_self_order", "shipping_charges_for_t1", "t2_for_self_order", "shipping_charges_for_t2",
                    "minimum_value_for_gifting", "international_fulfillment_fees", "menu_customization_fee",
                    "total_menu_customization_fee_cap", "video_message_fee", "total_video_message_fee_cap",
                    "swag_price", "box_types_with_price", "customization_box_types_with_price", "custom_note_fee",
                    "non_us_fees"]

Мне нравится делать это таким образом

THRESHOLD_INTENT.each do |t_intent|
  has_one  t_intent.to_sym, as: :source, dependent: :destroy, inverse_of: :source, class_name: 'Spree::PriceMapping'
end

Но как я могу передать объем в этом, как

-> { t1_for_self_order }

🤔 А знаете ли вы, что...
Ruby обеспечивает удобную работу с файлами и директориями на уровне операционной системы.


30
2

Ответы:

Попробуйте извлечь общие атрибуты, например

relationship_attributes = { as: :source, dependent: :destroy, inverse_of: :source, class_name: 'Spree::PriceMapping' }

has_one :t1_for_self_order, -> { t1_for_self_order }, relationship_attributes
has_one :shipping_charges_for_t1, -> { shipping_charges_for_t1 }, relationship_attributes
has_one :t2_for_self_order, -> { t2_for_self_order }, relationship_attributes
has_one :shipping_charges_for_t2, -> { shipping_charges_for_t2 }, relationship_attributes
has_one :minimum_value_for_gifting, -> { minimum_value_for_gifting }, relationship_attributes
has_one  :international_fulfillment_fees, -> { international_fulfillment_fees }, relationship_attributes

Я бы не стал использовать метапрограммирование, это может затруднить чтение


Решено

Вы можете перебрать список имен ассоциаций и вызвать has_one со всеми параметрами для каждого элемента. send(association) необходим для вызова области ассоциации как метода.

ASSOCIATIONS = [:t1_for_self_order, :shipping_charges_for_t1, :t2_for_self_order, :shipping_charges_for_t2, :minimum_value_for_gifting, :international_fulfillment_fees]

ASSOCIATIONS.each do |association|
  has_one association, -> { send(association) }, as: :source, dependent: :destroy, inverse_of: :source, class_name: 'Spree::PriceMapping'
end