Как распространить параметр через дочерние объекты? (Rails 5.2)

#ruby-on-rails #activerecord

#ruby-on-rails #activerecord

Вопрос:

Мое приложение управляет классификациями, в которых несколько списков значений связаны для создания иерархии. Таблица values_to_values реализует связи между значениями для всех классификаций:

 class Value < ApplicationRecord

  attr_accessor :classification_id

  has_many :values_to_values
  has_many :child_values, through: :values_to_values
  

для которых N-N ссылок хранятся в:

 # Table name: values_to_values
#
#  id                    :integer          not null, primary key
#  classification_id     :bigint
#  parent_values_list_id :bigint
#  child_values_list_id  :bigint
#  parent_value_id       :bigint
#  child_value_id        :bigint
  

В результате значение может быть задействовано в нескольких иерархиях.

При отображении иерархии я запрашиваю таблицы value_to_values столько раз, сколько уровней содержит иерархия. Чтобы получить только ссылки, относящиеся к текущей классификации, мне нужно распространить classification_id и включить его в запрос.

Я создал метод get_children в values_controller и добавил атрибут classification_id в модель значений. Чтобы извлечь дочерние значения, я фильтрую values_to_values с помощью распространяемого атрибута classification_id:

   # GET children from @classification values, including translations for child index
  def get_children
    @values = @value.child_values.where("values_to_values.classification_id = ?", @value.classification_id).includes(:name_translations).order(:code)
    @values.each do |child|
      child.classification_id = @value.classification_id
    end

    respond_to do |format|
      format.html { render :index } # index.html.erb
      format.json { render json: @values }
      format.js # uses specific template to handle js
    end
  end
  

Затем я бы присвоил идентификатор классификации виртуальному атрибуту classification_id для распространения на следующий уровень иерархии. На первом уровне classification_id передается через параметр url, но, работая с js в DOM на следующих уровнях, я больше не могу использовать параметр (или я не знаю, как это сделать).

 $(function () {
  var itemId = '<%= @values_list.id %>',
      ctId = 'ui-nav-values_list-'   itemId   '-children',
      // create children array (code generated server side)
      children = [
        <% @values.each do |child| %>
          {
            id: '<%= child.id %>',
            code: '<%= child.code %>',
            classification_id: '<%= child.classification_id %>',
            name: '<%= j(translation_for(child.name_translations)) %>',
            url: '<%= url_for(child) %>',
            loadUrl: '<%= url_for(get_children_value_path(child)) %>',
            hasChildren: <%= (!child.child_values.empty?).to_json %>
          },
        <% end %>
      ];

  $('#'   ctId).sisNavigation({
    children: children,
    childLevelId: 'value'
  });
});
  

К сожалению, виртуальный атрибут classification_id отсутствует в json, поэтому запрос не возвращает дочерних объектов.

  • Это правильный способ достижения этой цели?
  • Как получить набор данных @values, включающий виртуальный атрибут?

Ответ №1:

Я нашел ответ parial:

О attr_accessor :classification_id , я, наконец, создал атрибут physicall в таблице значений, который используется только здесь (плохое решение!).

Что касается распространения параметра classification_id, я обновил код, чтобы определенно использовать его в качестве параметра:

get_children.js.erb

 $(function () {
  var itemId = '<%= @values_list.id %>',
      ctId = 'ui-nav-values_list-'   itemId   '-children',
      // create children array (code generated server side)
      children = [
        <% @values.each do |child| %>
          {
            id: '<%= child.id %>',
            code: '<%= child.code %>',
            classification_id: '<%= child.classification_id %>',
            name: '<%= j(translation_for(child.name_translations)) %>',
            url: '<%= url_for(child) %>',
            loadUrl: '<%= url_for(get_children_value_path(child, classification_id: child.classification_id)) %>',
            hasChildren: <%= (!child.child_values.empty?).to_json %>
          },
        <% end %>
      ];

  $('#'   ctId).sisNavigation({
    children: children,
    childLevelId: 'value'
  });
});
  

values_controller

   # GET children from @classification values, including translations for child index
  def get_children
    #@values = @value.child_values.where("values_to_values.classification_id = ?", @classification.id).includes(:name_translations).order(:code)
    @values = @value.child_values.where("values_to_values.classification_id = ?", params[:classification_id]).includes(:name_translations).order(:code)
    @values.each do |child|
      child.classification_id = params[:classification_id]
    end

    respond_to do |format|
      format.html { render :index } # index.html.erb
      format.json { render json: @values }
      format.js # uses specific template to handle js
    end
  end
  

Замечания и альтернативные решения приветствуются!