Connect two models through id - ruby-on-rails

I have trailer model, and a movie model. When a movie is created, I look up all the available trailers and place each one of them in a record with the youtube link and the movie_id of the movie that's been added.
def index
trailer = Trailer.all
respond_to do |format|
format.json do
render :json => trailer.to_json(:only => [:id, :movie_id, :link])
end
end
end
And the json output,
[
{
"id":1,
"movie_id":"312221",
"link":"LsjX5dqHLuw"
},
{
"id":2,
"movie_id":"209112",
"link":"nIGtF3J5kn8"
},
{
"id":3,
"movie_id":"209112",
"link":"yViIi3gie2c"
},
{
"id":4,
"movie_id":"209112",
"link":"Onh7NbZ7F8o"
},
{
"id":5,
"movie_id":"290250",
"link":"1Vb32Kokbtg"
},
{
"id":6,
"movie_id":"290250",
"link":"1Vb32Kokbtg"
},
{
"id":7,
"movie_id":"27205",
"link":"8hP9D6kZseM"
},
{
"id":8,
"movie_id":"157336",
"link":"ePbKGoIGAXY"
},
{
"id":9,
"movie_id":"157336",
"link":"KlyknsTJk0w"
},
{
"id":10,
"movie_id":"157336",
"link":"nyc6RJEEe0U"
},
{
"id":11,
"movie_id":"157336",
"link":"Lm8p5rlrSkY"
},
{
"id":12,
"movie_id":"157336",
"link":"zSWdZVtXT7E"
}
]
Then I have my movie controller,
def index
#movie = Movie.all
respond_to do |format|
format.json do
render :json => #movie.to_json(include: :trailers)
end
end
end
The the json output,
[
{
"id":1,
"title":"Creed",
"release_date":"2016-01-21",
"image":"/xSE4NBFDzqedwa4AIj99r1Z7ljF.jpg",
"user_id":null,
"created_at":"2016-01-07T20:19:43.849Z",
"updated_at":"2016-01-07T20:19:43.849Z",
"movie_id":"312221",
"backdrop":"/nF4kmc4gDRQU4OJiJgk6sZtbJbl.jpg",
"crew":null,
"cast":null,
"trailers":[
]
},
{
"id":2,
"title":"Batman v Superman: Dawn of Justice",
"release_date":"2016-03-24",
"image":"/eJrlh2g9UGAd7R6mQAOQIIs329H.jpg",
"user_id":null,
"created_at":"2016-01-07T20:21:02.615Z",
"updated_at":"2016-01-07T20:21:02.615Z",
"movie_id":"209112",
"backdrop":"/15PbZtjRJ4zgQA8XS0otL70piQi.jpg",
"crew":null,
"cast":null,
"trailers":[
]
},
{
"id":3,
"title":"The Nice Guys",
"release_date":"2016-05-26",
"image":"/ecD35nDfjsxvDW5BtmK6YAaIkzF.jpg",
"user_id":null,
"created_at":"2016-01-07T20:22:05.960Z",
"updated_at":"2016-01-07T20:22:05.960Z",
"movie_id":"290250",
"backdrop":"/aEMBBMuK3BhKIuFu7iFSTXC41Bi.jpg",
"crew":null,
"cast":null,
"trailers":[
]
},
{
"id":4,
"title":"Inception",
"release_date":"2010-07-22",
"image":"/qmDpIHrmpJINaRKAfWQfftjCdyi.jpg",
"user_id":null,
"created_at":"2016-01-08T09:22:30.383Z",
"updated_at":"2016-01-08T09:22:30.383Z",
"movie_id":"27205",
"backdrop":"/s2bT29y0ngXxxu2IA8AOzzXTRhd.jpg",
"crew":null,
"cast":null,
"trailers":[
]
},
{
"id":5,
"title":"Interstellar",
"release_date":"2014-11-06",
"image":"/nBNZadXqJSdt05SHLqgT0HuC5Gm.jpg",
"user_id":null,
"created_at":"2016-01-08T09:22:39.120Z",
"updated_at":"2016-01-08T09:22:39.120Z",
"movie_id":"157336",
"backdrop":"/xu9zaAevzQ5nnrsXN6JcahLnG4i.jpg",
"crew":null,
"cast":null,
"trailers":[
]
}
]
Is there a way that I can look up all the trailers that have the same movie_id value as a movie and include them into the json render?
The disered result would be something like this,
{
"id":5,
"title":"Interstellar",
"release_date":"2014-11-06",
"image":"/nBNZadXqJSdt05SHLqgT0HuC5Gm.jpg",
"user_id":null,
"created_at":"2016-01-08T09:22:39.120Z",
"updated_at":"2016-01-08T09:22:39.120Z",
"movie_id":"157336",
"backdrop":"/xu9zaAevzQ5nnrsXN6JcahLnG4i.jpg",
"crew":null,
"cast":null,
"trailers":[
{
"id":8,
"movie_id":"157336",
"link":"ePbKGoIGAXY"
},
{
"id":9,
"movie_id":"157336",
"link":"KlyknsTJk0w"
},
{
"id":10,
"movie_id":"157336",
"link":"nyc6RJEEe0U"
},
{
"id":11,
"movie_id":"157336",
"link":"Lm8p5rlrSkY"
},
{
"id":12,
"movie_id":"157336",
"link":"zSWdZVtXT7E"
}
]
}

You can query for trailers by movie_id:
#movie = Movie.first
#trailers = Trailer.where(movie_id: #movie.id)
You might want to research Associations. If your Movie has_many Trailers then you can eventually just do:
#trailers = #movie.trailers
Ruby on Rails Guide: ActiveRecord Associations

You can try to show the trailers in movies
you wan to include trailers with movies in that json
def index
#movies = Movie.order('created_at desc')
respond_to do |format|
format.json do
render :json => #movies.to_json(:include => { :trailers => { :only => [:id, :movie_id, :link] } })
end
end
end
if you want to include particular trailers for movies
then in movie model
For rails > 4
has_many :trailers, -> { where(id: self.movie_id) }

Related

Selecting distinct values from a JSON -- in ruby

I have a json data like below :
data :[
{
"application_number": 1274930,
"status": "Removed",
},
{
"application_number": 1550670,
"status": "Registered",
},
{
"application_number": 1562368,
"status": "Registered",
},
{
"application_number": 1625492,
"status": "Objected",
},
{
"application_number": 1644092,
"status": "Registered",
},
{
"application_number": 1691808,
"status": "Removed",
},
{
"application_number": 1726161,
"status": "Registered",
}
]
I want to get the unique values of status only. Something like this:
["Removed", "Objected", "Registered"]
I found a similar question and solution there was in javascript :- _.keys(_.countBy(data, function(data) { return data.name; }));
Is there a similar way in ruby to find this ?
you achieve this by following ways:
uniq_status = []
data.each do |tupple|
uniq_status << tupple['status'] if status.include?(tupple['status'])
end
uniq_tupple
#$> ["Removed", "Objected", "Registered"
data.collect{|tupple|tupple["status"]}.uniq
#$> ["Removed", "Objected", "Registered"
data.group_by {|tupple| tupple["status"]}.keys
#$> ["Removed", "Objected", "Registered"
data.uniq {|tupple| tupple["status"]}.collect{|tupple|tupple['status']}
#$> ["Removed", "Objected", "Registered"
I hope this will help you.

Elasticsearch Find Out does user stops or moving - Possible?

I want to use elasticsearch configuration about mapping to display user location and his/her direction to admin in my web app. so I create an index in elasticsearch like:
{
"settings": {
"index": {
"number_of_shards": 5,
"number_of_replicas": 1
},
"analysis": {
"analyzer": {
"analyzer-name": {
"type": "custom",
"tokenizer": "keyword",
"filter": "lowercase"
}
}
}
},
"mappings": {
"properties": {
"driver_id": { "type": "integer" },
"email": { "type": "text" },
"location": { "type": "geo_point" },
"app-platform": { "type": "text" },
"app-version": { "type": "text" },
"created_at": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"}
}
}
}
and start to inserting user location to elasticsearch with this curl
{
"driver_id": 357,
"driver_email": "Andrew#mailinatior.com",
"location": {
"lat": 37.3,
"lon": 59.52
},
"created_at": "2021-06-04 00:09:00"
}
this structure came from user mobile to my elasticsearch, after that I wrote these services to fetch data for my web-end part of my designing:
module Api
module V1
module Drivers
module Elastic
class LiveLocation
include Peafowl
attribute :driver_id, ::Integer
def call
#driver = ::Driver.find(driver_id) if driver_id.present?
result = []
options = {
headers: {
'Content-Type' => 'application/json'
},
body: #driver.present? ? options_with_driver : options
}
begin
response = HTTParty.get(elasticseach_url.to_s, options)
records = JSON.parse(response.body)['hits']['hits']
if records.present?
records.group_by { |r| r['_source']['driver_id'] }.to_a.each do |record|
driver = ::Driver.where(id: record[0]).first
if driver.present?
location = record[1][0]['_source']['location']
app_platform = record[1][0]['_source']['app-platform']
app_version = record[1][0]['_source']['app-version']
result.push(driver_id: driver.id, driver_email: driver.profile.email, location: location, app_platform: app_platform, app_version: app_version)
end
end
end
rescue StandardError => error
Rails.logger.info "Error => #{error}"
result = []
end
context[:response] = result
end
def elasticseach_url
"#{ENV.fetch('ELASTICSEARCH_BASE_URL', 'http://127.0.0.1:9200')}/#{ENV.fetch('ELASTICSEARCH_DRIVER_POSITION_INDEX', 'live_location')}/_search"
end
def options
{
query: {
bool: {
filter: [
{
range: {
created_at: {
gte: (Time.now.beginning_of_day.strftime '%Y-%m-%d %H:%M:%S')
}
}
}
]
}
},
sort: [
{
created_at: {
order: 'desc'
}
}
]
}.to_json
end
def optinos_with_driver
{
query: {
bool: {
must: [
{
term: {
driver_id: {
value: #driver.id
}
}
}
],
filter: [
{
range: {
created_at: {
gte: (Time.now.beginning_of_day.strftime '%Y-%m-%d %H:%M:%S')
}
}
}
]
}
},
sort: [
{
created_at: {
order: 'desc'
}
}
]
}.to_json
end
end
end
end
end
end
this structure working perfectly but even if the user stops while elasticsearch saves his location but I need to filter user data that if the user stops for one hour in place elasticsearch understand and not saving data. Is it possible?
I use elsticsearch 7.1
and ruby 2.5
I know it's possible in kibana but I could not using kibana at this tim.
I am not sure if this can be done via a single ES query...
However you can use 2 queries:
one to check if the user's location's during the last hour is the same
Second same then don't insert
But i don't recommend that
What you could do:
Use REDIS or any in-mem cache to maintain the user's last geo-location duration
Basis that, update or skip update to Elastic Search
PS: I am not familiar with ES geo-location API

Node as Hash not Array in RABL

I have this RABL template:
object :#pollution => nil
attributes :id, :time
node :components do |p|
p.components.map do |component|
{ component.name => { level: component.level, main: component.main } }
end
end
It renders
{ "id":820,
"time":"2017-05-12 20:00:00 UTC",
"components": [ # I don't need this array
{ "component1": { "level": 3, "main": false } },
{ "component2": { "level": 5, "main": false } },
]
}
And I want this
{ "id":820,
"time":"2017-05-12 20:00:00 UTC",
"components": {
"component1": { "level": 3, "main" :false },
"component2": { "level": 5, "main" :false },
}
}
So, instead of array of components, I need a hash, where keys will be components names and value — hash with components data (level(Int) and main(Bool)).
I tried to render child :components, but it also renders an array.
Thanks for any help!
To get what you want, you need to change these lines:
p.components.map do |component|
{ component.name => { level: component.level, main: component.main } }
end
which are returning an array, to something like:
p.components.inject({}) do |components, component|
components[component.name] = { level: component.level, main: component.main }
components
end
that will build a hash instead of an array.

Rails 4 - Iterate through nested JSON params

I'm passing nested JSON into rails like so:
{
"product": {
"vendor": "Acme",
"categories":
{
"id": "3",
"method": "remove",
},
"categories":
{
"id": "4"
}
}
}
in order to update the category on a product. I am trying to iterate through the categories attribute in my products_controller so that I can add/remove the product to multiple categories at once:
def updateCategory
#product = Product.find(params[:id])
params[:product][:categories].each do |u|
#category = Category.find_by(id: params[:product][:categories][:id])
if params[:product][:categories][:method] == "remove"
#product.remove_from_category(#category)
else
#product.add_to_category(#category)
end
end
end
However, this only uses the second 'categories' ID in the update and doesn't iterate through both.
Example response JSON:
{
"product": {
"id": 20,
"title": "Heavy Duty Aluminum Chair",
"product_price": "47.47",
"vendor": "Acme",
"categories": [
{
"id": 4,
"title": "Category 4"
}
]
}
}
As you can see, it only added the category with ID = 4, and skipped over Category 3.
I'm fairly new to rails so I know I'm probably missing something obvious here. I've played around with the format of the JSON I'm passing in as well but it only made things worse.
You need to change your JSON structure. As you currently have it, the second "categories" reference will override the first one since you can only have 1 instance of a key. To get what you want, you should change it to:
{
"product": {
"vendor": "Acme",
"categories": [
{
"id": "3",
"method": "remove",
},
{
"id": "4"
}
]
}
}
You will also need to change your ruby code to look like:
def updateCategory
#product = Product.find(params[:id])
params[:product][:categories].each do |u|
#category = Category.find_by(id: u[:id])
if u[:method] == "remove"
#product.remove_from_category(#category)
else
#product.add_to_category(#category)
end
end
end

How do get LineString to show using Leaflet?

I have pipe model in my database and it has geometry attribute (LineString). I added this to pipes_controller.rb:
def index
#pipes = Pipe.all
#geojson = Array.new
#pipes.each do |pipe|
#geojson<< {
type: "FeatureCollection",
crs: { type: "name", properties: { name: "urn:ogc:def:crs:OGC:1.3:CRS84" } },
features: [
type: 'Feature',
properties: {
geometry: {
type: 'LineString',
coordinates: pipe.get_coordinates
},
stroke: "#1087bf"
}
]}
end
respond_to do |format|
format.html
format.json { render json: #geojson } # respond with the created JSON object
end
end
This is pipes.js file:
$(document).ready(function() {
if ($("#pipes_map").length>0) {
var geojson;
var map = L.map('pipes_map', {
center: [42.44, 19.26],
zoom: 16
});
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
max_zoom: 22
}).addTo(map);
L.geoJson(geojson).addTo(map);
$.ajax({
dataType: 'text',
url: 'http://localhost:3000/pipes.json',
success: function(data) {
var myStyle = {
"color": "#ff7800",
"weight": 5,
"opacity": 0.65
};
geojson = $.parseJSON(data);
L.geoJson(geojson).addTo(map);
},
error : function() {
alert('Error!');
}
})
}
})
But my pipes don't appear on the map. What am I doing wrong? Maybe my pipes.json is poorly formated? Or style is not ok?
This is what the controller should look like:
def index
#pipes = Pipe.all
#geojson = Array.new
#pipes.each do |pipe|
#geojson<< {
type: 'Feature',
properties: {
:category=> pipe.category.name
},
geometry: {
type: 'LineString',
coordinates: pipe.get_coordinates
}
}
end
respond_to do |format|
format.html
format.json { render json: #geojson } # respond with the created JSON object
end
end
The rest is fine.

Resources