首页 > 解决方案 > Rails 中的自联接正在返回每个预期子行的父记录

问题描述

我的 Rails 应用程序中有一个音频模型,它使用一个id和 parent_audio_id 字段来构建层次结构。单个音频可以是另一个音频的子级,也可以有多个子级音频(我称之为派生类)。

我已经参考了这个关于自我连接的边缘指南来构建关系以及这个 SO 帖子来帮助解决问题

使用下面的活动记录查询,我得到一个数据集,其中父音频数据重复了 N 次,其中 N 等于该父级的子记录数。

在给定自加入关系的情况下,如何返回给定父音频记录的子记录?

**Audio.rb**

class Audio < ApplicationRecord

  has_many :derivatives, :class_name => "Audio", :foreign_key => "parent_audio_id"
  belongs_to :parent_audio, :class_name => "Audio", optional: true

end

**Audio Migration**
    class CreateAudios < ActiveRecord::Migration[6.0]
     def change
      create_table :audios do |t|
       t.references :parent_audio, foreign_key: {to_table: :audios}
      end
     end
    end



    **Audios Controller**
     def audio_details
      data = []
      derivatives = Audio.joins(:derivatives)
      data.push(derivatives)
      render json: data
     end

我也尝试过derivatives = Derivative.joins(:audios),但出现以下错误:

uninitialized constant Api::V1::AudiosController::Derivative

标签: ruby-on-railsactiverecordself-join

解决方案


.joins只需将 a 添加INNER JOIN到查询中。它不会选择连接表上的任何列,也不会返回关联。它根据调用的任何内容返回一个新范围 - 因此在这种情况下,范围将选择在连接表中至少有一个匹配项(至少一个后代)的音频。

.joins主要用于根据连接表过滤记录:

Patient.joins(:appointments)
       .where(scheduled_at: Time.current..)

或选择聚合:

Hotel.joins(:reviews)
     .select('hotels.*', 'AVG(reviews.rating) AS average_rating')
     .group(:id)

如果要返回特定 Audio 的后代,则需要在类的实例上调用关联宏生成的方法:

@audio = Audio.find(params[:id])
@descendents = @audio.descendents

ActiveRecord 将自动创建一个单独的查询来加载死者。

您可以使用.eager_load强制单个查询而不是两个:

@audio = Audio.eager_load(:descendents)
              .find(params[:id])
@descendents = @audio.descendents

请参阅Rails 指南:Active Record 查询接口


推荐阅读