Mongoid composite query - mongoid

I'm kind of a newbie to mongoid, I have a problem querying the db for inner relations:
this is the first model of whom I wish to create a query
class User
include Mongoid::Document
include Mongoid::MultiParameterAttributes
include Geocoder::Model::Mongoid
has_many :hosted_meals, class_name:'Meal', inverse_of: :host
has_and_belongs_to_many :followers, class_name: 'User', inverse_of: :following
.
.
.
end
Second model
class Meal
include Mongoid::Document
include Mongoid::Timestamps
include Geocoder::Model::Mongoid
field :privacy, type: String, default: 'p'
belongs_to :host, class_name: 'User', inverse_of: :hosted_meals
Im trying to create a mongo query that does the following:
return all meals of type 'p'
return all meals are of type 'f' and their host is in the current user's followers, something like this:
Meal.where(:privacy => 'f', :host_id.in => )

Related

Can't get my strong parameters nested correct in Ruby on Rails

I'm trying to add an array of objects (tasks in this case) as a return type in my controller for the root object (project). One project has many tasks and I'd like to save it all at once, but I keep getting the following error indicating that the return type isn't correct.
ActiveRecord::AssociationTypeMismatch (Task(#47457277775360) expected, got {"name"=>"Some task", "start"=>"2019-12-05T03:38:48.555Z", "end"=>"2019-12-14T03:38:48.555Z"} which is an instance of ActiveSupport::HashWithIndifferentAccess(#47457266882220))
The whitelisted parameters I have are like this
# whitelist params
params.permit(:name, :description, tasks: [:name, :start, :end])
The data being returned for the above example:
{"name"=>"asdf", "description"=>"zxvccxvzzxcvxcvcxvzxcvz", "tasks"=>[{"start"=>"2019-12-05T03:38:48.555Z", "end"=>"2019-12-14T03:38:48.555Z", "name"=>"Some task"}]}
[Edit] - Here are the models we're working with
# app/models/task.rb
class Task < ApplicationRecord
# model association
belongs_to :project
# validation
validates_presence_of :name
end
# app/models/project.rb
class Project < ApplicationRecord
# model association
has_many :tasks, dependent: :destroy
accepts_nested_attributes_for :tasks
# validations
validates_presence_of :name
end
As per rails documentation Nested attributes allow you to save attributes on associated records through the parent. So in your strong params you need to pass attributes like this.
params.permit(:name, :description, task_attributes: [:name, :start, :end])
I suggest you to bind all params under one attribute like this
params.require(:project).permit(:name, :description, task_attributes: [:name, :start, :end])
so you must send params from frontend like
{"project": {"name"=>"asdf", "description"=>"zxvccxvzzxcvxcvcxvzxcvz", "task_attributes"=>[{"start"=>"2019-12-05T03:38:48.555Z", "end"=>"2019-12-14T03:38:48.555Z", "name"=>"Some task"}]}}
You can read the documentation from https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

How to find all document by association Mongoid 4

I have a model Tag which potentially belongs to several other models, but at the moment only one model Todo which in turn belongs to User like so:
class User
include Mongoid::Document
field: name, type: String
has_many :todos
end
class Todo
include Mongoid::Document
field: name, type: String
belongs_to :user
end
class Tag
include Mongoid::Document
field: name, type: String
belongs_to :todos
end
How can I query all Tags that belongs to a particular user? I've written the following:
todo_ids = Todo.where(user_id: '86876876787')
and then:
tags = Tag.where('todo_id.in': todo_ids)
But those didn't work. What am I missing?
You're missing two things:
Mongoid isn't ActiveRecord so it won't know what to do with todo_ids in the Tag query.
'todo_id.in' is a field path that is trying to look at the in field inside a todo_id hash, this isn't a use of MongoDB's $in operator.
You can only work with one collection at a time so to fix the first one, you need to pull an array of IDs out of MongoDB:
todo_ids = Todo.where(user_id: '86876876787').pluck(:id)
# -------------------------------------------^^^^^^^^^^^
To fix the second one, use the $in operator:
tags = Tag.where(todo_id: { '$in': todo_ids })
tags = Tag.where(:todo_id.in => todo_ids)
tags = Tag.in(todo_id: todo_ids)
#...

Mongoid 3.1 eager loading, json, and field names

Recently updated to Mongoid 3.1 from 3.0.3 and this resulted in some broken code and confusion on my side.
Say you have a pair of classes with a belongs_to/has_many relationship, like so:
class Band
include Mongoid::Document
field :name, type: String
has_many :members, :autosave => true
end
class Member
include Mongoid::Document
field :name, type: String
belongs_to :band
end
Saving all this to the database like so:
b = Band.new
b.name = "Sonny and Cher"
b.members << Member.new(name: "Sonny")
b.members << Member.new(name: "Cher")
b.save
I would in my API, be able to return a 'member' object like so:
m = Member.where(name: "Sonny").first
m.to_json
which yields the following, as expected:
{"_id":"<removed>","band_id":"5151d89f5dd99dd9ec000002","name":"Sonny"}
My client can request the full band object with a subsequent call if it wants to. However, in some cases I DO want to include the referenced item directly. With 3.0.3, I would just do the following:
m = Member.where(name: "Sonny").first
m[:band] = m.band
m.to_json
and this would add a new field with the full band information to it. With 3.1, however (it may have started in earlier versions, but I didn't test), I now get this:
{"_id":"<removed>","band_id":{"_id":"5151dc025dd99d579e000002","name":"Sonny and Cher"},"name":"Sonny"}
So, it looks like the band info has been eager-loaded into the field? Why is it stored under the key ':band_id' and not ':band'? I guess ':band' is protected, but I still don't think the data should be stored under the ':band_id' key. I suspect I am missing something here. Any ideas?
You can specify an :include option for to_json like so:
m.to_json(include: :band)
The JSON will then have a key band with the Band object converted to JSON and band_id will still be present.

Table seems lost when I try to I define a 'Campus' model in rails and set the plural name myself

I need a table whos name is Campus. But rails interprets that as plural, messing everything up.
So I did a little research and they suggest to add an inflection like this:
ActiveSupport::Inflector.inflections do |inflect|
inflect.singular /^(campus)(es)?$/i, '\1'
inflect.plural /^(campus)$/i, '\1es'
end
I have added this in the initializers/inflection.rb file.
I created a new migration to drop the table and create a new one again called Campus, expecting to have the problem solved, but now I can't get the table Campus in the console:
$ rails console
Loading development environment (Rails 3.0.10)
1.9.2p290 :001 > Campus
=> Campus(Table doesn't exist)
What am I doing wrong? How can I fix this problem?
Thanks for your help
My campus model is:
class Campus < ActiveRecord::Base
validates_presence_of :name
validates_presence_of :university_id
has_many :pois, dependent: :destroy
has_many :events, dependent: :destroy
has_many :market_items, dependent: :destroy
has_many :ads_points, dependent: :destroy
belongs_to :university
end
inflectors.rb has some standard code that you can adjust for your situation:
# inflect.plural /^(ox)$/i, '\1en'
# inflect.singular /^(ox)en/i, '\1'
# inflect.irregular 'person', 'people'
So for you it should be:
inflect.plural /^(campus)$/i, '\1es'
inflect.singular /^(campus)es/i, '\1'
Or this maybe even easier:
inflect.irregular 'campus', 'campuses'
With these inflectors Rails will be looking for a table called campuses. Since your table name is campus, you have to add the following to your Campus model:
set_table_name 'campus'
Be sure to restart your server after making changes to inflectors.rb.

nested form, embedded docs, mongoid 2.2.0 problem

I cant seem to find answer for this here or with the google, any help would be awesome.
The Building saves correctly, but the embedded doc PriorityArea doesnt get updated...
I want to eventually have it ajax a new form for new priority areas evenutally, but need it to update first.
Mongoid::Errors::InvalidFind in BuildingsController#update
Calling Document#find with nil is invalid
class Building
include Mongoid::Document
embeds_many :priority_areas
accepts_nested_attributes_for :priority_areas, :allow_destroy => true, :autosave => true
end
class PriorityArea
include Mongoid::Document
embedded_in :building, :inverse_of => :priority_areas
end
#view
= form_for [#customer, #building] do |f|
...
...
= f.fields_for :priority_areas do |pa|
= f.name
...
...
#controller
#building.update_attributes(params[:building])
It correctly yeilds the correct data from the db, but fails to error above on building#update. Any help is greatly appreciated.
update
in the building#update im
puts params[:building][:priority_areas_attributes].to_yaml
which yeilds
--- !map:ActiveSupport::HashWithIndifferentAccess
"0": !map:ActiveSupport::HashWithIndifferentAccess
name: area 51
location: near front door
notes: ""
priority: "1"
id: ""
"1": !map:ActiveSupport::HashWithIndifferentAccess
name: area 52
location: near rear door
notes: ""
priority: "2"
id: ""
im guessing the problem is the null id:""
The problem was the null id
it needed to have an ObjectId to work correctly. stupid error on my part.
I encountered the exact problem. simple_form was automatically passing an id parameter to my controller, but it was blank.
Why was the id for my embedded document blank? I'm guessing it's because I imported the parent document via mongoimport. If I manually generate a parent document via web forms, then the embedded documents have IDs as expected.
Here was my workaround:
class Foo
include Mongoid::Document
embeds_many :bars
accepts_nested_attributes_for :bars
####
# simple_form_for / embedded document workaround
#
# Because simple_form wants to provide the ID for an existing object,
# it will output a blank ID because imported embedded documents
# have an ID of nil.
#
# Intercept it to avoid
# Mongoid::Errors::InvalidFind in FoosController#update
def bars_attributes=(attribs)
attribs.each do |key, value|
index = key.to_i
fixed_attrib = value.delete_if { |k,v| k=="id" and v=="" }
self.bars[index].update_attributes(fixed_attrib)
end
end
end
class Bar
include Mongoid::Document
embedded_in :foo
end

Resources