I need to have a model which will behave like a embedded and not-embedded.
For example if I want to store this model as embedded:
class MenuPosition
include Mongoid::Document
field :name, type: String
field :category, type: String
I need to add
embedded_in :menu
to it.
On the other side, if I add this line in the model I cannot store this model as not-embedded:
position = {
"name" => "pork",
"category" => "meal",
"portion" => 100
}
MenuPosition.create(position)
error message:
NoMethodError:
undefined method `new?' for nil:NilClass
Can I use one model for embedded and not-embedded documents?
In our project we had a similar thing. What we did is define the fields as a module. A bit like this:
module SpecialFields
extend ActiveSupport::Concern
included do
field :my_field, type: String
field :my_other_field, type: String
end
end
Then in your class where you want to embed, just do:
include SpecialFields
In your class that you'd like to store separately as a non-embedded document, do this:
class NotEmbeddedDoc
include Mongoid::Document
include SpecialFields
end
This worked pretty well in our project for a few things. However, it might not be appropriate in your case since you want to embed many. This only really works for embeds one cases I think. I have posted it here in case it helps people.
Related
In a model definition can you have more than one belongs_to statement? If the answer is no, read no further. I am trying to create three 1-n referenced relationships with mongoid in a sinatra app.
models
class SkillTrack
include Mongoid::Document
belongs_to :student
belongs_to :grading_period
belongs_to :teacher
end
class Student
include Mongoid::Document
field :name
field :nickname
field :dob, type: Date
has_many :skill_tracks
end
class GradingPeriod
include Mongoid::Document
field :school_year
field :period_name
field :signing_date, type: Date
has_many :skill_tracks
end
class Teacher
include Mongoid::Document
field :name
has_many :skill_tracks
end
routes
post "/skill_track/new" do
form = params[:formdata] # using sinatra form helpers gem
student = Student.find("#{formdata["student_mongo_id"]}")
working = (student.skill_tracks.create).id
??? what do I do with working to make it a child of a teacher and of a grading_period?
end
what I have tried
The thing that looked the most promising to me from the mongoid docs was:
band.member_ids = [ id ] #Set the related document ids.
I mucked about in irb and tried lots of variations in my models but I could not set a parent teacher or grading period for the newly created skilltracking object. The student foreign key was set properly on creation.
I am hoping I have a simple syntax ignorance, but I tried so many variations I wonder if I can do this at all.
UPDATE:
I just needed to add working.save to David Troyer answer and boom working.
post "/skill_track/new" do
form = params[:formdata]
student = Student.find("#{formdata["student_mongo_id"]}")
working = student.skill_tracks.create
working.teacher = Teacher.create # or find
working.grading_period = GradingPeriod.create # or find
working.save
end
I believe so. If I understand your question correctly, try using some setters on the child SkillTrack document.
post "/skill_track/new" do
form = params[:formdata]
student = Student.find("#{formdata["student_mongo_id"]}")
working = student.skill_tracks.create
working.teacher = Teacher.create # or find
working.grading_period = GradingPeriod.create # or find
end
Dig a little bit further into the Operations section of the mongoid docs you referenced
Just want to start off by saying I did google this topic at length and was unable to find anything that applied to my own use case.
I have a simple little ad server. There is a model for Ad, and two embedded models called Impression and Click - like so:
class Ad
include MongoMapper::Document
key :name, String
key :image, String
key :url, String
has_many :clicks
has_many :impressions
end
class Click
include MongoMapper::EmbeddedDocument
key :ip, String
timestamps!
end
class Impression
include MongoMapper::EmbeddedDocument
key :ip, String
timestamps!
end
And here is the error I'm getting:
SystemStackError - stack level too deep:
/home/deployer/.rbenv/versions/1.9.3-p125/lib/ruby/gems/1.9.1/gems/mongo_mapper-0.12.0/lib/mongo_mapper/plugins/keys.rb:194
Here is the area that this is happening in:
#ad.impressions << Impression.new({:ip => request.ip})
#ad.save
Now, I do not have any callbacks here in my models, which is the reason this error happens for a lot of people.
Anyone have any insights?
Thanks.
I seem to have hit on the answer. the timestamps! is what was causing this. The other examples I saw online had to do with callbacks and the way that ActiveSupport runs them. I just didn't realize that timestamps! counts as one.
I am trying to configure and use mongoid for the first time. I have set the mongoid.yml config file simply as:
host: localhost
database: table
and my code:
Mongoid.load!("/mongoid.yml")
class Data
include Mongoid::Document
field :study, type: String
field :nbc_id, type: String
field :short_title, type: String
field :source, type: String
field :start_date, type: Date
end
puts Data.study
I keep getting an error:
NoMethodError at / undefined method `study' for Data:Class
I think it is because I have not specified the collection name which is 'test'. However I can find no examples on how to do this. Do I specify it in the .yml file or in the code. What is the correct syntax. Can anyone point me in the right direction?
Tx.
According to the Mongoid documentation, "Mongoid by default stores documents in a collection that is the pluralized form of the class name. For the following Person class, the collection the document would get stored in would be named people."
http://mongoid.org/docs/documents.html
The documentation goes on to state that Mongoid uses a method called ActiveSupport::Inflector#classify to determine collection names, and provides instructions on how to specify the plural yourself.
Alternatively, you can specify the collection name in your class by including "store_in" in your class definition.
class Data
include Mongoid::Document
store_in :test
Hope this helps!
I'm using Mongoid on Sinatra . And I use
Dir.glob(File.join(File.dirname(__FILE__),'models','*.rb')).each do |file|
require file
end
to load mongoid model files.
I tried to add a model B inherit from A ,like:
models/a.rb:
class A
include Mongoid::Document
include Mongoid::Timestamps
field :custom_id, type: Integer
end
models/b.rb
class B < A
field :title , type: String
field :body , type: String
end
But when I exec the App , I got errors :
uninitialized constant A (NameError)
So I'm trying to find a solution for this,
it could be fixed by add:
require A
at the top of model B , But I think it may not be a good way to solve it.
So , is there anyother way to fix this??
Regards
You just require your file where you A class is define.
Sinatra has no auto_load system like rails have. So you need doing all of your require needed.
require 'a'
class B < A
field :title , type: String
field :body , type: String
end
This might sound like a trivial question, but it is rather important for consumer facing apps
What is the easiest way and most scalable way to map the scary mongo id onto a id that is friendly?
xx.com/posts/4d371056183b5e09b20001f9
TO
xx.com/posts/a
M
You can create a composite key in mongoid to replace the default id using the key macro:
class Person
include Mongoid::Document
field :first_name
field :last_name
key :first_name, :last_name
end
person = Person.new(:first_name => "Syd", :last_name => "Vicious")
person.id # returns "syd-vicious"
If you don't like this way to do it, check this gem: https://github.com/hakanensari/mongoid-slug
Define a friendly unique field (like a slug) on your collection, index it, on your model, define to_param to return it:
def to_param
slug
end
Then in your finders, find by slug rather than ID:
#post = Post.where(:slug => params[:id].to_s).first
This will let you treat slugs as your effective PK for the purposes of resource interaction, and they're a lot prettier.
Unfortunately, the key macro has been removed from mongo. For custom ids,
users must now override the _id field.
class Band
include Mongoid::Document
field :_id, type: String, default: ->{ name }
end
Here's a great gem that I've been using to successfully answer this problem: Mongoid-Slug
https://github.com/digitalplaywright/mongoid-slug.
It provides a nice interface for adding this feature across multiple models. If you'd rather roll your own, at least check out their implementation for some ideas. If you're going this route, look into the Stringex gem, https://github.com/rsl/stringex, and acts_as_url library within. That will help you get the nice dash-between-url slugs.