MongoMapper issue with stack level being too deep - mongodb

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.

Related

Auto complete in text field in odoo

I would like to select a customer from the select box by start typing its phone number.
How can I do that?
I have seen some are using name_search method.But still i am confused how to use it in both front end and back end.
Or is there any other solution for this.
Override the name_search method of your model and the domain you want on the args variable. Take a look at addons/account/account.py around line 595 args += [('type', '=', type)] for a concrete implementation. Make sure that you return the appropriate data structure as documented in the method's docstring at openerp/models.py.
For Auto complete in odoo. It provides suggestion only in case of using Many2one field in any module.
If you want to show suggestion and autocomplete. Create a model to store the mobile numbers and then use that particular model as foreign key in existing model.
That will do for you.

Though I have a record in database, it's giving "Mongoid::Errors::DocumentNotFound"

Though I have the record with id 13163 (db.locations.find({_id: 13163})), it's giving me error:
Mongoid::Errors::DocumentNotFound in LocationsController#show
Problem: Document(s) not found for class Location with id(s) 13163.
Summary: When calling Location.find with an id or array of ids, each
parameter must match a document in the database or this error will be
raised. The search was for the id(s): 13163 ... (1 total) and the
following ids were not found: 13163. Resolution: Search for an id that
is in the database or set the Mongoid.raise_not_found_error
configuration option to false, which will cause a nil to be returned
instead of raising this error when searching for a single id, or only
the matched documents when searching for multiples.
# Use callbacks to share common setup or constraints between actions.
def set_location
#location = Location.find(params[:id])
end
locations_controller.rb:
class LocationsController < ApplicationController
before_action :set_location, only: [:show, :edit, :update, :destroy]
# GET /locations
# GET /locations.json
def index
#locations = Location.all
end
# GET /locations/1
# GET /locations/1.json
def show
end
private
# Use callbacks to share common setup or constraints between actions.
def set_location
#location = Location.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def location_params
params.require(:location).permit(:loc_name_en, :loc_name_jp, :channel)
end
end
Setting up the option raise_not_found_error: false is not the case as I do have a document in database.
SOLUTION:
Big thanks to #mu is too short for giving me a hint.
The problem can be solved in 2 ways:
Declare field :_id, type: Integer in the model location.rb
Or converting the passing parameter to Integer like Location.find(params[:id].to_i) in locations_controller.rb as shown below in the #mu is too short's answer
I'd guess that you have a type problem. You say that this:
db.locations.find({_id: 13163})
finds the document in the MongoDB shell. That means that you have a document in the locations collection whose _id is the number 13163. If you used the string '13163':
db.locations.find({_id: '13163'})
you won't find your document. The value in params[:id] is probably a string so you're saying:
Location.find('13163')
when you want to say:
Location.find(13163)
If the _id really is a number then you'll need to make sure you call find with a number:
Location.find(params[:id].to_i)
You're probably being confused because sometimes Mongoid will convert between Strings and Moped::BSON::ObjectIds (and sometimes it won't) so if your _id is the usual ObjectId you can say:
Model.find('5016cd8b30f1b95cb300004d')
and Mongoid will convert that string to an ObjectId for you. Mongoid won't convert a String to a number for you, you have to do that yourself.

Mongoid: If possible, how to assign a parent to pre-existing child?

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

Embedded and no-embedded document in the same time

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.

Mongo ids leads to scary URLs

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.