ActiveRecord,Rails 4:has_many:通过scoped条件失败

时间:2015-06-08 14:00:42

标签: ruby-on-rails ruby-on-rails-4 activerecord

我正在开发一个系统,User可以通过Wedding模型使用Attendance user_id以多种方式与另一个实体wedding_id相关联。 {1}}和role信息。在this问题的帮助下,我找到了用Rails 4风格关联替换:conditions的方法。我的协会现在是:

User

has_many  :wedding_attendances
has_many  :weddings,
          through: :wedding_attendances
has_many  :marriages,
          -> { WeddingAttendance.find_by_role(:spouse) },
          through: :wedding_attendances,
          class_name: 'Wedding'
has_many  :invitations,
          -> { WeddingAttendance.find_by_role(:invitee) },
          through: :wedding_attendances,
          class_name: 'Wedding'
has_many  :ceremonies,
          -> { WeddingAttendance.find_by_role(:worker) },
          through: :wedding_attendances,
          class_name: 'Wedding'

Wedding

has_many  :wedding_attendances
has_many  :attendees,
          through: :wedding_attendances,
          class_name: 'User'
has_many  :spouses,
          -> { WeddingAttendance.find_by_role(:spouse) },
          through: :wedding_attendances,
          class_name: 'User'
has_many  :invitees,
          -> { WeddingAttendance.find_by_role(:invitee) },
          class_name: 'User',
          through: :wedding_attendances
has_many  :workers,
          -> { WeddingAttendance.find_by_role(:worker) },
          class_name: 'User',
          through: :wedding_attendances

WeddingAttendance

belongs_to :wedding
belongs_to :user

class << self
  def roles
    {
      spouse: 0,
      invitee: 1,
      worker: 2
    }
  end

  def find_by_role role
    if role.class == Symbol
      where(role: roles[role])
    else
      where(role: role)
    end
  end
end

不像我想的那么简单,但显然是正确的。或者不是,因为User.first.weddings会引发以下错误,即使WeddingAttendance.find_by_role(:spouse)返回正确的结果集:

NoMethodError: undefined method `to_sym' for nil:NilClass
        from c:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/reflection.rb:100:in `_reflect_on_association'
        from c:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/reflection.rb:537:in `source_reflection'
        from c:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/reflection.rb:697:in `check_validity!'
        from c:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/associations/association.rb:25:in `initialize'
        from c:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/associations/has_many_through_association.rb:9:in `initialize'
        from c:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/associations.rb:155:in `new'
        from c:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/associations.rb:155:in `association'
        from c:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/associations/builder/association.rb:110:in `marriages'
        from (irb):51
        from c:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/console.rb:90:in `start'
        from c:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/console.rb:9:in `start'
        from c:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:69:in `console'
        from c:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
        from c:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands.rb:17:in `<top (required)>'
        from bin/rails:4:in `require'
        from bin/rails:4:in `<main>'

2 个答案:

答案 0 :(得分:2)

正如@Shadwell所提到的,您需要将sourcehas_many :through一起使用。

但是我只想创建自己的方法:

class User

  has_many  :wedding_attendances
  has_many  :weddings,
          through: :wedding_attendances

  def self.marriages
    self.weddings.where('wedding_attendances.role = ?', WeddingAttendance.find_by_role(:spouse))
  end
end

这只是一个偏好,但我觉得它更容易阅读。

答案 1 :(得分:1)

我认为您需要在source:关联中包含has_many through:配置选项。 (您已正确使用class_name来识别另一端的课程,但您需要的更多一点。)

来自rails guide on associations

  

:source选项指定has_many:through关联的源关联名称。如果无法从关联名称自动推断源关联的名称,则只需使用此选项。

由于您的关联被称为marriagesinvitationsceremonieshas_many through:正在寻找名为WeddingAttendance的{​​{1}}上的关联,{{ 1}}和marriage,以便在关联的另一端获取invitation实例。

如果您在ceremony上的Wedding个关联添加了source: :wedding,并且through Usersource: :user关联through活动记录将Wedding能够识别它应该遵循的关联。