【问题标题】:Rails Associations: with self through second modelRails 关联:通过第二个模型使用自我
【发布时间】:2016-10-24 22:53:44
【问题描述】:

我有两个模型分类和分类关系。我想使用超类和子类创建分类层次结构,以便每个分类可以有许多子类但只有一个超类。

我的迁移看起来像这样

class CreateClassifications < ActiveRecord::Migration[5.0]
  def change
    create_table :classifications do |t|
      t.string :symbol
      t.string :title
      t.integer :level

      t.timestamps
    end
    add_index :classifications, :symbol
    add_index :classifications, :level
  end
end

class CreateClassificationRelationships < ActiveRecord::Migration[5.0]
  def change
    create_table :classification_relationships do |t|
      t.integer :superclass_id
      t.integer :subclass_id

      t.timestamps
    end
    add_index :classification_relationships, :superclass_id
    add_index :classification_relationships, :subclass_id
    add_index :classification_relationships, [:superclass_id, :subclass_id], unique: true, name: 'unique_relationship'
  end
end

到目前为止,我有我的模型

class ClassificationRelationship < ApplicationRecord
    belongs_to :superclass, :class_name => "Classification"
    belongs_to :subclass,   :class_name => "Classification"
end

class Classification < ApplicationRecord
    has_many :classification_relationships
    has_many :subclasses, through => :classification_relationships
    has_one  :superclass, through => :classification_relationships
end

我阅读了很多其他帖子,但仍然不确定如何完成关联。我很确定我需要指定外键,但不清楚我应该如何做到这一点。感谢您的帮助!

【问题讨论】:

    标签: activerecord associations ruby-on-rails-5


    【解决方案1】:

    摆脱ClassificationRelationship
    您只需要Classification 有一个parent_id,在根实例中,它允许为空。

    添加:

    belongs_to :parent, class_name: 'Classification', foreign_key: :parent_id
    def children
      Classification.where(:parent_id => self.id)
    end
    

    有些操作不是最优的。例如找到所有的后代。那是因为这将需要重复查询才能找到孩子、他们的孩子等...
    这可能不是您关心的问题。
    如果是,我建议将path 存储为这样:

    after_create :set_path
    def set_path
      path = parent ? "#{parent.path}#{self.id}/" : "#{self.id}/"
      self.update_attributes!(:path => path)
    end
    

    然后您可以执行以下操作:

    def descendants
        Classification.where("classifications.path LIKE '#{self.path}%' AND classifications.path <> '#{self.path}'")
    end
    

    当然,如果您要进行这样的查询,请确保路径已编入索引。

    【讨论】:

    • 最初我想过这样的事情,但我认为使用它们之间的第二个关系模型查询会更自然。想法?
    • 我提供了一种方法,可以用更少的数据库表准确地获得您所要求的内容。该模型由数据库强制执行。连接表用于多对多关系。如果您可能通过代码示例解释“更自然”的含义,那么我可以重新考虑。
    • 我想我只是误读了一些导轨。这肯定会奏效。 railsguides 的一部分帮助我理清了关于自我加入协会的问题(2.10 供参考)。此外,尽管他们添加了一个我认为可能取代 children 方法的 has_many 关联。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-27
    相关资源
    最近更新 更多