mongoid self to self relationship? - ruby

Hi guys I have a class like below for a crawler model:
class Link
include Mongoid::Document
include Mongoid::Timestamps
field :url, type: String
field :links, type: String
index :url
has_many :pages
end
where a link repent a URL and they have many inbound/outbound connections, I would like to have it working, so:
a_link.links # => gives a list of outbound link objects.
How would you do it with mongoid?

You can set up a many-many association using has_and_belongs_to_many on each side of the relationship.
class Link
include Mongoid::Document
has_and_belongs_to_many :links, :class_name => 'Link', :inverse_of => :inbound_links
has_and_belongs_to_many :inbound_links, :class_name => 'Link', :inverse_of => :links
end
As the association is to and from the same class in this case you need to give mongoid a little help with the class_name and inverse_of because it can't infer this from the association name.

a bit cleaner way to archive this using many-many associations
class Link
include Mongoid::Document
has_and_belongs_to_many :links, class_name: 'Link', inverse_of: :links
end

Related

Mongoid: Referencing Same Model More Than Once Through has_many

I'd like to be able to reference a model (a has_many relationship) more than once in the same model. For example, given the following models:
class MyModel
include Mongoid::Document
field :name, type: String
has_many :main_efforts, :class_name => 'Effort', as: :effortable, dependent: :delete, autosave: true
has_many :secondary_efforts, :class_name => 'Effort', as: :effortable, dependent: :delete, autosave: true
validates_presence_of :name
end
class Effort
include Mongoid::Document
field :name, type: String
belongs_to :effortable, polymorphic: true
validates_presence_of :name
end
As you can see, the Effort model is referenced twice. Originally, my Effort model wasn't polymorphic, but it seemed Mongoid was unable to determine which collection (main_efforts or secondary_efforts) the effort belonged to. As such, I made it polymorphic. After making it polymorphic, however, my main_efforts and secondary_efforts fields are always an empty array.
What is the proper way to reference a polymorphic model more than once in the same model (assuming a polymorphic model is necessary)?
Figured it out:
class MyModel
include Mongoid::Document
field :name, type: String
has_many :main_efforts, :class_name => 'Effort', dependent: :delete, autosave: true, :inverse_of => :main_effort
has_many :secondary_efforts, :class_name => 'Effort', dependent: :delete, autosave: true, :inverse_of => :secondary_effort
validates_presence_of :name
end
class Effort
include Mongoid::Document
field :name, type: String
belongs_to :main_effort, :class_name => 'Conop', :inverse_of => :main_efforts
belongs_to :secondary_effort, :class_name => 'Conop', :inverse_of => :secondary_efforts
validates_presence_of :name
end

Trying to figure out what kind of relationships I should use

Sinatra, Mongoid 3
There 4 models: User, Book, FavoriteBooks, ReadBooks, NewBooks. Each user has their list of the favourites, read and new books. A book belongs to a list. But it's also possible to request an information about any book which means books should not be embedded into FavoriteBooks, ReadBooks, NewBooks.
The part of the scheme:
class Book
include Mongoid::Document
belongs_to :favourite_books
belongs_to :read_books
belongs_to :new_books
end
class FavoriteBook
include Mongoid::Document
has_many :books
end
#.... the same for ReadBooks and NewBooks
class User
include Mongoid::Document
# what else?
end
It seems like I missed something.
What should I do to make a user "contain" the lists of FavoriteBooks, ReadBooks, NewBooks? Should I use one-to-one relationship?
I think you should rethink your modeling. IMHO it should be book and user as models, and the favorite_books, read_books and new_books should all be relationhips like so:
class User
include Mongoid::Document
has_many :favorite_books
has_many :read_books
has_many :new_books
has_many :books, :through => :favorite_books
has_many :books, :through => :read_books
has_many :books, :through => :new_books
end
class Book
include Mongoid::Document
has_many :favorite_books
has_many :read_books
has_many :new_books
has_many :users, :through => :favorite_books
has_many :users, :through => :read_books
has_many :users, :through => :new_books
end
class FavoriteBook
include Mongoid::Document
belongs_to :books
belongs_to :users
end
#.... the same for ReadBooks and NewBooks
I think this should be a better approach. =)

Mongoid not saving nested_attributes for 'belongs_to' in a 1:1 relationship

I have two model's Contact, and User. When I create a new user I am trying to create the contact at the same time. But It is not getting created for some reason. Any ideas on why?
class Contact
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::MultiParameterAttributes
include Mongoid::Paranoia
include Mongoid::Versioning
# Attr.
attr_accessible :first_name, :last_name, :birthday, :email_addresses_attributes, :phone_numbers_attributes, :relationships_attributes, :addresses_attributes
#Relationships
belongs_to :firm, validate: true
has_one :user # contact information for user
has_many :relationships, autosave: true
has_many :clients
has_many :notes, dependent: :destroy
...
end
class User
include Mongoid::Document
include ActiveModel::SecurePassword
include Mongoid::Timestamps
# Attr.
attr_accessible :contact_id, :contact_attributes, :password, :password_confirmation, :google_tokens
#Relationships
belongs_to :firm, validate: true
belongs_to :contact, validate: true, autosave: true
has_one :user_type
embeds_many :histories
# Nested Attrs
accepts_nested_attributes_for :contact
...
end
accepts_nested_attributes_for is done on the owner object to allow you to set attributes of objects that belong it.
In your case, User belongs to (or is nested under) Contact. You would have to do accepts_nested_attributes_for :user in your Contact model.
You could switch it around so that User has_one :contact and Contact belongs_to :user. This requires you give Contact a user_id field.

Change name of mongoid relations (embeds_...,belongs_to,has_...)

When you have a relation such as embeds_many :album_items which relates to the AlbumItem model. How can I have it stored in just items. I tried embeds_many :album_items, :as => :items and embeds_many :items, :class_name => AlbumItem. Neither worked.
How can I go about renaming the relation?
Thanks
Does this work(assuming your parent model name is Album)?
In Album:
embeds_many :items, :class_name => "AlbumItem", :inverse_of => :album
and in AlbumItem:
embedded_in :album, :class_name => "Album", :inverse_of => :items

Mongoid documents inside namespaces

How can I deal with mongoid documents inside namespaces?
I have two mongoid documents as follow:
module A
module B
Class User
include Mongoid::Document
field :name, type: String
has_and_belongs_to_many :groups, :cascade => :nullify, :class_name => 'A::B::Group'
end
Class Group
include Mongoid::Document
field :name, type: String
has_and_belongs_to_many :users, :cascade => :nullify, :class_name => 'A::B::User'
end
end
end
The problem raises when I try to delete a group that contains an user:
u = User.create()
g = Group.create()
g.users << u
at this point u.groups_ids contains the _id of the group g, but when I perform:
g.destroy
It complains of a missing method called 'A/B/groups_ids' in class 'User'.
It is trying to remove the reference of g inside u, but it fails to find the correct namespace...
If I remove the namespaces A and B and the :class_name options everything works fine.
Which is the correct way (if any) to handle namespaces in this scenario?
the solution is to add a :foreign_key => 'A/B/groups_ids':
Class User
include Mongoid::Document
field :name, type: String
has_and_belongs_to_many :groups, :cascade => :nullify, :class_name => 'A::B::Group', :foreign_key => 'A/B/group_ids'
end
Class Group
include Mongoid::Document
field :name, type: String
has_and_belongs_to_many :users, :cascade => :nullify, :class_name => 'A::B::User', :foreign_key => 'A/B/user_ids'
end

Resources