Multikey indexing in rails mongoid - ruby-on-rails

I want to store data in this format.
{
"_id": ObjectId(...)
"title": "Grocery Quality"
"comments": [
{ author_id: ObjectId(...)
date: Date(...)
text: "Please expand the cheddar selection." },
{ author_id: ObjectId(...)
date: Date(...)
text: "Please expand the mustard selection." },
{ author_id: ObjectId(...)
date: Date(...)
text: "Please expand the olive selection." }
]
}
I'm confused as to how to achieve this format for my data.
I am using mongoid; does Mongoid support Multikey Indexing?
How can use mongoid to achieve my desired format and behaviour?

I'm not sure if I got your doubt correctly but as I can't comment I'm answering right away. If it isnt this what you asked, please explain a little bit more =)
You have your model with those fields you wrote before, I will call it Post model. For the comments on it, I would suggest you create another model callend Comment and embed it on the Post model:
class Post
field: title
embeds_many :comments
end
class Comment
field :date
field :text
has_one :author
embedded_in :post
end
And to index the comments on the Post model you could do:
index({ :"comments.updated_at" => 1 })

Related

Rails, how to specify which fields to output in a controller's JSON response?

in my controller I currently have:
invite = Invite.find_by_token(params[:id])
user = invite.user
json_response({
user: user
})
def json_response(object, status = :ok)
render json: object, status: status
end
Right now, user is returning all user fields. I want to return just (id, email)... I've tried:
user = invite.user.select(:id, :email)
user = invite.user.pluck(:id, :email)
neither works. Ideas?
You can use the method as_json passing attributes you want in the response, like:
user.as_json(only: [:id, :email])
I know this question already has an answer, but there is also a nice gem you could use called active_model_serializers. This lets you specify exactly which properties you want in your JSON output for different models and even let's you include relationships to other models in your response.
Gemfile:
gem 'active_model_serializers', '~> 0.10.0'
Then run bundle install.
You can then create a serializer using the generator command:
rails g serializer user
which will create the serializer in project-root/app/serializers/.
In your serializer, you can whitelist the attributes you would like:
project-root/app/serializers/user_serializer.rb:
class UserSerializer < ActiveModel::Serializer
attributes :id, :email
end
Now any time you return a User object it will only output those two attributes, id and email.
Want to print out related models? Easy. You can just add the relationship in your serializer and it will include those related models in your JSON output.
Pretend a user "has many" posts:
class UserSerializer < ActiveModel::Serializer
attributes :id, :email
has_many :posts
end
Now your JSON outputs should look something like:
{
"id": 1,
"email": "user#example.com",
"posts": [{
id: 1,
title: "My First Post",
body: "This is the post body.",
created_at: "2017-05-18T20:03:14.955Z",
updated_at: "2017-05-18T20:03:14.955Z"
}, {
id: 2,
title: "My Second Post",
body: "This is the post body again.",
created_at: "2017-05-19T20:03:14.955Z",
updated_at: "2017-05-19T20:03:14.955Z"
},
...
]
}
Pretty neat and convenient. And if you want to limit the the posts to only print certain columns as well, all you need to do is create a serializer for posts, specify the attributes, and the output will just work.

Rails 5 - include nested associations not working

I have two simple models:
note.rb
with
:title -> string, :content -> string
has_and_belongs_to_many :tags, join_table: :tags_notes
accepts_nested_attributes_for :tags
tag.rb
with
:name -> string
has_and_belongs_to_many :notes, join_table: :tags_notes
Both models are connected through has_and_belongs_to_many relationship.
The association table is called tags_notes as indicated above.
Well, the problem I have here is, in my RESTful controller, to get notes, I have this:
GET /api/notes
This only returns Note objects:
[
{
"id": 1,
"title": "12231",
"content": "121213"
},
{
"id": 2,
"title": "test",
"content": "testtest"
}
]
However, each note has tags, and I would like to dump those in the response as well, like this:
[
{
"id": 1,
"title": "12231",
"content": "121213",
tags: [
{
"name": "test",
"id": 1
},
{
...
}
]
},
...
]
In my controller, I've tried
Note.includes(:tags).
Current controller code:
def index
notes = Note.includes(:tags)
render json: notes, status: :ok
end
They only seem to return notes, without tags. Same is the case with Note.eager_load(:tags) What am I doing wrong? Cannot find enough documentation that will help me fix this issue.
If someone can help me with this I will be grateful.
Thanks a bunch.
Shortly after posting my question I found the answer myself. The include has to go in render.
So the controller code
def index
notes = Note.all
render json: notes, :include => :tags, status: :ok
end
Seems to do the trick!

Rails JBuilder recursive lookup

I am using Rails 4, and I have some simple models as follow:
class Question < ActiveRecord::Base
# columns (id, text)
has_many :answers
end
class Answer < ActiveRecord::Base
# columns (id, text, next_question_id)
belongs_to :question
end
You can see that an answer has a next_question_id column, which will be used to look up another question. I want to generate a tree-structure json like this:
{
"text": "This is question 1",
"answers": [
{
"text": "This is answer a",
"next_question": {
"text": "This is question 2",
"answers": [
{
"text": "This is answer c",
"next_question":
}
]
}
},
{
"text": "This is answer b",
"next_question": {
"text": "This is question 2",
"answers": [
{
"text": "This is answer d",
"next_question":
}
]
}
}
]
}
How can I achieve this with JBuilder? I tried the solution here, but I cannot pass the json argument to the helper function.
The standard aproach for rendering trees is using a recursive partial. To implement this you'll first need to add a method to your Answer model like this.
def next_question
Question.find(next_question_id) if next_question_id
end
(hint: alternetively you could just set a belongs_to :next_question, class_name: Question association on your Answer model)
Then you create a partial like _question.json.jbuilder that goes like this:
json.(question,:id, :text)
json.answers question.answers do |answer|
json.(answer, :id, :text)
json.partial!(:question, question: answer.next_question) if answer.next_question
end
Then in the controller you take the first question in your survey and put it in say the #first_question variable.
And the last thing: in your view you write
json.partial! :question, question: #first_question

Rails 3: Wrapping as_json response with additional lines

I was very happy to learn of as_json to make my code DRY. And I've added the following to a model:
class ProductType < ActiveRecord::Base
has_many :component_types
def as_json(parameter)
{:name => self.name,
:description => self.description,
:children => self.componentTypes}
end
end
This is great. The only thing is that for my client side application, I need to wrap the response I get into this format, (where "items" contains what is created by as_json):
{
"identifier": "name",
"label": "name",
"items":
[
{
"name": "myName1",
"description": "myDesc1",
"children":[]
},
{
"name": "myName2",
"description": "myDesc2",
"children":[]
}
]
}
There are a lot of limitations to overriding as_json, and your issue is one of them. I'd suggest having a look at the RABL gem as I think it will help you reach your goal.

Why does Ruby on Rails append an empty object when has_many and belongs_to are in use?

Hey, I am writing a website similar to 4chan. I have two models: Board and Picture. A Board has many Pictures:
class Board < ActiveRecord::Base
# Relationships
has_many :pictures, :dependent => :destroy
end
class Picture < ActiveRecord::Base
# Relationships
belongs_to :board
end
I do this in my view boards/show.html.haml:
- if #board.pictures.any?
- #board.pictures.each do |picture|
%article.picture-article{ :id => "picture-#{picture.id}" }
- if picture.title?
%header
%h2= picture.title
%img{ :src => picture.pic.url, :alt => (picture.title? ? picture.title : 'untitled pic') }/
%pre~ picture.description
- else
meh this board is still empty
And in my nice BoardsController:
def show
#board = Board.find_by_short_name params[:id]
end
The problem is that always one Picture is shown which is empty. For example, I have a Board with no Pictures in the db (checked it with Picture.all), but this is the output:
<article class='picture-article' id='picture-'>
<img alt='untitled pic' src='/pics/original/missing.png'>
<pre></pre>
</article>
However, when I render it as JSON, the output is with no Pictures, like it should be:
{
"board": {
"name": "n00bs",
"created_at": "2011-03-16T17:14:32Z",
"updated_at": "2011-03-16T17:14:32Z",
"id": 14,
"short_name": "0",
"pictures": [
]
}
}
I can remove this by simply removing the last item of the array before doing an each but the bug still remains and this is super duper clumsy. How can this happen? Why does #board.pictures always append an empty Picture object?
Try pictures.present? instead of .any?
Ha!
In my view, adding .all did the job (and order also works):
- #board.pictures.all.each do |picture|

Resources