Mongoid has_many and multiple belongs_to association - ruby-on-rails

I have model relationships like so:
class User
include Mongoid.Document
has_many :favorite_shows
end
class FavoriteShow
include Mongoid.Document
belongs_to :user
belongs_to :show
end
class Show
include Mongoid.Document
has_many :favorite_shows
end
FavoriteShow is a join table between users and shows with both the user_id and show_id as foreign keys. I keep getting the following error despite the fact that these foreign keys already exist:
Problem:
When adding a(n) Show to User#favorite_shows, Mongoid could not determine the inverse foreign key to set. The attempted key was 'user_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
Now I've tried adding both inverse_of: nil to the associations, as well as the following with no luck:
class User
include Mongoid.Document
has_many :favorite_shows, class_name: "FavoriteShow", inverse_of: :user
end
class FavoriteShow
include Mongoid.Document
belongs_to :user, class_name: "User", inverse_of: :favorite_shows
belongs_to :show, class_name: "Show", inverse_of: :favorite_shows
end
class Show
include Mongoid.Document
has_many :favorite_shows, class_name: "FavoriteShow", inverse_of: :favorite_shows
end
I have these relationships working perfectly in ActiveRecord, but when switching over to Mongoid, I'm still unclear how the exact relationship is supposed to be translated. Any help would be really appreciated!

When using a document based database such as MongoDB you don't have a need for join tables like you would with a relational database. I suggest a structure like the one below:
class User
include Mongoid::Document
include Mongoid::Timestamps
has_and_belongs_to_many :favorite_shows, class_name: "Show", inverse_of: :users
end
class Show
include Mongoid::Document
include Mongoid::Timestamps
has_and_belongs_to_many :users, class_name: "User", inverse_of: :favorite_shows
end

Related

Complex association topic in Rails / mongoid with inverse foreign key

Having a problem getting associations right. In my model I have users and requests. A request has an owner and many participants. A user has many requests and many participations.
I tried to model it like this:
class User
include Mongoid::Document
has_many :requests, inverse_of: :owner
has_many :participations, class_name: 'Request', inverse_of: :participants
...
class Request
include Mongoid::Document
belongs_to :owner, class_name: 'User', inverse_of: :requests
has_many :participants, class_name: 'User', inverse_of: :participations
...
When I try to set a participation by calling
#request.participants << current_user
I get the following error:
message: When adding a(n) User to Request#participants, Mongoid could
not determine the inverse foreign key to set. The attempted key was
'participations_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 get it, I have all inverse_of set, what am I doing wrong?

Ruby on rails & mongoid - relation management belongs_to, has_many

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.
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

Using foreign_key in rails associations has_many

Could somebody explain me is my code correct.
I'm trying to get foreign_key option in rails associations.
I have 2 models:
Book and Author
Book db schema:
name
user_id
Author db schema:
name
My models:
class Author < ApplicationRecord
has_many :books, foreign_key: :user_id
end
class Book < ApplicationRecord
belongs_to :author, foreign_key: :user_id
end
Here I don't understand why we should define foreign_key in both models. Is it necessarily?
If you have used the table and column names that Rails expects, then you do not need to explicitly define the foreign_key. In your case, if the foreign key column was named author_id, then you could get by quite simply:
class Author < ApplicationRecord
has_many :books
end
class Book < ApplicationRecord
belongs_to :author
end
However, in your case, the foreign key column is not named according to what Rails expects, so you have needed to explicitly define the foreign key column name. That's fine, but it does make a little more work for you.
In cases where you have explicitly defined the foreign key, you should define it for both associations. Your has_many association will not work without it.
In addition, you should define the inverse association:
class Author < ApplicationRecord
has_many :books, foreign_key: :user_id, inverse_of: :author
end
class Book < ApplicationRecord
belongs_to :author, foreign_key: :user_id, inverse_of: :books
end
Defining the inverse_of can cause ActiveRecord to make fewer queries, and gets rid of a few surprise behaviors. For an explanation of inverse_of, see Exploring the :inverse_of Option on Rails Model Associations by Ryan Stenberg

Mongoid:4.x how to have array of ids as a 1-N reference?

I have two classes
class Round
include Mongoid::Document
include Mongoid::Attributes::Dynamic
has_many :users
end
class User
include Mongoid::Document
include Mongoid::Attributes::Dynamic
belongs_to :round
end
This all works fine, but what I want to have is two methods on the Round model
good_users and bad_users, both is a relation to the User class. I want to reuse the user class, but have a distinct method access.
I understand that the classic model is using a field on user, to associate it with round, so user has a round_id field in the database. but I would be ok with a setup where. the Round class has two fields with the ids of the users as an array, stored in them.
Is this something I can achieve out of the box with mongoid?
This will create two columns in users, for the two relations.
round.rb
has_many :good_users, class_name: 'User', inverse_of: :good_in_round
has_many :bad_users, class_name: 'User', inverse_of: :bad_in_round
user.rb
belongs_to :good_in_round, class_name: 'Round', inverse_of: :good_users
belongs_to :bad_in_round, class_name: 'Round', inverse_of: :bad_users
Mongoid stores the related object ids as an Array in many to many relations. So you could also use that here
round.rb
has_and_belongs_to_many :good_users, class_name: 'User', inverse_of: :good_in_round
has_and_belongs_to_many :bad_users, class_name: 'User', inverse_of: :bad_in_round

Mongoid self reference collection has_many not working

Can't work out why this is not working
class User
include Mongoid::Document
class Student < User
include Mongoid::Document
....
has_one :parent , class_name: "Parent", inverse_of: :children
class Parent < User
include Mongoid::Document
....
has_many :children, class_name: "Student", inverse_of: :parent
When I try to setup the parent/child relationship via
jane = Student.create!(name: "Jane")
janesParent = Parent.new(name: "Jenny")
janesParent.children.push(jane)
janesParent.save!
I get this error
When adding a(n) Student to Parent#children, Mongoid could not determine the
inverse foreign key to set. The attempted key was 'parent_id'.
What have I done wrong?
P.S I don't want to embed these want to store the id's if applicable types.
If it is 1-N relation, change Student model relation to
belongs_to :parent, class_name: "Parent", inverse_of: :children
Have you tried and has_and_belongs_to_many relation ?

Resources