I'm working on a system where a User
can be associated with another entity, a Wedding
, in multiple ways through an Attendance
model using user_id
, wedding_id
and role
information. With help from this question, I sort of found my way of replacing :conditions
with a Rails 4-style association. My associations are now these:
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
Not as straightforward as I wanted, but apparently correct. Or not, because User.first.weddings
, for example, raises the following error, even though WeddingAttendance.find_by_role(:spouse)
returns a correct result set:
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>'
I think you need to include a
source:
configuration option on yourhas_many through:
associations. (You've correctly usedclass_name
to identify the class at the other end but you need a little more than that).From the rails guide on associations:
Because your associations are called
marriages
,invitations
andceremonies
thehas_many through:
is looking for associations onWeddingAttendance
calledmarriage
,invitation
andceremony
to follow to get theWedding
instance at the other end of the association.If you add a
source: :wedding
to yourthrough
associations onUser
and asource: :user
to yourthrough
associations onWedding
active record will be able to identify the associations it should follow.