Mongoid generic embedded_in fields - ruby

I have a Translation class embedded in a Product class.
class Translation
include Mongoid::Document
field :key, type: String
field :value, type: String, default: ''
field :locale, type: String
embedded_in :product
end
class Product
embeds_many :translations
end
It work but now, I need Translation to be embedded in other classes :
class Order
embeds_many :translations
end
but Translation still embeds_many :translations. How can I fix that ?

Related

Mongoid skip validation or set default value for document with nil embeds_many

Mongoid won't save document with no reference to embeds_many field, and I can't find any mention in documentation on how to make embeds_many default to [] if not present, or alternatively to skip that validation if not present.
Here's a simple reproduction
class ModelOne
include Mongoid::Document
include Mongoid::Timestamps
field :name, type: String
embeds_many :model_twos
end
class ModelTwo
include Mongoid::Document
embedded_in :model_one
end
mOne = ModelOne.new({name: "foo"})
if mOne.save
...
else
pp mOne.errors.full_messages
end
Which results in an error like;
["ModelTwos is invalid"]
"...by default, Mongoid will validate the children of any relation that are loaded into memory via a validates_associated... If you do not want this behavior, you may turn it off when defining the relation." (documentation)
So, the following should help hopefully:
embeds_many :model_twos, validate: false

Mongoid nesting with embeds_many two times of one class

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.

Mondoid search one document with multiples in a has_many/belongs_to relationship

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

How do I autocreate associated records in MongoDB using Mongoid?

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.

Mongoid 1..N polymorphic referenced relations

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)

Resources