Rails 查找除已经关联的二级记录之外的所有记录

Rails find all records except already second level associated

我的 rails 应用程序中有以下模型

型号community:

class Community < ActiveRecord::Base
  has_many :community_program
end

型号community_program:

class CommunityProgram < ActiveRecord::Base
  belongs_to :program_name
end

型号program_name:

class ProgramName < ActiveRecord::Base
  has_many :community_programs
end

我正在尝试找到一种方法来提取所有不属于 community_programprogram_names,而 community_program 已经分配给了 community

我已经能够拉出所有 program_names,然后删除已经与 community 相关联的 program_names,但这非常昂贵。可以直接拉取二级无关联记录吗?

编辑:这个问题与链接的问题不同,因为在这种情况下,program_name 可能与不同社区的社区计划有关联,但我们仍然希望包含该名称如果它与当前 community.

没有关联

**编辑 2:我想提取所有尚未分配给与特定社区关联的社区计划的计划名称。它们可以与不同社区相关联的社区计划相关联。用例是用户应该能够 select 从剩余名称列表中选择一个名称,并将其分配给与其社区关联的社区计划。

程序名称是全球性的,虽然特定社区的社区程序的程序名称是唯一的,但不同的社区可以有与同一程序名称相关联的社区程序**

您可以通过几种不同的方式来执行此操作,具体取决于您在哪个 controller/view 上显示它们。

在社区模型上创建 association

has_many :unassigned_program_names, -> { where community_program_id: nil }

在 ProgramName 模型上创建这样的 scope

scope :unassigned, -> { where(community_program_id: nil) }

希望这对您有所帮助。 :)

except_community是一个特定的Community应该排除的关联。下面的代码将产生一个 SQL 查询:

except_relation = except_community.
  community_programs.
  select(:program_name_id)

ProgramName.
  where.not(id: except_relation)

您可以将其添加为 Community 模型的实例方法。

可能是这样的:

class Community < ActiveRecord::Base
  has_many :community_programs
end

class CommunityProgram < ActiveRecord::Base
  belongs_to :program_name, optional: true
  belongs_to :community
end

class ProgramName < ActiveRecord::Base
  has_many :community_programs
end

some_community            = Community.find some_community_id
programs_from_a_community = some_community.community_programs.map &:id 
program_names_to_exclude  = CommunityProgram.where(id: programs_from_a_community)
                                            .where.not(program_name_id: nil)
                                            .map { |c_p| c_p.program_name.id }
program_names             = ProgramName.where.not(id: program_names_to_exclude)

我之前接受的答案版本被拒绝了,所以我将其添加为另一个答案。 Pavel Mikhailyuk 提供的解决方案解决了我的问题。

因为我想找到最有效的查询,所以我最终更新了它并使用了:

ProgramName.where.not(id: except_community.community_programs.pluck(:program_name_id))

编辑:所选答案比这更有效。