Querying nested arrays in Postgres JSON field with Rails - ruby-on-rails

I am using Postgres 9.3 json data type. I want to do a query with data that is nested within the array.
For example, I want to query for users that have all of this interests = ["music", "movies", "programming"].
Thanks!
Example:
model User
data: {
"name": "johndoe1",
"github": "johndoe1",
"bio": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Labore impedit aliquam sapiente dolore magni aliquid ipsa ad, enim, esse ut reprehenderit quaerat deleniti fugit eaque. Vero eligendi voluptatibus atque, asperiores.",
"blog": "http://johndoe1.example.com",
"interests": [
"music",
"movies",
"programming"
],
"age": 35,
"newsletter": true
}
User.where("data -> 'interests' = '[\"music\", \"movies\", \"programming\"]'") not working.

Related

How to render content from nested json object in ruby on rails view

I'm trying to render data from a API response (JSON) into my view.
For some reason i only can access the toplevel objects withouth any issues. BUt my knowledge is limited when it commes to retrieve the data from a nested object.
Woul appreciate if anybody can help me out.
controller.rb
require 'httparty'
class BlogController < ApplicationController
include HTTParty
def show
id = params[:id]
get("posts/#{id}")
end
def index
get('posts')
end
private
def get(path)
#host = 'api.example.com'
#blog = HTTParty.get('https://' + #host + '/' + path )
#post = HTTParty.get('https://' + #host + '/' + path )
return false if response.status != 200
puts response.body
end
end
view.html.erb
<p id="notice"><%= notice %></p>
<h2><%= #post["title"] %></h2>
<p><%= #post["description"] %></p>
<p><%= #post["content"] %></p>
<p><%= #post["heroimage.url"] %></p> <# This here is the problem how to render the url object which is part of "heroimage" parent
JSON response which i'm consuming:
{
"id": 1,
"title": "First Post",
"description": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam",
"content": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. \n\n![g-000261-g_W2615899_6-ktm-300-exc-637602315686776824.jpg](/uploads/g_000261_g_W2615899_6_ktm_300_exc_637602315686776824_a3b44fdf00.jpg)\n\n\nDuis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. ",
"author": null,
"created_at": "2021-10-28T21:31:10.445Z",
"updated_at": "2021-11-10T17:54:36.175Z",
"heroimage": {
"id": 1,
"name": "g-000261-g_W2615899_6-ktm-300-exc-637602315686776824.jpg",
"alternativeText": "",
"caption": "",
"width": 2048,
"height": 1536,
"formats": {
"large": {
"ext": ".jpg",
"url": "/uploads/large_g_000261_g_W2615899_6_ktm_300_exc_637602315686776824_a3b44fdf00.jpg",
"hash": "large_g_000261_g_W2615899_6_ktm_300_exc_637602315686776824_a3b44fdf00",
"mime": "image/jpeg",
"name": "large_g-000261-g_W2615899_6-ktm-300-exc-637602315686776824.jpg",
"path": null,
"size": 184.83,
"width": 1000,
"height": 750
},
"small": {
"ext": ".jpg",
"url": "/uploads/small_g_000261_g_W2615899_6_ktm_300_exc_637602315686776824_a3b44fdf00.jpg",
"hash": "small_g_000261_g_W2615899_6_ktm_300_exc_637602315686776824_a3b44fdf00",
"mime": "image/jpeg",
"name": "small_g-000261-g_W2615899_6-ktm-300-exc-637602315686776824.jpg",
"path": null,
"size": 50.69,
"width": 500,
"height": 375
},
"medium": {
"ext": ".jpg",
"url": "/uploads/medium_g_000261_g_W2615899_6_ktm_300_exc_637602315686776824_a3b44fdf00.jpg",
"hash": "medium_g_000261_g_W2615899_6_ktm_300_exc_637602315686776824_a3b44fdf00",
"mime": "image/jpeg",
"name": "medium_g-000261-g_W2615899_6-ktm-300-exc-637602315686776824.jpg",
"path": null,
"size": 110.16,
"width": 750,
"height": 563
},
"thumbnail": {
"ext": ".jpg",
"url": "/uploads/thumbnail_g_000261_g_W2615899_6_ktm_300_exc_637602315686776824_a3b44fdf00.jpg",
"hash": "thumbnail_g_000261_g_W2615899_6_ktm_300_exc_637602315686776824_a3b44fdf00",
"mime": "image/jpeg",
"name": "thumbnail_g-000261-g_W2615899_6-ktm-300-exc-637602315686776824.jpg",
"path": null,
"size": 10.56,
"width": 208,
"height": 156
}
},
"hash": "g_000261_g_W2615899_6_ktm_300_exc_637602315686776824_a3b44fdf00",
"ext": ".jpg",
"mime": "image/jpeg",
"size": 711.13,
"url": "/uploads/g_000261_g_W2615899_6_ktm_300_exc_637602315686776824_a3b44fdf00.jpg",
"previewUrl": null,
"provider": "local",
"provider_metadata": null,
"created_at": "2021-11-10T16:22:27.152Z",
"updated_at": "2021-11-10T16:22:27.169Z"
}
}
As mentioned i'm trying to display the url (which is one level under "heroimage").
Shouldn't something like
#post[:heroimage][:url]
or
#post['heroimage']['url']
work?
With ruby, you should be able to treat the keys like a symbol. and ruby won't use dot notation in a hash so you would need to use square brackets.
You will have to convert response from json to Hash and for that use this:
parsed_response = JSON.parse(response.body)
After that it is just a hash so you can access simply like following:
parsed_response['heroimage']['url']
I would recommend to use dig here
parsed_response.dig('heroimage', 'url')
If you want a structured object then I would recommend to use RecursiveOpenStruct it will make all fields as nested object attributes
structured = RecursiveOpenStruct.new(parsed_response)
structured.heroimage.url

Activemodel Serializer with custom attributes

I have to return a json to my frontend with a structure like this
{
"meta": {
"page": 1,
"pages": 1,
"perpage": -1,
"total": 40,
"sort": "asc",
"field": "RecordID"
},
"data": [
{
"RecordID": 1,
"OrderID": "61715-075",
"Country": "China",
"ShipCountry": "CN",
"ShipCity": "Tieba",
"ShipName": "Collins, Dibbert and Hoeger",
"ShipAddress": "746 Pine View Junction",
"CompanyEmail": "nsailor0#livejournal.com",
"CompanyAgent": "Nixie Sailor",
"CompanyName": "Gleichner, Ziemann and Gutkowski",
"Currency": "CNY",
"Notes": "imperdiet nullam orci pede venenatis non sodales sed tincidunt eu felis fusce posuere felis sed lacus morbi",
"Department": "Outdoors",
"Website": "irs.gov",
"Latitude": 35.0032213,
"Longitude": 102.913526,
"ShipDate": "2/12/2018",
"PaymentDate": "2016-04-27 23:53:15",
"TimeZone": "Asia/Chongqing",
"TotalPayment": "$246154.65",
"Status": 3,
"Type": 2,
"Actions": null
},
{
"RecordID": 2,
"OrderID": "63629-4697",
"Country": "Indonesia",
"ShipCountry": "ID",
"ShipCity": "Cihaur",
"ShipName": "Prosacco-Breitenberg",
"ShipAddress": "01652 Fulton Trail",
"CompanyEmail": "egiraldez1#seattletimes.com",
"CompanyAgent": "Emelita Giraldez",
"CompanyName": "Rosenbaum-Reichel",
"Currency": "IDR",
"Notes": "adipiscing elit proin risus praesent lectus vestibulum quam sapien varius ut blandit non interdum",
"Department": "Toys",
"Website": "ameblo.jp",
"Latitude": -7.1221059,
"Longitude": 106.5701927,
"ShipDate": "8/6/2017",
"PaymentDate": "2017-11-13 14:37:22",
"TimeZone": "Asia/Jakarta",
"TotalPayment": "$795849.41",
"Status": 6,
"Type": 3,
"Actions": null
},
{....}
]
}
I'm using a serializer with the Netflix json library.
I know how to return the collection:
render json: ContentSerializer.new(#contents).serializable_hash
Return me the data collection, but I cannot understand how can I add the 'meta' attribute

Swift TableView not showing any data

I am trying to show a list of all project names in a table view however my tableview is empty and shows nothing. I dragged the tableview from my storyboard to the tableView IBOutlet in ProjectViewController class. I ultimately want to request the data from the server but I am using dummy data until I can get the view working. I am using swift 3 and xcode.
class ProjectViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
// MARK: Properties
#IBOutlet weak var tableView: UITableView!
let projectsJson = [
"projects" : [
[
"id": "1",
"name": "Molestiae labore qui ut quam aut provident.",
"summary": "Ut rerum quia similique perferendis reiciendis officiis. Id aliquid possimus sunt suscipit.",
"executive_summary": "Eius ipsa quia enim enim suscipit. Iste dolor ea dolore occaecati ducimus deserunt. Vero fugit omnis dolorem. Perspiciatis quas et commodi aliquam labore consequuntur est eaque.",
"system_scope": "Est eos deleniti perspiciatis cupiditate numquam saepe ut. Laborum consequuntur ullam aperiam magnam. Aliquam nisi ut quia. Consequatur aut molestias vero debitis. Autem id harum asperiores neque sit iusto soluta.",
"proposed_project": "Ut dolores officiis sit ut corporis consequatur. Aliquam enim sapiente fugit aut aspernatur modi qui molestias. Atque aspernatur optio qui temporibus repudiandae. Voluptas libero beatae soluta vel distinctio accusantium. Qui ducimus placeat ut nam dignissimos ut."
],
[
"id": "2",
"name": "Repellat voluptatem ut laboriosam officiis quo error ut.",
"summary": "Ducimus quo esse consequatur sequi suscipit et. Velit maiores maxime ut distinctio. Assumenda et corrupti tempora accusamus dolores et fugiat. Incidunt sapiente nam est eum rerum error. Molestiae velit neque omnis aliquid qui.",
"executive_summary": "Praesentium quae perferendis ipsam sapiente earum. Voluptates accusantium consequatur voluptatum.",
"system_scope": "Eaque sint quis id doloremque voluptas. Mollitia hic velit et et. Id et qui eum non.",
"proposed_project": "Qui qui est sed quod ut vel et. Omnis placeat ea sint alias rerum rerum a aut. Et necessitatibus incidunt incidunt aspernatur est magni. Et non vitae non incidunt nam odio."
],
[
"id": "3",
"name": "Saepe reiciendis excepturi est sequi.",
"summary": "Asperiores rerum laboriosam asperiores aut rerum in dolor. Qui quia et aperiam laborum animi quia.",
"executive_summary": "Aut vero non id nulla voluptatum dignissimos alias. Deserunt sint rem laboriosam consequuntur. Illum molestiae ipsum inventore explicabo.",
"system_scope": "Praesentium numquam aut eveniet neque. Et sed repellat distinctio dolorem. Sit ex doloremque nisi ipsam ullam ut rem. Error molestias consectetur omnis quaerat consequatur sed et.",
"proposed_project": "Veniam expedita rerum voluptas accusantium laudantium aut. Reiciendis architecto optio labore iste rem et. Fuga quasi et et omnis molestias."
],
[
"id": "4",
"name": "Sint provident et aperiam et.",
"summary": "Enim eum amet aspernatur. Et cumque qui nisi. Amet distinctio et ut aut perferendis ea vel. Velit quas nesciunt et quaerat ea ullam culpa. Dolores qui est aut quis est.",
"executive_summary": "Omnis et at exercitationem consequatur quaerat. Sed eligendi modi quibusdam et quo. Nesciunt perferendis officiis modi consequatur. Quas id rerum earum rerum rerum harum.",
"system_scope": "Incidunt ut necessitatibus animi. Id adipisci culpa sed est ut quam asperiores cupiditate. Ut incidunt aperiam libero voluptatem.",
"proposed_project": "Velit quis est vitae nam et delectus pariatur. Deleniti odio nihil quo libero dolorum. Fugiat iusto in dignissimos quisquam enim doloribus illo. Sint suscipit ducimus et totam doloremque optio enim."
],
[
"id": "5",
"name": "Animi velit itaque eligendi est.",
"summary": "Consequatur ea laudantium dicta non asperiores qui sapiente. Est dolor laboriosam nostrum a cupiditate. Ratione nemo eaque ut sit velit.",
"executive_summary": "Ullam ex animi asperiores in laboriosam rem. Repellendus et amet minus voluptas illum. Voluptatem nisi officia accusantium et eum.",
"system_scope": "Corrupti est ad earum dolorum quo. Blanditiis debitis dolorum maxime voluptatum quisquam vitae. Similique repellendus rerum aspernatur sint officiis. Suscipit qui eius autem qui saepe in ut et.",
"proposed_project": "Aut velit a illo nostrum iure temporibus vel. Eos est dignissimos distinctio dignissimos voluptas. Sit tenetur error accusantium voluptatum recusandae aut. Assumenda quod quo sint sed debitis eum."
]
]
]
var projects : [Project] = []
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return projects.count;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "ProjectCell")
let project = projects[indexPath.row]
cell.textLabel?.text = project.name
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.row)!")
}
override func viewDidLoad() {
super.viewDidLoad()
projects = ProjectWrapper.projectArrayFromJSON(json: projectsJson)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
Project class
class Project{
let name: String
let id: Int
let summary: String
let executiveSummary: String
let systemScope: String
let proposedProject: String
public init?(name: String, id: Int, summary: String, executiveSummary: String, systemScope: String, proposedProject: String) {
self.name = name
self.id = id
self.summary = summary
self.executiveSummary = executiveSummary
self.systemScope = systemScope
self.proposedProject = proposedProject
}
func getName() -> String {
return name;
}
func getId() -> Int {
return id;
}
func getSummary() -> String{
return summary
}
func getExecutiveSummary() -> String{
return executiveSummary
}
func getSystemScope() -> String{
return systemScope
}
func getProposedProject() -> String{
return proposedProject
}
func getUrlExtension() -> String{
return "project/" + String(id)
}
}
class ProjectWrapper{
static func projectArrayFromJSON(json: [String : Any]) -> [Project]{
let jsonProjects = json["projects"] as! [[String: String]]
var projects: [Project] = []
for project in jsonProjects{
let thisProject = Project(name: project["name"]!, id: Int(project["id"]!)!, summary: project["summary"]!, executiveSummary: project["executive_summary"]!, systemScope: project["system_scope"]!, proposedProject: project["proposed_project"]!)
projects.append(thisProject!)
}
return projects
}
}
Thanks for any advice
Did you set the dataSource and delegate for the tableview? If not, you can specify the dataSource, by going to the outlet view:
and drag the dataSource outlet to your view controller
Putting self.tableView.delegate = self in viewDidLoad() will achieve the same thing, programatically.

Upload an array of images in a JSON object with Alamofire

I'm developing an iOS app and need to make an Post request with a json object that looks like this:
{
"id": 30645,
"obj1": [
{
"id": 21649,
"comment":"Lorem ipsum dolor sit amet,",
"obj2": [
{
"id": 42070,
"comment": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum lacinia, urna sed gravida fringilla, elit",
"obj3": [
{
"id": 518964,
"active": false
}
],
"images": [UImage, UIImage, UIImage]
}
],
"status": 1
}
]
}
My question is: what is the best way to do this?
EDIT:
The issue is the array of UIImage, what can i do with that? Transform to base64 or use the multipart solution that Alamofire provides?
Thanks for your time.
P.D. I'm using Alamofire 4.0 and Swift 3

Generating this type of URI http://localhost:3000/api/products?ids=1,2,3,4

I have this http://localhost:3000/api/products request that returns json format output with a list of products objects. I heard in some scenario its better to use multi-gets design where you list products ids in URI like so http://localhost:3000/api/products?ids=1,2,3,4. My question is how do i configure the route to return such an URI? Below is the json output returned by http://localhost:3000/api/products.Thank you in advance
controller
def index
#products=Product.all
respond_to do |format|
format.json { render json: #products.to_json}
format.xml
end
end
json output
[
{
"category_id": null,
"created_at": "2011-03-25T13:35:16Z",
"details": "Molestias pariatur consequuntur ut voluptas aperiam facere et et autem ad laudantium ut qui dolorem iste sit ut in dignissimos. Et debitis et et sunt quidem qui est est et numquam in dolorum natus sapiente nihil ipsa ratione. Quisquam aut molestiae earum voluptas vero et officiis magnam quam provident voluptatibus quia",
"id": 1,
"product_name": "Velit",
"publisher_id": 1,
"updated_at": "2012-11-12T18:45:13Z",
"publisher_details": "http://localhost:3000/api/users/1"
},
{
"category_id": null,
"created_at": "2012-01-10T23:16:53Z",
"details": "Temporibus quis et quam eveniet hic consequatur maiores eum expedita molestiae velit eligendi laboriosam ut molestiae. Velit delectus aliquid nobis quia velit aut dolorem omnis numquam reprehenderit quo illo saepe molestiae nisi. Soluta nihil quae soluta facilis cumque voluptates eaque amet unde non in placeat id cupiditate illum at et vero. Laborum id eaque voluptas illo eius iure",
"id": 2,
"product_name": "Nam Laboriosam Et Sed",
"publisher_id": 1,
"updated_at": "2012-11-12T18:45:13Z",
"publisher_details": "http://localhost:3000/api/users/1"
}]
There is a gem, which is discontinued, which was written for sproutcore (now ember) that offered this out of the box: https://github.com/drogus/bulk_api
But actually, it does not have to be that hard at all. For a single controller I would just do something like
def index
ids = params[:ids]
if ids.blank?
#categories = Category.all
else
wanted_ids = ids.split(',')
#categories = Categoriy.where(:id => wanted_ids)
end
render :json => #categories
end
Does that help?

Resources