I have the following models
class Track
include Mongoid::Document
field :artist, type: String
field :title, type: String
has_many :subtitles, as: :subtitleset
end
class Subtitle
include Mongoid::Document
field :lines, type: Array
belongs_to :subtitleset, polymorphic: true
end
class User
include Mongoid::Document
field :name, type: String
has_many :subtitles, as: :subtitleset
end
And in my ruby code when I create a new Subtitle I'm pushing it in the appropriate Track and User like this:
Track.find(track_id).subtitles.push(subtitle)
User.find(user_id).subtitles.push(subtitle)
The problem is that it gets pushed only in the User and not in the Track also. But if I remove the second line it gets pushed it the Track. So why isn't working for both?
I get this in the Subtitle document:
"subtitleset_id" : ObjectId( "4e161ba589322812da000002" ),
"subtitleset_type" : "User"
If a subtitle belongs to something, it has an ID pointing to that something. A subtitle cannot belong to two somethings at once. If the belonging is polymorphic, a subtitle can belong to something whose class is not specified - but it still cannot belong to two somethings at once.
You want:
class Track
include Mongoid::Document
field :artist, type: String
field :title, type: String
has_many :subtitles
end
class Subtitle
include Mongoid::Document
field :lines, type: Array
belongs_to :track
belongs_to :user
end
class User
include Mongoid::Document
field :name, type: String
has_many :subtitles
end
And then you will be able to:
Track.find(track_id).subtitles.push(subtitle)
User.find(user_id).subtitles.push(subtitle)
Related
Recently I came across issue I cannot resolve (or google it properly). First, here are the files:
#Counter.rb
class Counter
include Mongoid::Document
embeds_many :pointing, as: :goodvs, store_as: "goodvs"
embeds_many :pointing, as: :badvs, store_as: "badvs"
accepts_nested_attributes_for :pointing
field :name, type: String
field :champId, type: Integer
end
#Pointing.rb
class Pointing
include Mongoid::Document
belongs_to :counter
accepts_nested_attributes_for :counter
field :name, type: String
field :votes, type: Integer
field :lane, type: String
end
Description
I want to nest Pointing class in Counter class double to make structure like this:
{
name: 'sth',
champId: 1,
goodvs: [{
name: 'sthsth'
votes: 1
lane: 'top'
},
{
name: 'sthsth2'
votes: 4
lane: 'bot'
}],
badvs: [{
name: 'sthsth'
votes: 1
lane: 'mid'
}]
}
Anyone have any solution how to do this? I can make normal structure for nested attributes used once only but I have no clue how to do this properly for this situation.
I have only just started messing around with mongo/mongoid myself but it looks like your class definition is a bit awry. The details are referenced from the Mongoid Relations docs
Use the embedded_in relationship for embeds_many. belongs_to goes with has_many.
class Pointing
include Mongoid::Document
embedded_in :counter
field :name, type: String
field :votes, type: Integer
field :lane, type: String
end
If that doesn't fix it... I setup custom relation names slightly differently by using class_name to point back to the actual class. The as: option is documented to be used when the the child document can belong to many parents but I've not used it enough to say if this is an actual difference or just style.
class Counter
include Mongoid::Document
embeds_many :goodvs, class_name: "Pointing"
embeds_many :badvs, class_name: "Pointing"
accepts_nested_attributes_for :goodvs, :badvs
field :name, type: String
field :champId, type: Integer
end
Then retrieving the objects I've created with:
Counter.each do |c|
log 'counter name', c.name, c.id
log 'goodv', c.goodvs
log 'goodv first', c.goodvs.first.name, c.goodvs.first.id
log 'badvs', c.badvs
log 'badvs first', c.badvs.first.name, c.badvs.first.id
end
Results in:
counter name [sth] [53cfcee66fcb2d2db5000001]
goodv [#<Pointing:0x00000601a395b0>] [#<Pointing:0x00000601a393f8>]
goodv first [mee] [53cfcee66fcb2d2db5000002]
badvs [#<Pointing:0x00000601a37468>] [#<Pointing:0x00000601a372b0>]
badvs first [mee] [53cfcee66fcb2d2db5000002]
So different Pointing object references but both goodvs and badvs contain the same mongo document underneath.
I am trying to store messages and I want to store to and from User reference as below:
class Message
include Mongoid::Document
include Mongoid::Timestamps
field :from, type: Moped::BSON::ObjectId
field :to, type: Moped::BSON::ObjectId
end
class User
include Mongoid::Document
field :username, type: String
end
Is the above the correct way of doing so? I can imagine one way is to create User as a custom type, but that seems a lengthy direction to take. Ideally I want to be able to reference the User directly as so: message.from.username or message.from['username'] and be able to validate the presence of the from and to fields.
Any help would be much appreciated.
class Message
belongs_to :from, class_name: 'User', inverse_of: nil
belongs_to :to, class_name: 'User', inverse_of: nil
...
Message.where(from: my_user)
How do I go about validating the presence of an item defined as belongs_to? In other words:
class Temp
include Mongoid::Document
include Mongoid::Timestamps
belongs_to :user
end
and I wish to make sure a user was input.
Thanks in advance!
From the fine manual:
The parent document of the relation should use the has_many macro to indicate is has n number of referenced children, where the document that is referenced uses belongs_to.
class Band
include Mongoid::Document
has_many :members
end
class Member
include Mongoid::Document
field :name, type: String
belongs_to :band
end
[...]
# The parent band document.
{ "_id" : ObjectId("4d3ed089fb60ab534684b7e9") }
# The child member document.
{
"_id" : ObjectId("4d3ed089fb60ab534684b7f1"),
"band_id" : ObjectId("4d3ed089fb60ab534684b7e9")
}
Take note of the band_id that represents the belongs_to :band relationship. So saying:
belongs_to :user
implicitly adds a field :user_id to your Temp. That means that you can simply:
validates_presence_of :user_id
to make sure that a :user_id has been given. If you want to ensure that the :user_id is valid then you could:
validates_presence_of :user
and the validation will make sure that temp.user (i.e. User.find(temp.user_id)) finds something.
I have this releationship
class Cupboard
include Mongoid::Document
field :name, type: String
has_many :ingredients
end
class Recipe
include Mongoid::Document
field :name, type: String
has_many :ingredients
end
class Ingredient
include Mongoid::Document
field :name, type: String
field :description, type: String
belongs_to :cupboard
belongs_to :recipe
end
I need to create a method in Cupboard model to find a recipe that contains the same ingredients as the cupboard, I don't find in the Mongoid docs a method to find it.
I need something like Recipe.find( #all cupboard.ingredients.ids )
thanks in advance
def shared_recipes
ingredients.map(&:recipe).uniq
end
I'm still getting my head around MongoDB and Mongoid in particlar.
Let's say I have a User and each User has one Thingamajig. When I create the User
I want the system to autmatically also create a blank Thingamajig for that User.
Each Thingamajig has a whatsit field that must be unique if it has a value, but is allowed to have no value when created.
So I define the following classes.
class Thingamajig
include Mongoid::Document
field :whatsit, type: String
index({whatsit: 1}, {unique: true, name: 'whatsit_index'})
end
class User
include Mongoid::Document
field :name, type: String
index({name: 1}, {unique: true, name: 'user_name_index'})
embeds_one :thingamajig, dependent: :nullify, autobuild: true
end
However what I find when I
User.create!(name: 'some name')
is that User.find(name: 'some name').thingamajig is nil.
Questions:
How can I ensure that each User gets an associated Thingamajig? and
How do I specify that the name field of a User is required?
FYI I am using Sintara not Rails (if that matters to anyone).
1 - The autobuild: true option normally should have done the trick. I think the problem is that you forgot to add the other side of the relation to the Thingamajig model:
class Thingamajig
include Mongoid::Document
embedded_in :user
...
end
2 - To specify required fields, use validations:
class User
include Mongoid::Document
field :name, type: String
validates_presence_of :name
...
end
Mongoid uses ActiveModel validations.