Now i have used the as_json method like this in my model
def as_json(options = {})
{
id: id,
diary_id: diary_id,
title: title,
post_date_gmt: date,
post_content: strip_tags(content),
smiley_id: smiley_id,
author_id: user_id,
author_name: user.display_name,
attachments: filter_attachments(options[:version]),
root_comments: format_comments(nested_comments.arrange(:order => :created_at)),
post_readings: post_readings.size,
is_read: read_by(options[:current_user])
}
end
I need to change this structure a bit as follows, Actually i want group this array by the date.
{
date_01: {
[post1], [post2], [post3]
},
date_02: {
[post1], [post2], [post3]
}
}
What should I do ?
I fixed the issue as follows
post_dates = (no_of_days.days.ago.to_date..(date_as_string.to_date + no_of_days.days)).map{ |date| date.strftime("%Y-%m-%d") }
# Arrange posts details under each date
i = 0
post_dates.each do |post_date|
posts_grouped_by_date[i] = {:post_date => post_date, :posts_for_date => diary.posts_for_date(Date.parse(post_date) )}
i = i + 1
end
render json: posts_grouped_by_date.sort_by {|hash| hash['post_date']}.as_json(current_user: current_user)
replace the values of data keys to an array of arrays. like below.
{
date_01: [
[post1], [post2], [post3]
],
date_02: [
[post1], [post2], [post3]
]
}
Related
I have following array of hash. I am trying to loop over it and build an array of hash of values of id and product_order_id.
objects =
[
#<Product: 0x00007ffd4a561108
#id="1",
#product_id="2",
#product_order_id="23",
#description="abc",
#status="abcde",
#start_date=nil,
#end_date=nil>,
#<Product: 0x00007ffd4a560c80
#id="45",
#product_id="22",
#product_order_id="87",
#description="ahef",
#status="gesff",
#start_date=nil,
#end_date=nil>
......more objects.....
]
This is what it should look like
[{ "1": "23" }, { "45": "87" }] -->its going to be uuid
I tried doing this but no luck
def mapped_product(objects)
mapping = []
objects.each do |object|
mapping << {
object.product_order_id: object.id
}
end
end
Any idea?
inline solution:
> Hash[objects.map{|p| [p.id, p.product_order_id] }]
# Output : [{ 1=>23 }, { 45=>87 }]
I'd usually implement it using an each_with_object
objects.each_with_object({}) { |obj, acc| acc[obj.id] = obj.product_order_id }
Unless I reaaaly want to squeeze some performance, than I'd go with Gagan's answer
Have you tried this?
def mapped_product(objects)
mapping = []
objects.each do |object|
mapping << {
object.id => object.product_order_id # I'm using an `=>` here
}
end
mapping # return the new mapping
end
I've just changed the : on the hash for a => to "make it dynamic" and swapped the values of id and product_order_id
You can also use a map here:
def mapped_product(objects)
objects.map do |object|
{ object.id => object.product_order_id }
end
end
I want to join items from 2 tables. There output:
"costs":[
{
"id":2,
"cost_name":"rent office",
"user_id":2,
"fix":true,
"amount":300300,
"created_at":"2018-11-05T18:36:19.108+06:00",
"updated_at":"2018-11-05T18:36:19.108+06:00"
},
{
"id":3,
"cost_name":"new computer",
"user_id":2,
"fix":false,
"amount":350000,
"created_at":"2018-11-06T14:44:49.805+06:00",
"updated_at":"2018-11-06T14:44:49.805+06:00"
}
],
"users":[
[
"Vi_Ok",
2
]
]
}
I want to add parameter of users (user name which is "Vi_Ok") add to every cost. How you noticed there in both table exist userId. Now code looks:
def index
#costs = Cost.all
#user_name = #costs.pluck(:user_id)
#user_name = User.find(#user_name).pluck(:name, :id)
# #costs.push("name" => #user_name.pluck(:name) this one just try to add
render json: {costs: #costs, name: #user_name}
end
You can write a custom method in your model and call it in index action, which returns all the costs with the username like below:
def self.list_costs
cost_list = []
costs = Cost.all
costs.each do |cost|
cost_info = cost.attributes
cost_info[:user_name] = cost.user.name
cost_list << cost_info
end
cost_list
end
class CostsController < ApplicationController
def index
render json: {costs: Cost.cost_list }
end
end
Supposing User has_many Costs,
What you provided,
hash = {"costs"=>[{"id"=>2, "cost_name"=>"rent office", "user_id"=>2, "fix"=>true, "amount"=>300300, "created_at"=>"2018-11-05T18:36:19.108+06:00", "updated_at"=>"2018-11-05T18:36:19.108+06:00"}, {"id"=>3, "cost_name"=>"new computer", "user_id"=>2, "fix"=>false, "amount"=>350000, "created_at"=>"2018-11-06T14:44:49.805+06:00", "updated_at"=>"2018-11-06T14:44:49.805+06:00"}], "users"=>[["Vi_Ok", 2]]}
Proceed,
costs, users = hash['costs'], hash['users']
costs.each { |c| c['user_name'] = users.detect { |u| u[1] == c['user_id'] }[0] }
Above will add user_name in each cost hash.
I am learning ruby and I am playing with a sample data. I converted following hash into an array of objects as follows.
class Openstruct
require 'JSON'
require 'ostruct'
HASH = {
items: [
{
health: [
{
goal: [
{
activity: [
{
id: "1A"
},
{
id: "2A"
}
],
id: "GA"
}
],
activity: [
{
id: "1B"
},
{
id: "2B"
}
],
id: "GB"
}
],
goal: [
{
activity: [
{
id: "1C"
},
{
id: "2C"
},
],
id: "3c"
}
],
createdAt: "2018-01-01",
updatedAt: "2018-01-01",
id: "DA"
}
],
}
def self.all
json = HASH.to_json
JSON.parse(json, object_class: OpenStruct)
end
end
Above returns me following result
#<OpenStruct items=
[#<OpenStruct health=
[#<OpenStruct goal=
[#<OpenStruct activity=
[#<OpenStruct id="1A">, #<OpenStruct id="2A">], id="GA">],
activity=[#<OpenStruct id="1B">, #<OpenStruct id="2B">], id="GB">],
goal=[#<OpenStruct activity=[#<OpenStruct id="1C">, #<OpenStruct id="2C">], id="3c">],
createdAt="2018-01-01",
updatedAt="2018-01-01",
id="DA">]>
However, i want to convert the array of object having id's into array of values of ids. e.g [#<OpenStruct id="1A">, #<OpenStruct id="2A">] --> ["1A", "2A"]. so i want the final result as follows:
#<OpenStruct items=
[#<OpenStruct health=
[#<OpenStruct goal=
[#<OpenStruct activity=
["1A","2A"], id="GA">],
activity=["1B", 2B"], id="GB">],
goal=[#<OpenStruct activity=["1C","2C"], id="3c">],
createdAt="2018-01-01",
updatedAt="2018-01-01",
id="DA">]>
Does anyone know how to do that?
You will have to check the child node recursively until you find the OpenStruct with only :id element. Following is the working code for your sample data.
def self.convert_struct_id(os)
# Get possible attributes of any open_struct
attributes = os.to_h.keys
# Only get id_value if :id is the only attribute of open_struct
if attributes.length == 1 && attributes.first == :id
id_value = os.send(:id)
return id_value
end
# Iterate through attributes
attributes.each do |attr|
# Get child elements
data = os.send(attr)
case data
when OpenStruct
convert_struct_id(data)
when Array
# Recursively process for child node
data.map! { |d| convert_struct_id(d) }
end
end
return os
end
Your self.all method will look like this
def self.all
json = HASH.to_json
os = JSON.parse(json, object_class: OpenStruct)
res = convert_struct_id(os)
end
Result:
=> #<OpenStruct items=[#<OpenStruct health=[#<OpenStruct goal=[#<OpenStruct activity=["1A", "2A"], id="GA">], activity=["1B", "2B"], id="GB">], goal=[#<OpenStruct activity=["1C", "2C"], id="3c">], createdAt="2018-01-01", updatedAt="2018-01-01", id="DA">]>
On a single instance, validation would produce something like:
foo = Foo.new(price: -2)
foo.valid?
foo.errors
=> #<ActiveModel::Errors:0x00007fc66e670430
#base=#<Foo:0x00007fc6503f8658 id: nil, price: nil,
#details={:price=>[{:error=>:greater_than_or_equal_to, :value=>-0.2e1, :count=>0}]},
#messages={:price=>["must be greater than or equal to 0"]}>
Is there a rails way of obtaining the errors when using the update method?:
Foo.update([1, 2, 3], [{ price: 10 }, { price: -20 }, { price: 3 }])
Thank you!
Here is an example how to gather errors from the Model.update(...) method:
# first create a payload with ids and attributes
payload = { 1 => { price: 10 }, 2 => { price: -20 } }
# next update records
result = Foo.update(payload.keys, payload.values)
# the update method returns processed records
# in case of array it will return array of records
# iterate over all objects and find invalid
with_errors = result.map { |r| !r.errors.any? ? nil : r }.compact
# after compact the with_errors variable contains only invalid records.
What I did in the end:
class FooUpdateService
attr_reader :errors
def update(ids, values)
self.errors = ActiveModel::Errors.new(Foo.new)
Foo.update(ids, values).select(&:invalid?).each { |invalid_foo| self.errors.merge!(invalid_foo.errors) }
end
private
attr_writer :errors
end
In my Rails Application i have Two instance variables #departments and #register
#departments =
{
"users": [
{
"departmentid": "DP11"
},
{
"departmentid": "DP12"
},
{
"departmentid": "DP13"
},
{
"departmentid": "DP10"
}
]
}
#register =
{
"attendance": [
0,
0,
2,
1
]
}
#register contains an array .
Is it possible to show like below format using rabl (attendancebydepartment.json.rabl) view
{
"users": [
{
"departmentid": "DP11",
"attendance"=0
},
{
"departmentid": "DP12",
"attendance"=0
},
{
"departmentid": "DP13",
"attendance"=2
},
{
"departmentid": "DP10",
"attendance"=1
}
]
}
My controller looks like
def attendancebydepartment
#register = Array.new
#departments = User.select('departmentid').uniq
startdate = params[:startdate]
enddate = params[:enddate]
#count = #departments.count
#departments.each do |d|
#register << (Register.where(:date => startdate..enddate , :departmentid => d.departmentid).sum(:one))+(Register.where(:date => startdate..enddate , :departmentid => d.departmentid).sum(:two))
end
end
Is it possible to add each department and its corresponding attendance to array,so that i can display like expected format.
Perhaps use the zip method to create a new variable and then present that.
irb(main):001:0> departments = {'users' => [{'id' => 1}, {'id' => 2}]}
=> {"users"=>[{"id"=>1}, {"id"=>2}]}
irb(main):002:0> register = {'attendance' => [0,1]}
=> {"attendance"=>[0, 1]}
irb(main):004:0> departments['users'].zip(register['attendance'])
=> [[{"id"=>1}, 0], [{"id"=>2}, 1]]
On the other hand, it looks like a simpler design would be to have a Department model that has a has_many association with Users. Then you could refer to the count of users directly from an instance of Department.
It may be easiest to create objects in your controller using OpenStruct, something like this, but I would recommend re-writting attendancebydepartment to not loop twice.
#users = []
#departments.each_with_index do |dep, index|
user = OpenStruct.new
user.departmentid = dep.departmentid
user.attendence = #register[index].attendence
#users << user
end
And in the view:
collection #users => :users
attribute :departmentid, :attendence