ruby-on-railsrubymongoidmongoid5

Mongoid can't save document with a belongs_to/has_many relationship. Circular dependency


I have 2 Mongoid classes:

class Reservation
  include Mongoid::Document
  belongs_to :listing, class_name: 'Listing', inverse_of: 'Reservation'
end

class Listing
  include Mongoid::Document
  has_many :reservations, class_name: 'Reservation', foreign_key: :listing_id
end

If I find the listing by _id and #save! it, there is no error raised

listing = Listing.find(...)
listing.save! #=> true

Then I initialize a new reservation obect:

reservation = Reservation.find_or_initialize_by(params)
reservation.save! #=> error, exptected though, because I didn't set the listing_id yet

Mongoid::Errors::Validations: 
message:
  Validation of Reservation failed.
summary:
  The following errors were found: Listing can't be blank
resolution:
  Try persisting the document with valid data or remove the validations.
from /home/ec2-user/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/bundler/gems/mongoid-71c29a805990/lib/mongoid/persistable.rb:78:in `fail_due_to_validation!'

So I assign the earlier listing's id to the reservation:

reservation.listing_id = listing._id
reservation.listing_id #=> nil

I can't even assign the listing_id field ?!

reservation.listing    #=> returns the associated document no problem though..
reservation.listing.save! #=> error

Mongoid::Errors::Validations: 
message:
  Validation of Listing failed.
summary:
  The following errors were found: Reservations is invalid
resolution:
  Try persisting the document with valid data or remove the validations.
from /home/ec2-user/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/bundler/gems/mongoid-71c29a805990/lib/mongoid/persistable.rb:78:in `fail_due_to_validation!'

Can't save the reservation without a valid listing, Can't save the listing without a valid reservation

WHAT IS THIS?!?!

Please save my day...


Solution

  • You actually have to specify the inverse field in inverse_of, so try with something like:

    class Reservation
      include Mongoid::Document
      belongs_to :listing, class_name: 'Listing', inverse_of: :reservations
    end
    
    class Listing
      include Mongoid::Document
      has_many :reservations, class_name: 'Reservation', inverse_of :listing
    end
    

    I also replaced the foreign_key by inverse_of for the has_many relation, it's easier to let Mongoid guess the foreign key name :)

    Then, check the validations you specified and you did not included in your post, but if you first create a listing you should be able to create a reservation for it without any problem.

    Also, assigning the directly the object is fine too, and often easier, so you can directly write reservation.listing = my_listing