0

在我的 rails 应用程序中,我有一个具有复杂 default_scope 的特定模型,并且我试图在一个通过该模型的模型上创建 has_many 关系。不幸的是,我收到了奇怪的错误消息,这似乎是由 :through 模型的默认范围引起的。这是我的设置:

# == Schema Information
#
# Table name: training_classes
#
#  id            :integer         not null, primary key
#  created_at    :datetime        not null
#  updated_at    :datetime        not null
#
class TrainingClass < ActiveRecord::Base
  has_many :meetings, class_name: :ClassMeeting, foreign_key: :class_id, dependent: :destroy, inverse_of: :training_class
  has_many :training_records, foreign_key: :class_id, dependent: :destroy, inverse_of: :training_class

  scope :with_date, joins("
    LEFT OUTER JOIN
      (#{ClassMeeting.earliest_dates.to_sql}) as class_meeting
    ON class_meeting.class_id = training_classes.id
  ")
  default_scope with_date.order('class_meeting.start_time ASC')
end

# == Schema Information
#
# Table name: training_records
#
#  id         :integer         not null, primary key
#  class_id   :integer
#  created_at :datetime        not null
#  updated_at :datetime        not null
#
class TrainingRecord < ActiveRecord::Base
  belongs_to :training_class, foreign_key: :class_id, inverse_of: :training_records
  has_many :attendance_records, inverse_of: :training_record, dependent: :destroy
  has_many :meetings, class_name: :ClassMeeting, through: :training_class # This doesn't work correctly
end

# == Schema Information
#
# Table name: class_meetings
#
#  id         :integer         not null, primary key
#  class_id   :integer
#  start_time :datetime
#  end_time   :datetime
#  created_at :datetime        not null
#  updated_at :datetime        not null
#
class ClassMeeting < ActiveRecord::Base
  belongs_to :training_class, foreign_key: :class_id, inverse_of: :meetings
  has_many :attendance_records, class_name: :AttendanceRecord, foreign_key: :meeting_id, dependent: :destroy
  has_many :training_records, through: :training_class # This doesn't work correctly

  scope :earliest_dates, select('
    class_meetings.id,
    class_meetings.class_id,
    MIN(class_meetings.start_time) as start_time'
  ).group('class_meetings.class_id').order('class_meetings.start_time DESC')
end

请注意,在这些示例中,为简单起见,我删除了代码。我很确定与这三个模型之间的关系相关的所有内容都完好无损。此外,关于这些模型的其他所有内容在我的应用程序中都可以正常工作,只是has_many :x, through: training_class关系不起作用。这是我收到的错误消息:

irb(main):004:0> ClassMeeting.first.training_records
  ClassMeeting Load (0.0ms)  SELECT "class_meetings".* FROM "class_meetings" LIMIT 1
  TrainingRecord Load (0.0ms)  SELECT "training_records".* FROM "training_records" INNER JOIN "training_classes" ON "training_records"."class_id" = "training_classes"."id" WHERE "training_classes"."id" = 1 ORDER BY class_meeting.start_time ASC
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: class_meeting.start_time: SELECT "training_records".* FROM "training_records" INNER JOIN "training_classes" ON "training_records"."class_id" = "training_classes"."id" WHERE "training_classes"."id" = 1 ORDER BY class_meeting.start_time ASC
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/sqlite3-1.3.6-x86-mingw32/lib/sqlite3/database.rb:91:in `initialize'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/sqlite3-1.3.6-x86-mingw32/lib/sqlite3/database.rb:91:in `new'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/sqlite3-1.3.6-x86-mingw32/lib/sqlite3/database.rb:91:in `prepare'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/connection_adapters/sqlite_adapter.rb:246:in `block in exec_query'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/connection_adapters/abstract_adapter.rb:280:in `block in log'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activesupport-3.2.6/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/connection_adapters/abstract_adapter.rb:275:in `log'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/connection_adapters/sqlite_adapter.rb:242:in `exec_query'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/connection_adapters/sqlite_adapter.rb:467:in `select'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/connection_adapters/abstract/database_statements.rb:18:in `select_all'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/connection_adapters/abstract/query_cache.rb:63:in `select_all'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/querying.rb:38:in `block in find_by_sql'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/explain.rb:40:in `logging_query_plan'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/querying.rb:37:in `find_by_sql'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/relation.rb:171:in `exec_queries'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/relation.rb:160:in `block in to_a'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/explain.rb:33:in `logging_query_plan'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/relation.rb:159:in `to_a'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/relation/finder_methods.rb:159:in `all'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/associations/has_many_through_association.rb:173:in `find_target'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/associations/collection_association.rb:333:in `load_target'
        from c:in `load_target'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/associations/collection_proxy.rb:87:in `method_missing'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/railties-3.2.6/lib/rails/commands/console.rb:47:in `start'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/railties-3.2.6/lib/rails/commands/console.rb:8:in `start'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/railties-3.2.6/lib/rails/commands.rb:41:in `<top (required)>'
        from script/rails:6:in `require'

和:

irb(main):006:0> TrainingRecord.first.meetings      
  TrainingRecord Load (0.0ms)  SELECT "training_records".* FROM "training_records" LIMIT 1
  ClassMeeting Load (0.0ms)  SELECT "class_meetings".* FROM "class_meetings" INNER JOIN "training_classes" ON "class_meetings"."class_id" = "training_classes"."id" WHERE "training_classes"."id" = 23 ORDER BY class_meeting.start_time ASC
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: class_meeting.start_time: SELECT "class_meetings".* FROM "class_meetings" INNER JOIN "training_classes" ON "class_meetings"."class_id" = "training_classes"."id" WHERE "training_classes"."id" = 23 ORDER BY class_meeting.start_time ASC
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/sqlite3-1.3.6-x86-mingw32/lib/sqlite3/database.rb:91:in `initialize'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/sqlite3-1.3.6-x86-mingw32/lib/sqlite3/database.rb:91:in `new'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/sqlite3-1.3.6-x86-mingw32/lib/sqlite3/database.rb:91:in `prepare'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/connection_adapters/sqlite_adapter.rb:246:in `block in exec_query'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/connection_adapters/abstract_adapter.rb:280:in `block in log'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activesupport-3.2.6/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/connection_adapters/abstract_adapter.rb:275:in `log'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/connection_adapters/sqlite_adapter.rb:242:in `exec_query'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/connection_adapters/sqlite_adapter.rb:467:in `select'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/connection_adapters/abstract/database_statements.rb:18:in `select_all'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/connection_adapters/abstract/query_cache.rb:63:in `select_all'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/querying.rb:38:in `block in find_by_sql'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/explain.rb:40:in `logging_query_plan'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/querying.rb:37:in `find_by_sql'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/relation.rb:171:in `exec_queries'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/relation.rb:160:in `block in to_a'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/explain.rb:33:in `logging_query_plan'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/relation.rb:159:in `to_a'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/relation/finder_methods.rb:159:in `all'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/associations/has_many_through_association.rb:173:in `find_target'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/associations/collection_association.rb:333:in `load_target'
        from c:in `load_target'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activerecord-3.2.6/lib/active_record/associations/collection_proxy.rb:87:in `method_missing'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/railties-3.2.6/lib/rails/commands/console.rb:47:in `start'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/railties-3.2.6/lib/rails/commands/console.rb:8:in `start'
        from c:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/railties-3.2.6/lib/rails/commands.rb:41:in `<top (required)>'
        from script/rails:6:in `require'
        from script/rails:6:in `<main>'irb(main):007:0>

似乎 :through 关系在其repsective查询中包含了默认范围的order('class_meeting.start_time ASC')一部分。TrainingClass对我来说,这似乎根本不是合理的行为。这是 Rails 的错误吗?我已经能够通过使用 :finder_sql 关系选项使关系正常工作,但这似乎是一个相当尴尬的解决方案。有谁知道我该如何解决这个问题?(也许是一种让关系忽略TrainingClass默认范围的方法?)

4

0 回答 0