In the given case a User may:
- invite many invitees (has_many :invitations)
- accept one invitation (has_one :invitation)
According to http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association a has_many :through association should allow me to use a shortcut like the one in the following functional test.
However, it fails with the error noted in the comment.
snippet from functional test:
assert_difference('Invitation.count') do # WORKS
post :create, :user => { :email => invitee_email, :password => "1password" }
end
@invitee = User.find_by_email(invitee_email)
@invitation = Invitation.find_by_issuer_id_and_invitee_id(@issuer.id, @invitee.id)
assert @invitation.valid? # WORKS
assert_present @invitation.issuer # WORKS
assert_present @invitation.invitee # WORKS
# TODO: repair
assert_present @issuer.invitees # FAILS with "[] is blank"
assert_present @invitee.issuer # FAILS with "nil is blank"
snippet from the method under test:
@issuer.create_invitation(:invitee => @invitee, :accepted_at => Time.now)
# tested as well - also fails the test:
# Invitation.create!(:issuer => @issuer, :invitee => @invitee, :accepted_at => Time.now)
relevant parts of invitation.rb:
belongs_to :issuer, :class_name => "User"
belongs_to :invitee, :class_name => "User"
validates_presence_of :issuer
validates_presence_of :invitee
relevant parts of user.rb:
has_many :invitations, :foreign_key => 'invitee_id', :dependent => :destroy
has_many :invitees, :through => :invitations
has_one :invitation, :foreign_key => 'issuer_id', :dependent => :destroy
has_one :issuer, :through => :invitation
Now I wonder:
- What is the correct ‘shortcut’?
- Are my models set up correctly in the first place?
I guess you’re trying to design the logic like this:
User 1 can invite user 2, user 3, then the data is:
Suppose user 2 accepted the invitation, the data become:
What if user 2 invites user 1 later? If my guess is right, your design wouldn’t work.
I think you also have some misunderstanding about the associations.
has_many :invitations, :foreign_key => 'invitee_id'means a user, as an invitee, received many invitations. Andhas_one :invitation, :foreign_key => 'issuer_id'means a user, as an issuer, sent an invitation.