2

I have an issue with mongoid / rails relations, I know that there are a lot of topics with this kind of issue, but I don't find any that help me .. I have these models :

class Project
  include Mongoid::Document

  belongs_to :owner, :class_name => 'User', inverse_of: :projects
  has_many :members
end

class Member
  include Mongoid::Document

  belongs_to :project, inverse_of: :members
  belongs_to :user
end

class User
  include Mongoid::Document

  has_many :projects, inverse_of: :user

end

When I try to record an user as a member, I have this error :

Mongoid::Errors::InverseNotFound (
message:
  When adding a(n) User to Project#members, Mongoid could not determine the inverse foreign key to set. The attempted key was 'project_id'.
summary:
  When adding a document to a relation, Mongoid attempts to link the newly added document to the base of the relation in memory, as well as set the foreign key to link them on the database side. In this case Mongoid could not determine what the inverse foreign key was.
resolution:
  If an inverse is not required, like a belongs_to or has_and_belongs_to_many, ensure that :inverse_of => nil is set on the relation. If the inverse is needed, most likely the inverse cannot be figured out from the names of the relations and you will need to explicitly tell Mongoid on the relation what the inverse is.

 Example:
   class Lush
     include Mongoid::Document
     has_one :whiskey, class_name: "Drink", inverse_of: :alcoholic
   end

   class Drink
     include Mongoid::Document
     belongs_to :alcoholic, class_name: "Lush", inverse_of: :whiskey
   end):

I don't understand why, I think something is wrong with the relations, and the inverses relation but I don't know how to fix this issue.

Antonin Mrchd
  • 656
  • 3
  • 9
  • 31

1 Answers1

2
class Project
  include Mongoid::Document

  belongs_to :owner, :class_name => 'User', inverse_of: :projects
  has_many :members
  has_many :users
end

But I don't think your modeling actually will accomplish what you want. In a relational database you would use an indirect association with a join table:

class User < ActiveRecord::Base
  has_many :memberships 
  has_many :projects, through: :memberships
end

class Membership < ActiveRecord::Base
  belongs_to :user
  belongs_to :project
end

class Project < ActiveRecord::Base
  has_many :memberships 
  has_many :members, through: :memberships, 
                     source: :user
end 

But over in Mongoland there are no joins so we we need to use a different approach which is embedding:

class Project
  # ...
  embeds_many :users
end

class User 
  # ...
  embedded_in :project
end

Or you can fake an indirect association if you need to be able to add data to the intermediate model:

class Project
  # ...
  embeds_many :memberships

  def members
    Patient.in(id: memberships.pluck(:user_id))
  end
end

class Membership
  # ...
  field :approved, type: Boolean
  belongs_to :user
  embedded_in :project
end

class User 
  # ...
  def projects
    Project.where("members.user_id" => id).all
  end
end
max
  • 96,212
  • 14
  • 104
  • 165
  • Thank you for the answer ! I think that embed is a good idea, but how can I manage it for user which is owner and users which are just members ? – Antonin Mrchd Apr 28 '17 at 12:59
  • I'm not completely sure but I think you can setup embeds with aliasing by using the class option `embeds_many :members, class_name: 'User'`, `embeds_one :owner, class_name: 'User'`. But I haven't used Mongoid in quite a while. – max Apr 28 '17 at 13:08
  • http://stackoverflow.com/questions/7000605/how-to-implement-has-many-through-relationships-with-mongoid-and-mongodb – max Apr 28 '17 at 13:09
  • I'm not sure that embed it a good idea finally, because I don't want that my users depend of project, I want a relation between project and user – Antonin Mrchd Apr 28 '17 at 13:19
  • 1
    See my edit how you can work around the limitation be embedding a "join" document. I don't have mongodb on this machine so I have not tested it though. – max Apr 28 '17 at 13:24
  • You think that I can't improve that with `has_many` / `belongs_to` ? – Antonin Mrchd Apr 28 '17 at 13:25
  • No - the mongoid associations don't really support indirect assocations. I think that its by design since the lack of joins can lead to very slow queries. – max Apr 28 '17 at 13:27
  • You can use `Project has_and_belongs_to_many :users`, `User has_and_belongs_to_many :projects` but that will not let you use any metadata that describes the association. https://mongoid.github.io/old/en/mongoid/docs/relations.html#has_and_belongs_to_many – max Apr 28 '17 at 13:31
  • Ok I understand, it's really difficult to understand how to implement what I want .. – Antonin Mrchd Apr 28 '17 at 13:35
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/142922/discussion-between-antonin-mrchd-and-max). – Antonin Mrchd Apr 28 '17 at 13:42