Mongoid self reference collection has_many not working - ruby-on-rails

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 ?

Related

Rails - Has many on model with multiple references

I have a model CompanyIntro which has two references to a Company:
class CompanyIntro < ApplicationRecord
belongs_to :company_one, class_name: "Company", foreign_key: "company_one_id"
belongs_to :company_two, class_name: "Company", foreign_key: "company_two_id"
...
I would like to do something like:
class Company < ApplicationRecord
has_many :company_intros, class_name: 'CompanyIntro', foreign_key: 'company_one_id'
has_many :company_intros, class_name: 'CompanyIntro', foreign_key: 'company_two_id'
...
But this is not valid
In my Company model, how to I create a has_many for both foreign keys? I am using Rails 6 which dos not allow custom sql for has_many (afaik). I also do not want to write a custom company_intros method on the Company model as I'm using another gem which looks for my has_many relationships.
You can't define has_many assocations where the foreign key is one of two columns. Its just not supported by ActiveRecord as the feature would add tons of complexity.
Using the same name for two assocations also just overwrites the previous assocation. If you want to have a single assocation here you need to add a join table.
class Company < ApplicationRecord
has_many :company_intro_participations
has_many :company_intros, through: :company_intro_participations
end
# for lack of a better name
class CompanyIntroParticipation < ApplicationRecord
belongs_to :company
belongs_to :company_intro
end
class CompanyIntro < ApplicationRecord
has_many :company_intro_participations
has_many :companies, through: :company_intro_participations
end
The alternative is creating a method which joins on company_one_id = companies.id OR company_two_id = companies.id but you will not be able to use that in the same way as an association when it comes to stuff like eager loading.

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?

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

Is there a way to specify an association_foreign_key for a belongs_to relation?

I have a model that uses a belongs_to relation. I want to be able to specify both the foreign_key and association_foreign_key values. However, I can only specify the foreign_key value for a belongs_to relation (http://guides.rubyonrails.org/association_basics.html#belongs-to-association-reference) Is there a way to solve this problem?
Here is my example:
I have a Client model. Its location_id key has to belong to the Region model, where ids are referred to by place_id. What I'd like to do is:
class ClientId < ActiveRecord::Base
belongs_to :region, foreign_key: 'location_id', association_foreign_key: 'place_id'
However, I cannot specify the association_foreign_key here...
The association doesn't need to be declared both ways in the same model. You have to declare:
has_one/many in the other related model.
class Client < ActiveRecord::Base
belongs_to :region, foreign_key: 'location_id'
class Region < ActiveRecord::Base
has_many :clients, foreign_key: 'place_id'

Mongoid has_many and multiple belongs_to association

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

Resources