I have a service that does a request,
.factory('movieService', ['$http', function($http) {
return {
loadMovies: function() {
return $http.get('/movies_users.json');
}
};
}])
This is the JSON output and is the result of 2 tables being joined. A user table and a movie table. As you can see the users are associated with 1 or more movies.
[
{"id":1,
"email":"peter#peter.nl",
"movies":[
{
"id":4,
"title":"Creed",
movie_id":"312221"
},
{
"id":5,
"title":"Star Wars: Episode VII - The Force Awakens",
"movie_id":"140607"
}
]
},
{"id":2,
"email":"jan#jan.com",
"movies":[
{
"id":4,
"title":"Creed",
movie_id":"312221"
}
]
}
]
And this is the movies_users_controller.rb
def index
movie = Movie.all
render :json => movie.to_json(:include => :users)
end
Is it possible to only show the current user in the JSON output instead of both users?
Is it possible to only show the current user in the JSON output
instead of both users?
That implies that you have some authentication system (if you don't, you can have a look at devise).
Instead of fetching all the movies, just get the movies of the current user.
#movies = current_user.movies
In order to make this work, you'll have to have a relationship between the User model and the Movie model, something like this:
# user.rb
has_many :user_movies
has_many :movies, through: user_movies
# user_movie.rb
belongs_to :movie
belongs_to :user
# movie.rb
has_many :user_movies
has_many :users, through: :user_movies
Also, it seems that you are building an API, I would advice to use something like jbuilder to build your json object, it will be cleaner and you will be able to display pretty much everything you want.
Related
Given the following documents, I'm trying to find a log document given a token ID.
class Log
include Mongoid::Document
belongs_to :user
end
class User
include Mongoid::Document
embeds_many :tokens
end
class Token
include Mongoid::Document
end
I tried Log.where('user.tokens._id': BSON::ObjectId('123ABC') with no luck. Any ideas?
In this case you can't navigate to user from log in Mongoid Criteria because they are different collections in database (dot notation is only available when using embedding). For this case you can use aggregation pipeline:
Log.collection.aggregate([
{
'$lookup' => {
from: User.collection.name,
localField: 'user_id',
foreignField: '_id',
as: 'users'
}
},
{
'$match' => {
'users.tokens' => {
'$elemMatch' => {
_id: { '$eq' => BSON::ObjectId('123ABC') }
}
}
}
}
]).map { |doc| Log.instantiate(doc) }
Lookup works like join in SQL docs.
aggregate in Mongoid returns collection of BSON::Documents so we use Log.instantiate to create Log instances from them.
Searchkick - Autocomplete with multiple models & fields
I am struggling to implement the autocomplete functionality for multiple models associated to my Post model. The search functionality works fine and returns the expected data. My autocomplete method also works fine if I implement it the way it is done in the documentation (only for posts' title however).
I also tried this answer and this one by switching Post.index.name to Post.searchkick_index.name but the autocomplete functionality does not display.
This is the code I wrote in posts_controller.rb:
def autocomplete
render json: Post.search(params[:query],
index_name: [
Post.searchkick_index.name,
Tag.searchkick_index.name,
User.searchkick_index.name
],
limit: 10,
load: false,
misspellings: { below: 5 })
end
I also tried:
def autocomplete
render json: Searchkick.search(params[:query],
models: [Post, Tag, User],
limit: 10,
load: false,
misspellings: { below: 5 })
end
I get no errors with the above code, but the autocomplete functionality does not work either.
In post.rb:
class Post < ApplicationRecord
belongs_to :user
has_many :comments, dependent: :destroy
has_many :posts_tags, dependent: :destroy
has_many :tags, through: :posts_tags
searchkick word_start: %i[title]
def search_data
{
title: title,
description: description,
user: user.full_name
}.merge(
tag: tags.map(&:title),
comments: comments.map(&:description)
)
end
end
As suggested in the answer section, I also tried the following:
def autocomplete
posts = Post.search(params[:query], execute: false)
tags = Tag.search(params[:query], execute: false)
users = User.search(params[:query], execute: false)
render json: Searchkick.multi_search([posts, tags, users])
end
This returns the following error: fatal - exception reentered.
I want to be able to autocomplete Post's title, Tag's title & User's full_name. How should I change my code?
Thank you in advance!
From multi_search of searchkick:
posts = Post.search(params[:query], execute: false)
tags = Tag.search(params[:query], execute: false)
users = User.search(params[:query], execute: false)
Searchkick.multi_search([posts, tags, users])
I have two models: Worker and Skill.
A worker can have multiple skills. Each skill has its own name (e.g. 'php', 'web-development' etc.)
In my search form I want to be able to filter workers (with the help of searchkick) according to their skills. If multiple skills are selected in the form, the search results should only include those workers, who have all the skills which have been selected.
I tried the following:
worker.rb
has_many :worker_skills
has_many :skills, through: worker_skills
searchkick
scope :search_import, -> { includes(:skills) }
def search_data
{
skills_name: skills.pluck(:name)
}
end
skill.rb
has_many :worker_skills
has_many :workers, through: :worker_skills
workers_controller.rb
def index
...
#workers = Worker.search(
params[:q],
where: {
skills_name: params[:skills]
}
end
...
end
This returns me all the workers who have at least one of the selected skills.
Example:
Filters selected: ['php', 'ruby']
Result: All workers who either have 'php' - OR - 'ruby' as a skill.
How can I achieve it to only return those workers who have both skills at the same time?i.e. 'php' - AND - 'ruby'
If you look here https://github.com/ankane/searchkick#querying you can use the all parameter so that it must match with all elements in the where clause. Do the following in your workers_controller.rb:
def index
...
#workers = Worker.search(
params[:q],
where: {
skills_name: {
all: params[:skills]
}
}
end
...
end
Also keep in mind to ensure that you have values in params[:skills]. If not you get an undefined method `each' for nil:NilClass Error. So maybe disable the search button until some values were selected.
The following renders a json of the attribute selected_branch, including all its products, and the categories for the products:
render json: selected_branch, :include => { :products=> {:include =>:categories }, :enabled => true }
How can I only include all the products that have "Product.enabled = true"?
Earlier in your ActiveRecord query where you presumably get the data for selected_branch, build it into your query before the render :json. I would start by using a rails scope on the model.
Something like this:
In your model (not sure what it is, so I will refer to it as Branch)
Branch.rb
class Branch < ActiveRecord::Base
has_many :products
scope :with_enabled_products, -> { includes(:products).where(products: {enabled: true}) }
end
Then in your Controller
selected_branch = Branch.with_enabled_products
Then the JSON you render should be only those of the branches that have enabled products. Of course you can always tack a .where(...) onto the end of that scope because it is just an ActiveRecord relation and you can further narrow down your data set.
I currently have an Album/Artist database that uses multiple join tables to signify when how an artist relates to the album. They can be listed as a Composer, an Arranger, or a Performer. That is:
class Artist < ActiveRecord::Base
...
has_and_belongs_to_many :albumbycomposers, :class_name => "Album", :join_table => "albums_composers"
has_and_belongs_to_many :albumbyarrangers, :class_name => "Album", :join_table => "albums_arrangers"
has_and_belongs_to_many :albumbyperformers, :class_name => "Album", :join_table => "albums_performers"
...
end
And
class Album < ActiveRecord::Base
has_and_belongs_to_many :composers, :class_name => "Artist", :join_table => "albums_composers"
has_and_belongs_to_many :arrangers, :class_name => "Artist", :join_table => "albums_arrangers"
has_and_belongs_to_many :performers, :class_name => "Artist", :join_table => "albums_performers"
...
end
This code is used to look up for existing artists in the database, then create the association. If no artist exists, then I use the .build method to create the artist.
class AlbumsController < ApplicationController
...
def create
#album = Album.new(params[:album])
params["Composer Names"].each do |each|
if each.empty? == false
#exists = Artist.find_by_name(each)
if #exists.nil? == true
#album.composers.build(:name => each)
else
#album.composers << Artist.find_by_name(each)
end
end
end
params["Arranger Names"].each do |each|
if each.empty? == false
#exists = Artist.find_by_name(each)
if #exists.nil? == true
#album.arrangers.build(:name => each)
else
#album.arrangers << Artist.find_by_name(each)
end
end
end
...
end
...
end
The problem I encounter occurs when I try to enter a new artist as both a composer and an arranger. For example, say I submit this as a post request
Parameters: {"Name"=>["New Album"],
"Performer Names"=>["New Artist"],
"Composer Names"=>["New Artist"],
"Arranger Names"=>["New Artist"],
...
}
Since the composer arguments are first, rails interprets them properly (as if the artist does not exist). The arranger and performer arguments are also interpreted as if the artist does not exist. Then rails begins inserting data into my database. First the album is created and inserted into the albums table, then "New Artist" is created and inserted into album_composer (according to the .build method).
However, for the arranger and performer arguments, the build method can no longer be used, since the artist has been created, so the code is not executed properly.
I tried to workaround by using the push method (aka <<) in the arranger and performer argument lines for this specific case, but that doesn't work because it instantly fires without waiting for the artist to be made by the composer argument, resulting in an "Artist cannot be found" error. For Reference:
collection<<(object, …)
Adds one or more objects to the collection by creating associations in the join table (collection.push and collection.concat are aliases to this method).
Note that this operation instantly fires update sql without waiting for the save or update call on the parent object.
What is the proper way to handle this?
I solved the problem by adding in each artist separately into my database first using the code:
#artists = params["Composer Names"] | params["Arranger Names"] | params["Performer Names"]
#artists.each do |artist|
if artist.empty? == false
#exists = Artist.find_by_name(artist)
if #exists.nil?
#artist = Artist.new(:name => artist)
#artist.save
end
end
end
I could use the push method and add each artist to the proper join table using code like:
params["Composer Names"].each do |each|
if each.empty? == false
#album.composers << Artist.find_by_name(each)
end
end
so that's that!