Ruby on rails rails中的命名作用域具有多个关联

Ruby on rails rails中的命名作用域具有多个关联,ruby-on-rails,activerecord,associations,named-scope,Ruby On Rails,Activerecord,Associations,Named Scope,我正在尝试使用Rails的魔力来实现我认为相当复杂的查询,而代码中没有很多难看的SQL 由于我的数据库处理的是相当专业的生物医学模型,我将以下内容转换为更真实的场景 我有一本模型书 有很多章节 那一章呢 属于:书 比如说,章节有一个名称属性,名称可以是前言、引言和附录,一本书可以有一个章节名为前言,一个章节名为引言,但没有章节名为附录。事实上,任何这些的组合 我想找到所有既有前言又有引言的书 目前,我有一个命名的_范围,如下所示 Book named_scope :has_chapter?,

我正在尝试使用Rails的魔力来实现我认为相当复杂的查询,而代码中没有很多难看的SQL

由于我的数据库处理的是相当专业的生物医学模型,我将以下内容转换为更真实的场景

我有一本模型书

有很多章节

那一章呢

属于:书

比如说,章节有一个名称属性,名称可以是前言、引言和附录,一本书可以有一个章节名为前言,一个章节名为引言,但没有章节名为附录。事实上,任何这些的组合

我想找到所有既有前言又有引言的书

目前,我有一个命名的_范围,如下所示

Book
  named_scope :has_chapter?, lambda { |chapter_names|
    condition_string_array = []
    chapter_names.size.times{condition_string_array << "chapters.name = ?"}
    condition_string = condition_string_array.join(" OR ")
    {:joins => [:chapters]  , :conditions => [condition_string, * chapter_names]}
  }
书
命名范围:有章?,lambda{124;章名|
条件字符串数组=[]
章节名称.大小.时间{条件字符串数组[:章节],:条件=>[条件字符串,*章节名称]}
}
如果我给书打电话。你有第二章吗?[“序言”,“导言”]这将为我找到所有有一章名为序言或导言的书。我怎样才能做一件类似的事情,让我既能找到序言又能找到引言

我对SQL不是很熟悉,所以我不太确定需要什么样的联接,以及这是否可以在命名范围内实现

非常感谢

安东尼

我正在寻找所有的书 两章都命名为前言和 导言

目前,我有一个名为 跟随

您可以在没有命名的\u作用域的情况下执行此操作

class Book < ActiveRecord::Base
  has_many :chapters

  def self.has_chapter?(chapter_names)
    Chapter.find_all_by_name(chapter_names, :include => [:book]).map(&:book)
  end
end
classbook[:book])。地图(&:book)
结束
结束
我正在寻找所有的书 两章都命名为前言和 导言

目前,我有一个名为 跟随

您可以在没有命名的\u作用域的情况下执行此操作

class Book < ActiveRecord::Base
  has_many :chapters

  def self.has_chapter?(chapter_names)
    Chapter.find_all_by_name(chapter_names, :include => [:book]).map(&:book)
  end
end
classbook[:book])。地图(&:book)
结束
结束

我喜欢将代码压缩到

condition_string = Array.new(chapter_names.size, "chapters.name=?").join(" AND ")
这确实适用于带有“或”的联接。但是and联接不起作用,因为这意味着联接的单行中的chapters.name必须是“前言”和“引言”

一个更整洁的方式来做我的原始“或”加入是

感谢Rails双工论坛() 为了解决我原来的问题,DUPLEX建议

named_scope :has_chapters, lambda { |chapter_names|
  {:joins => :chapters  , :conditions => { :chapters => {:name => chapter_names}},
   :select => "books.*, COUNT(chapters.id) AS c_count",
   :group => "books.id", :having => "c_count = #{chapter_names.is_a?(Array) ? chapter_names.size : 1}" }
}
这可能在某种类型的SQL中起作用,但在PostgreSQL中不起作用。我必须使用以下命令

named_scope : has_chapter?, lambda { | chapter_names |
  {:joins => :chapters  , :conditions => { :chapters => {:name => chapter_names}},
   :select => "books.* , COUNT(chapters.id)",
   :group => Book.column_names.collect{|column_name| "books.#{column_name}"}.join(","), :having => "COUNT(chapters.id) = #{chapter_names.is_a?(Array) ? chapter_names.size : 1}" }
}
代码

Book.column_names.collect{|column_name| "books.#{column_name}"}.join(",")

是必需的,因为在PostgreSQL中,您不能选择带有books.*的所有列,然后按books.*分组。每个列必须单独命名:(

我喜欢将代码压缩为

condition_string = Array.new(chapter_names.size, "chapters.name=?").join(" AND ")
这确实适用于带有“或”的联接。但是and联接不起作用,因为这意味着联接的单行中的chapters.name必须是“前言”和“引言”

一个更整洁的方式来做我的原始“或”加入是

感谢Rails双工论坛() 为了解决我原来的问题,DUPLEX建议

named_scope :has_chapters, lambda { |chapter_names|
  {:joins => :chapters  , :conditions => { :chapters => {:name => chapter_names}},
   :select => "books.*, COUNT(chapters.id) AS c_count",
   :group => "books.id", :having => "c_count = #{chapter_names.is_a?(Array) ? chapter_names.size : 1}" }
}
这可能在某种SQL风格中起作用,但在PostgreSQL中不起作用

named_scope : has_chapter?, lambda { | chapter_names |
  {:joins => :chapters  , :conditions => { :chapters => {:name => chapter_names}},
   :select => "books.* , COUNT(chapters.id)",
   :group => Book.column_names.collect{|column_name| "books.#{column_name}"}.join(","), :having => "COUNT(chapters.id) = #{chapter_names.is_a?(Array) ? chapter_names.size : 1}" }
}
代码

Book.column_names.collect{|column_name| "books.#{column_name}"}.join(",")
是必需的,因为在PostgreSQL中,您不能选择包含books.*的所有列,然后按books进行分组。*每个列必须单独命名:(

我正在寻找所有的书 两章都命名为前言和 导言

我使用的是mysql,不是postgres,但我假设postgres支持子查询?您可以尝试以下方法:

class Book

  named_scope :has_preface, :conditions => "books.id IN (SELECT book_id FROM chapters WHERE chapters.name = 'preface')"
  named_scope :has_introduction, :conditions => "books.id IN (SELECT book_id FROM chapters WHERE chapters.name = 'introduction')"

end
然后:

Book.has_preface.has_introduction
我正在寻找所有的书 两章都命名为前言和 导言

我使用的是mysql,不是postgres,但我假设postgres支持子查询?您可以尝试以下方法:

class Book

  named_scope :has_preface, :conditions => "books.id IN (SELECT book_id FROM chapters WHERE chapters.name = 'preface')"
  named_scope :has_introduction, :conditions => "books.id IN (SELECT book_id FROM chapters WHERE chapters.name = 'introduction')"

end
然后:

Book.has_preface.has_introduction

这似乎很好。唯一的问题是我更喜欢一个命名的\u范围,因为这样我可以将它与其他范围链接在一起。我将继续调查这似乎很好。唯一的问题是我更喜欢一个命名的\u范围,因为这样我可以将它与其他范围链接在一起。如果有点慢慢来。添加一些索引有帮助。是的,PostgreSQL支持子查询。它比MySQL更早得到支持,所以它也在这方面发挥作用。这非常好,如果稍微慢一点的话。添加一些索引有帮助。是的,PostgreSQL支持子查询。它比MySQL更早得到支持,所以它也在这方面发挥作用。更整洁的方法是st::conditions=>{:chapters=>{:name=>chapter\u names}},但我也喜欢:conditions=>[“chapters.chapter\u names IN(?),“chapters\u names IN(?”,chapter\u names]最简洁的方式是::conditions=>{:chapters=>{:name=>chapter\u names},但我也喜欢:conditions=>[“chapters.chapter\u names IN(?),chapter\u names]