Search code examples
ruby-on-railsmongodbmongoidnomethoderror

Updating a document that has both belongs_to and has_many associations


I'm having trouble with my Rails/Mongoid app whenever I'm updating my documents.

I have three collections: owners, vessels and modifications.

class Owner
    include Mongoid::Document
    has_many :vessels
    field :name, type: String
    field :uprn, type: String
end

class Vessel
    include Mongoid::Document   
    belongs_to :owner
    has_many :modifications
    field :name, type: String
    attr_accessor :uprn
end

class Modification
    include Mongoid::Document   
    belongs_to :vessel  
    field :change_description, type: String
end

The idea is that each owner owns several vessels (there's a has_many, belongs_to relationship going on) and that there are several modifications which were done on each vessel (again, has_many, belongs_to relationship).

Creating owners, vessels and changes works just fine. When I try to update an owner, it works. If I try to update a modification, it also works. However, the moment I try to update the vessel that belongs to an owner and has some modifications done on it, I'm getting this error:

NoMethodError in OwnersController#update

undefined method `values' for # Mongoid::Criteria:0xb50d49d0

Here's the code that throws this error. Besides just modifying the data stored in the document, it also checks if the owner's changed (that's where the uprn field comes in) and alters the owner_id accordingly.

def update
    @vessel = Vessel.find(params[:id])
    @owner = Owner.find_by(uprn: params[:vessel][:uprn])
    if @owner.present?
        @vessel.owner_id = @owner.id
        if @vessel.update(vessel_params)
            redirect_to @vessel
        else
            render 'edit'
        end
    else
        @vessel.errors[:base] << "There is no owner with the UPRN entered."
        render 'edit'
    end
end

Note that this only happens when there's a 1-n association between the two. If there's just one modification per vessel (so a has_one, belongs_to association) it works just fine. Same deal if I try to embed - 1-1 embeds update fine, 1-n embeds report the same error. It also works fine if there's just the vessel and its modifications (no association with the owner). The moment vessel is associated with both the owner and its modifications, this thing happens.

I'm using Ruby 1.9.3, Rails 4.2.1, Mongo 2.6.1 and Mongoid 4.0.2.


Solution

  • Apparently the way to fix this is to remove the has_many :vessels from Owner and has_many: modifications from Vessel, so that the resulting code looks like:

    class Owner
        include Mongoid::Document
        field :name, type: String
        field :uprn, type: String
    end
    
    class Vessel
        include Mongoid::Document   
        belongs_to :owner
        field :name, type: String
        attr_accessor :uprn
    end
    
    class Modification
        include Mongoid::Document   
        belongs_to :vessel  
        field :change_description, type: String
    end
    

    After removing these two lines, the app works just fine.