Определение атрибутов во время выполнения на основе данных из связанного объекта - PullRequest
0 голосов
/ 22 марта 2019

Я создаю приложение, в котором пользователи являются частью Organisation.В организации много List с, что, в свою очередь, имеет много ListItem с.

Теперь я хотел бы, чтобы пользователи с правами администратора могли указывать, какие атрибуты доступны в элементах списка на основе организацииони принадлежат (или, скорее, в организации, к которой принадлежит их список), не касаясь какого-либо кода.

До сих пор при определении атрибутов, которые не привязаны к конкретному столбцу в базе данных, я использовал document_serializable , изящный маленький драгоценный камень (основанный на virtus ), который сериализует виртуальные атрибуты для столбца JSONB в БД.Мне нравится этот подход, потому что я получаю все положительные качества в Virtus (типы, принуждение, проверки и т. Д.), А также потому, что данные оказываются в столбце JSONB, то есть их можно быстро загружать, индексировать и просматривать с относительной простотой..

Я хотел бы продолжать использовать этот подход при добавлении этих пользовательских атрибутов на лету.Поэтому я хотел бы сделать что-то вроде:

class ListItem < ApplicationRecord
  belongs_to :list
  delegate :organisation, to: :list

  organisation.list_attributes.each do |a, t|
    attribute a, t
  end
end

Где Organisation#list_attributes возвращает пользовательский хэш имен атрибутов и связанных с ними типов, который, например, может выглядеть следующим образом:

{
  name: String,
  age: Integer
}

Как вы уже догадались, это не работает, потому что organisation.list_attributes.each фактически выполняется в контексте ListItem, который является экземпляром Class, а Class не имеет #organisation метод.Я надеюсь, что это сформулировано таким образом, что имеет смысл 1 .

Я пытался использовать after_initialize, но в этот момент в жизненном цикле объекта #attribute принадлежит ActiveRecord::AttributeMethods::Read а не DocumentSerializable::ClassMethods, так что это совершенно другой метод, и я не могу понять, могу ли я получить доступ к тому, что мне нужно, и можно ли даже работать.

Другой альтернативой может быть поискОрганизация, о которой идет речь, каким-то явным образом, Organisation#find, но я, честно говоря, не знаю, где хранить информацию, необходимую для этого.

Итак, мой вопрос: в момент создания (инициализации)или загружая 2 ) запись, есть ли способ получить хэш, хранящийся в столбце базы данных одного из его отношений?Или я пытаюсь построить это совершенно ошибочным образом, и если да, то как еще мне это сделать?


1 Чтобы уточнить, должен ли я использоватьхеш прямо так:

class ListItem < ApplicationRecord
  belongs_to :list
  delegate :organisation, to: :list

  {
    name: String,
    age: Integer
  }.each do |a, t|
    attribute a, t
  end
end

это будет работать, моя проблема исключительно в получении отношения записи в этот более ранний момент времени.

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

1 Ответ

0 голосов
/ 22 марта 2019

в момент создания (инициализации или загрузки) записи, есть ли способ получить хэш, хранящийся в столбце базы данных одного из его отношений?

Да.Это довольно тривиально, если ваши отношения настроены правильно / просто.Допустим, у нас есть эти три модели:

class ListItem < ApplicationRecord
  belongs_to :list
end

class List < ApplicationRecord
  belongs_to :organisation
  has_many :list_items
end

class Organisation < ApplicationRecord
  has_many :lists
end

Мы можем создать экземпляр ListItem и затем получить данные от кого-либо из его родителей.

@list_item = ListItem.find(5) # assume that the proper inherited 
                                foreign_keys exist for this and 
                                its parent
@list = @list_item.list
@hash = @list.organisation.special_hash_of_org

И если мы захотим сделать этов каждом случае ListItem мы можем использовать обратные вызовы Active Record, например:

class ListItem < ApplicationRecord
  belongs_to :list

  # this is called on ListItem.new and whenever we pull from our DB
  after_initialize do |list_item|
    puts "You have initialized a ListItem!"
    list = list_item.list
    hash = list.organisation.special_hash_of_org
  end

end

Но after_initialize кажется странным использованием для такого рода вещей.Возможно, лучше использовать вспомогательный метод!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...