Автоматическое создание отсутствующих моделей соединения - PullRequest
0 голосов
/ 20 декабря 2018

В последнее время я устал от засорения моего каталога app/models бессмысленными шаблонными моделями, такими как:

  • Присоединяйся к моделям, которые всегда содержат пару belongs_to s и ничего больше.
  • Модели журнала состояний, которые просто include SomeConcern и совершают пару вызовов макроса.
  • Модели отслеживания изменений, которые снова включают в себя задачу и вызывают макрос.

Эти моделисуществуют только для поддержки ассоциаций has_many и has_many ... through:.

Добавление проблем моделей, которые генерируют эти модели по мере необходимости, очищает, упрощает каталог app/models.Таким образом, вместо:

has_many :model_things
has_many :things, through: :model_things

и тривиального app/models/model_thing.rb, который говорит:

class ModelThing < ApplicationRecord
  belongs_to :model
  belongs_to :thing
end

Я могу иметь беспокойство ThingSupport с макросом has_things, который:

  1. Создает ассоциацию has_many :model_things на основе имени класса и некоторых опций для has_things.

  2. Создает ассоциацию has_many :things, through: :model_things.

  3. Найдите или создайте класс Model::Thing (см. Ниже, почему это имя используется) с помощью вызова, подобного:

     ModuleUtil.find_or_create(join_model_name) do
      Class.new(ApplicationRecord) do
        # Set the table name, call belongs_to as needed, call concern methods, ...
      end
    end
    

    , где ModuleUtil.find_or_create - простой метод, которыйиспользует String#constantize, чтобы найти нужный модуль (если он существует) или создать его с помощью блока, и Object#const_set, если он не может быть найден.

Все названия моделей и ассоциацийможет быть построен с использованием обычных соглашений Rails от имени класса вызывающего и некоторых опций до has_things для особых случаев.

Вопрос в том, играю ли я здесь с огнем?Что может пойти не так с этим видом chicanery?

Одна проблема, с которой я уже сталкивался, состоит в том, что сгенерированные классы моделей не существуют сами по себе, поэтому на них нельзя напрямую ссылаться из ActiveJob (такой как deliver_later почтовик).Например, если при загрузке Model создается модель ассоциации ModelThing, вы не можете ссылаться на ModelThing в аргументе почтовой программы, поскольку ActiveJob не будет знать, что вам нужно загрузить класс Model до того, как ModelThing существует,Однако это можно решить, используя вместо этого Model::Thing, так что constantize будет искать Model (и найти его в app/models/model.rb), прежде чем пытаться найти Model::Thing (который будет существовать, потому что constantize будет иметь толькозагружен Model, который создает Model::Thing).Я что-то упускаю?

1 Ответ

0 голосов
/ 20 декабря 2018

Понятия не имею, слежу я за тобой или нет.Так что, если это далеко от цели, пожалуйста, скажите, и я удалю.

Сосредоточив внимание на модели соединения, я также устал от этого легкого пламени.Итак, я создал такую ​​модель:

module ActsAsHaving
  class HasA < ActiveRecord::Base
    validates :haser_type, :haser_id, :hased_type, :hased_id, presence: true
    belongs_to :hased, polymorphic: true
    belongs_to :haser, polymorphic: true

    acts_as_taggable

    def haser=(thing)
      self.haser_type = thing.class.name
      self.haser_id   = thing.id
    end

    def haser
      haser_type.constantize.find_by(id: haser_id)
    end

    def hased=(thing)
      self.hased_type = thing.class.name
      self.hased_id   = thing.id
    end

    def hased
      hased_type.constantize.find_by(id: hased_id)
    end

  end
end

Я не использовал встроенные средства доступа и проверки, потому что иногда я использую это для объединения не-AR записей (которые я извлекаю из служб удаленного API, некоторые изкоторые принадлежат мне, а некоторые нет, но это более длинная история).

Во всяком случае, тогда я написал макрос acts_as_having, который позволяет мне делать такие вещи, как:

class Person < ActiveRecord::Base

  acts_as_having :health_events, class_name: "Foo::Event", tag_with: "health_event", remote: true
  acts_as_having :program_events, class_name: "Foo::Event", tag_with: "program_event", remote: true
  acts_as_having :email_addresses, :phone_numbers, :physical_addresses

end

Что дает мне такие вещи, как:

@person.email_addresses
@person.email_addresses << @email_address 
etc...

Я могу сделать обратное, как:

class EmailAddress < ActiveRecord::Base

  acts_as_had_by :person

end

Что дает мне такие вещи, как:

@email_address.person
etc...

Затем я завернулвсе это барахло в драгоценный камень.Сейчас я редко создаю соединяемые модели, если у них нет особых требований, которые я не могу вставить в свой бит acts_as_having.

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

...