Как быстро загрузить ассоциации в переменную экземпляра?

В модели у меня есть:

class CalendarItem < Resource
  belongs_to :schedule

  has_many :people
  has_many :documents

  acts_as_list scope: :schedule, column: :visual_position

  validates :schedule, :title, presence: true
end

Затем в контроллере:

class ScheduleController < ApplicationController
  def show
    @calendar_items = CalendarItem.where(schedule: @schedule).includes(:people, :documents)
  end

  ...
end

В представлении я визуализирую react_component с помощью react-rails (но это должно иметь какое-то значение):

= react_component('CalendarItemsList', calendar_items: @calendar_items)

Однако он не передает связанные данные в представление (react_component), а только основную модель.

Я сталкивался с этим раньше, с нереагирующим интерфейсом, и это тоже не сработало. Что может быть не так?


person Aurimas    schedule 05.03.2017    source источник
comment
Он передает пустой массив, nil или выдает ошибку?   -  person Kieran E    schedule 05.03.2017
comment
Я могу использовать @caledar_items, но он не включает ассоциации людей и документы. Спасибо   -  person Aurimas    schedule 05.03.2017
comment
О, это должно быть легко. Попробуйте CalendarItem.includes(<criteria>).where(<criteria>). У вас обратный порядок.   -  person Kieran E    schedule 05.03.2017
comment
Пробовал безуспешно :( не меняет, только основная модель   -  person Aurimas    schedule 05.03.2017
comment
Порядок действительно имеет значение? Я думал, что это не так   -  person Aurimas    schedule 05.03.2017
comment
Я ошибался. Я действительно устал ;). Во всяком случае, что вы имеете в виду, когда говорите, что он возвращает основную модель? Возвращает ли он класс CalendarItem или коллекцию, соответствующую вашему предложению where?   -  person Kieran E    schedule 05.03.2017
comment
Он возвращает коллекцию, но я ожидаю, что каждый элемент коллекции будет содержать связанную коллекцию режимов.   -  person Aurimas    schedule 05.03.2017
comment
includes только предварительно загружает ассоциации. Не имеет значения, доступна ли ассоциация для представления. Похоже, вы ищете сериализатор.   -  person fylooi    schedule 05.03.2017
comment
@fylooi, спасибо, не могли бы вы дать ответ? Был бы признателен.   -  person Aurimas    schedule 05.03.2017
comment
Я следовал руководству здесь api.rubyonrails.org/classes/ActiveModel/Serialization.html, но он по-прежнему не включает ассоциацию.   -  person Aurimas    schedule 05.03.2017
comment
В вашем сериализаторе определены отношения?   -  person Peter Toth    schedule 05.03.2017
comment
Гиды говорят только о предоставлении attr_accessor, поэтому у меня есть attr_accessor :id, :title, :people, :documents   -  person Aurimas    schedule 05.03.2017
comment
Что он возвращает? Обычно он возвращает основную модель, но вы получите ассоциацию, перемещаясь по объекту основной модели.   -  person Anwar    schedule 05.03.2017
comment
О, не используйте attr_accessor для фактических столбцов базы данных - это ошибка, которую я видел много, и она имеет тенденцию портить естественные методы доступа Active Record. Всегда используйте attr_accessor только для вещей, которые не являются столбцами базы данных.   -  person Taryn East    schedule 06.03.2017


Ответы (2)


Проблема не в данных в переменной экземпляра, а в сериализации.

Помощник представления react_component вызовет метод to_json для второго аргумента, если он не является строкой. В вашем случае: {calendar_items: @calendar_items}.to_json, который работает рекурсивно, поэтому вы хотите убедиться, что @calendar_items.to_json возвращает ожидаемый результат JSON. Вы можете использовать @calendar_items.serializable_hash для тестирования в rails console, он возвращает хеш, который более удобочитаем для людей.

Или вы сериализуете свои данные в строку и передаете ее react_component.

Я не знаю сериализацию Rails 5, но она похожа на ActiveModelSerializers, так что вы можете включить отношения в сериализованном выводе, например: @calendar_items.to_jso(include: [:documents]). В ActiveModelSerializers вы можете указать сериализатор для каждого класса и указать отношения к ним, которые могут быть включены автоматически.

Таким образом, одним рабочим решением может быть:

def show
  calendar_items = CalendarItem.where(schedule: @schedule).includes(:people, :documents)
  @react_component_props = { calendar_items: calendar_items.to_json(include: [:people, :documents]) }
end

= react_component('CalendarItemsList', @react_component_props)

Скромный совет: вы можете создать область видимости by_schedule в модели CalendarItem, чтобы позже вы могли ее использовать: CalendarItem.by_schedule @schedule

ИЗМЕНИТЬ

Если вам нужны данные в других местах представления, вы можете использовать метод as_json:

def show
  calendar_items_scope = CalendarItem.where(schedule: @schedule).includes(:people, :documents)
  @calendar_items = calendar_items_scope.as_json(include: [:people, :documents])
end
person Peter Toth    schedule 05.03.2017
comment
Спасибо, вроде работает! за исключением того, что теперь @react_component_props является частью объекта json, поэтому мне нужно выполнить некоторую пост-обработку во внешнем интерфейсе, что не очень аккуратно. Есть ли способ сделать @react_component_props объектом? (включая ассоциации).. Я предполагаю, что это потому, что .to_json вызывается дважды, затем (?) - person Aurimas; 05.03.2017
comment
Забудьте об этом, он отлично работает следующим образом: @calendar_items = calendar_items.as_json(include: [:people, :documents]), где calendar_items — локальная переменная, а не экземпляр. - person Aurimas; 05.03.2017
comment
Если вы можете добавить это в решение, я могу принять его как используемое. ... as_json здесь работает лучше - person Aurimas; 05.03.2017

Обходной путь решения состоит в том, чтобы добавить as_json и включить туда ассоциации:

@calendar_items = CalendarItem.where(schedule: @schedule)
                              .as_json(include: [:people, :documents])

Это загружает/сериализует ассоциации, как и ожидалось.

person Aurimas    schedule 05.03.2017