Модель дерева Rails с атрибутами дерева-узла - PullRequest
1 голос
/ 10 апреля 2019

Мне нужно создать модель в Rails (5.2) для древовидной структуры со следующими требованиями:

  • листья дерева могут быть повторно использованы в нескольких древовидных структурах
  • Узлы дерева также могут иметь атрибуты (например, количество в примере ниже)

Я решил использовать следующую модель базы данных:

db model

Миграции для создания этих таблиц выглядят следующим образом:

class CreateItems < ActiveRecord::Migration[5.2]
  def change
    create_table :items, id: false, primary_key: :item_no do |t|
      t.string :item_no, null: false
      t.string :item_name
      t.float :inventory

      t.timestamps
    end
    add_index :items, :item_no, :unique => true
    execute "ALTER TABLE items ADD PRIMARY KEY (item_no);"
  end
end

class CreateTrees < ActiveRecord::Migration[5.2]
  def change
    create_table :trees, id: false, primary_key: %i[parent_item_no child_item_no] do |t|
      t.string :parent_item_no
      t.string :child_item_no
      t.float :quantity

      t.timestamps
    end
    execute "ALTER TABLE trees ADD PRIMARY KEY (parent_item_no, child_item_no);"
  end
end

У меня проблема в том, чтобы настроить модели Rails для отражения этой модели данных с использованием ассоциаций.

class Tree < ApplicationRecord
  self.primary_keys = :parent_item_no, :child_item_no
  belongs_to :item_no, class_name: 'Item', foreign_key: :parent_item_no
  has_many :item_no, class_name: 'Item', foreign_key: :child_item_no
end

Родительское отношение в порядке, но has_many явно не работает, так как ожидает внешнего ключа в таблице Item.Мне нужен способ доступа к дочерним узлам дерева.

Как бы вы это сделали?Я ценю любые предложения.

1 Ответ

0 голосов
/ 10 апреля 2019

Я полагаю, вы бы сделали что-то вроде:

class Tree < ApplicationRecord
  belongs_to :parent_item, class_name: 'Item', foreign_key: :parent_item_no
  belongs_to :child_item,  class_name: 'Item', foreign_key: :child_item_no
end

Тогда вам нужно сделать что-то вроде:

class Item < ApplicationRecord
  has_many :children_trees, class_name: 'Tree', foreign_key: :parent_item_no
  has_many :child_items, through: :children_trees
  has_many :parent_trees, class_name: 'Tree', foreign_key: :child_item_no
  has_many :parent_items, through: :parent_trees
end

Возможно, вам придется немного поработать с этим, поскольку он не протестирован.

Тогда вы сможете сделать что-то вроде:

@item.child_items
@item.parent_items

Поскольку вы оговорили, что Item (то, что вы называете «листом дерева», но также может называться «узлом»), может быть многократно использовано в нескольких древовидных структурах, вам потребуется выполнить некоторую сложную работу, чтобы сделать убедитесь, что вы извлекаете родительские и дочерние элементы в контексте определенного дерева. Но это другая проблема.

Лично я не уверен, о чем этот бит:

self.primary_keys = :parent_item_no, :child_item_no

Если вы хотите убедиться, что существует только один экземпляр Tree между двумя данными Item с, то я бы предложил вам проверить уникальность, используя область действия .

Я не знаю, почему вы используете _no вместо _id. Если бы у вас было parent_item_id и child_item_id вместо parent_item_no и child_item_no, то я думаю, что вы могли бы сделать:

class Tree < ApplicationRecord
  belongs_to :parent_item, class_name: 'Item'
  belongs_to :child_item,  class_name: 'Item'
end

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

Кстати, Tree кажется странным именем для класса. Tree - это совокупность всех ребер и узлов в вашей иерархической структуре. Но вы используете Tree, чтобы обозначить преимущество в вашей структуре. Это кажется мне своеобразным. Но, эй, это вопрос личных предпочтений. Так что, если она плывет на вашей лодке, дерзайте!

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