Ruby on rails Rails 4中联接表的默认范围

Ruby on rails Rails 4中联接表的默认范围,ruby-on-rails,activerecord,ruby-on-rails-4,Ruby On Rails,Activerecord,Ruby On Rails 4,我必须只选择属于ctype=TV频道的节目时间表 但我得到了这个错误: 程序(型号) Schema.rb create_table "channels", force: true do |t| t.string "site" t.string "name" t.string "icon" t.string "ctype" t.string "country" t.string "lang" t.integer

我必须只选择属于ctype=TV频道的节目时间表

但我得到了这个错误:

程序(型号)

Schema.rb

  create_table "channels", force: true do |t|
    t.string   "site"
    t.string   "name"
    t.string   "icon"
    t.string   "ctype"
    t.string   "country"
    t.string   "lang"
    t.integer  "ordertab"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.boolean  "homepage"
  end

      create_table "programs", force: true do |t|
    t.string "country"
    t.string "title"
    t.text   "subtitle"
    t.text   "description"
    t.float  "official_rating", default: 0.0
    t.float  "rating",          default: 0.0
    t.string "ptype"
    t.string "year"
    t.string "imdb"
    t.string "tmdb"
    t.string "tvdb"
    t.string "wiki"
    t.string "poster"
    t.string "backdrop"
    t.string "trailer"
    t.float  "popularity",      default: 0.0
  end

  create_table "program_schedules", force: true do |t|
    t.integer  "program_id"
    t.datetime "start"
    t.datetime "stop"
    t.integer  "channel_id"
  end

您的
includes
应该包含关联,而不是符号形式的表名。尝试将默认范围更改为以下内容:

default_scope { includes(:channel).where("channels.ctype NOT IN (?)", ['tv']) }

我将此作为一个“答案”发布,但它只是一个评论。我这样做是为了更好地说明我的解释。如果/何时需要我删除此非答案,请通知我。

我试图复制您的问题,但我无法使用您发布的查询和
default\u scope
。最后,问题是您的
左外部联接
条件引用了一个尚未联接的表。即使在查询的后面加入了它,解释器也看不到前面很远的地方

这是我所指的部分(为可读性而格式化):

此外,我从未见过将
.where
附加到连接条件。如果您使用该方法,ActiveRecord应该将传递给
.where
方法的任何内容放置在
where
子句中,正如您所期望的那样。出于某种原因,它显然是将您的条件作为
条件附加到
左外部联接

我所知道的将条件附加到联接的唯一方法是使用
.joins
方法,如下所示:

...joins(" AND program_schedules.channels.ctype NOT IN (?)", ['tv'])
这确实会导致这样一个查询(为了简洁起见被截断):

此外,在错误消息状态下生成的查询

(channels.ctype NOT IN ...)
作为失败的连接条件,而您的
.where
条件声明

program_schedules.channels.ctype
在您的问题中,我看不到其他任何地方您在错误消息中编写了类似于查询部分的内容。所以,我们似乎并没有看到所有的东西


我们似乎仍然缺少一些信息。你真的有可能有像我上面写的那样的
.join
条件吗?在其他型号中是否有其他的
默认\u作用域可以这样做?

我在研究应用程序中看到的类似问题时,偶然发现了这个堆栈溢出问题。我认为将
default\u作用域
联接
一起使用是不正确的

我把你的代码归结为一个简单的会失败的东西,运行了
Program.joins(:Program\u schedules).to\u sql
,得到了以下sql:

SELECT "programs".*
FROM "programs"
INNER JOIN "program_schedules" ON
  "program_schedules"."program_id" = "programs"."id" AND 
  ("channels"."ctype" NOT IN ('tv'))
问题不在于它还没有加入
频道
,而是它将永远不会加入频道。
default\u范围
中的where子句被固定到
内部联接
,但联接被丢弃

class Channel < ActiveRecord::Base
  has_many :programs
end

class Program < ActiveRecord::Base
  has_many :program_schedules
end

class ProgramSchedule < ActiveRecord::Base
  belongs_to :program
  belongs_to :channel

  default_scope { joins(:channel).where.not(channels: { ctype: ['tv'] }) }
end

ActiveRecord::Schema.define(version: 20140331124327) do
  create_table "channels", force: true do |t|
    t.string   "site"
    t.string   "name"
    t.string   "icon"
    t.string   "ctype"
    t.string   "country"
    t.string   "lang"
    t.integer  "ordertab"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.boolean  "homepage"
  end

  create_table "programs", force: true do |t|
    t.string "country"
    t.string "title"
    t.text   "subtitle"
    t.text   "description"
    t.float  "official_rating", default: 0.0
    t.float  "rating",          default: 0.0
    t.string "ptype"
    t.string "year"
    t.string "imdb"
    t.string "tmdb"
    t.string "tvdb"
    t.string "wiki"
    t.string "poster"
    t.string "backdrop"
    t.string "trailer"
    t.float  "popularity",      default: 0.0
  end

  create_table "program_schedules", force: true do |t|
    t.integer  "program_id"
    t.datetime "start"
    t.datetime "stop"
    t.integer  "channel_id"
  end
end
class频道
请查看:

在activerecord-4.1.7/lib/active_record/scoping/default.rb中,有一条注释,下面是:

# If you need to do more complex things with a default scope, you can
# alternatively define it as a class method:
#
class Article < ActiveRecord::Base
  def self.default_scope
    # Should return a scope, you can call 'super' here etc.
  end
end
#如果需要使用默认范围执行更复杂的操作,可以
#或者将其定义为类方法:
#
类文章

这对我很有效。

尝试过。我得到PG::UndefinedTable:错误:从表“channels”@user1028100 Add
的子句条目中丢失。也加入(:channel)
.includes
将导致第二次查询以快速加载关联,但是第一次查询不会直观地生成
内部联接。在尝试引用
WHERE
子句中已加载但未联接的表之前,这通常不是问题。同样的事情。我尝试过:“default_scope{joins(:channel).其中(“channels.ctype NOT IN(?),['tv'])}”和“default_scope{joins(:channel).includes(:channel).其中(“channels.ctype NOT IN(?),['tv'])}@user1028100,看起来你发布的查询屏幕截图不是所讨论的ActiveRecord查询的结果。您能发布生成该错误的确切查询吗?
LEFT OUTER JOIN "program_schedules" ON ... AND program_schedules.channels......
(channels.ctype NOT IN ...)
program_schedules.channels.ctype
SELECT "programs".*
FROM "programs"
INNER JOIN "program_schedules" ON
  "program_schedules"."program_id" = "programs"."id" AND 
  ("channels"."ctype" NOT IN ('tv'))
class Channel < ActiveRecord::Base
  has_many :programs
end

class Program < ActiveRecord::Base
  has_many :program_schedules
end

class ProgramSchedule < ActiveRecord::Base
  belongs_to :program
  belongs_to :channel

  default_scope { joins(:channel).where.not(channels: { ctype: ['tv'] }) }
end

ActiveRecord::Schema.define(version: 20140331124327) do
  create_table "channels", force: true do |t|
    t.string   "site"
    t.string   "name"
    t.string   "icon"
    t.string   "ctype"
    t.string   "country"
    t.string   "lang"
    t.integer  "ordertab"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.boolean  "homepage"
  end

  create_table "programs", force: true do |t|
    t.string "country"
    t.string "title"
    t.text   "subtitle"
    t.text   "description"
    t.float  "official_rating", default: 0.0
    t.float  "rating",          default: 0.0
    t.string "ptype"
    t.string "year"
    t.string "imdb"
    t.string "tmdb"
    t.string "tvdb"
    t.string "wiki"
    t.string "poster"
    t.string "backdrop"
    t.string "trailer"
    t.float  "popularity",      default: 0.0
  end

  create_table "program_schedules", force: true do |t|
    t.integer  "program_id"
    t.datetime "start"
    t.datetime "stop"
    t.integer  "channel_id"
  end
end
# If you need to do more complex things with a default scope, you can
# alternatively define it as a class method:
#
class Article < ActiveRecord::Base
  def self.default_scope
    # Should return a scope, you can call 'super' here etc.
  end
end