How to use each do in Rails within Chartkick - ruby-on-rails

My HTML looks like:
<%= column_chart #data, stacked: true %>
In my controller I created the data field:
#values = WorkingMonth.select("date_end","workload").where(personal_id: #current_employee.personal_id)
#values.each do |data|
#data = [
{
name: "Available",
data: []
},
{
name: "Workload",
data:[[data.date_end.strftime("%B"),data.workload]]
}
]
end
My problem is in #values there are more than only one value but it shows me only the last one. How can I use each do with this data field?
Thanks in advance
UPDATE:
I've changed my data field like:
#data = #values.map do |value|
#data = [
{name: "Available", data: []},
{name: "Workload", data:[[value.date_end.strftime("%B"),value.workload]]}
]
end
After changing the result looks like:
Column Chart

You should use map instead of each since you want convert #values array:
#data = #values.map do |value|
[
{ name: "Available", data: [] },
{ name: "Workload", data: [[value.date_end.strftime("%B"),value.workload]] }
]
end

I changed the way to think and stopped using .each/.map do. I've used "group" and "DATE_TRUNC". The answer to my problem looks like:
#data = [{name: "Workload", data: WorkingMonth.where(personal_id: #current_employee.personal_id).group("DATE_TRUNC('Month', date_end)").sum(:workload)}]

Related

how to create an array of hashes by looping over array of objects

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

Structure json inside controller

I need to do a json structure like this, but with more than 1 items:
charge = {
items: [{
name: "Product A",
value: 1000,
amount: 2
}]
}
I have an #items that is #items.pluck(:name, :price)
And I'm trying to create my json like this:
charge = {
items: [{
#items.each do |item|
'name:' = item.name,
'value:' = item.price,
'amount:' = 2
end
}]
}
And return this error:
SyntaxError in CoursesController#qualquer
syntax error, unexpected '=', expecting keyword_end
'name:' = item.name,
How i do this structure?
There are two things I see wrong. First, you're using "=" operator to set a Ruby Hash value. That's not correct, as Ruby hashes use symbols or strings. So your hash values will need to look like this:
{ "may_hash_key" => my.has_value }
or
{ my_hash_key: my.hash_value }
or
{ :may_hash_key => my.has_value }
Take your pick.
Additionally, if you are rendering JSON from your controller action, you can do something like this:
def index
# presumably some setup code
charge = {
items: #items.map do |item| {
name: item.name,
value: item.price,
amount: 2
} end
}
render json: charge
end
If you are not rendering JSON from your controller action, what you can do is set #charge and interact with it as a Ruby hash in your view instead.

Formatting ruby hash to json

I am current working on formatting some data from ruby into json;
My current code looks like this
def line_chart_data
#sources = ['Facebook','Twitter','Instagram','LinkedIn']
#sourceCount = [5,12,16,6]
#weeks = ['one','two','three','four','five','six']
h = []
#weeks.each do |i,v|
h.push({'v' => 'Week ' + i})
#sourceCount.each do |s|
h.push({'v' => s})
end
end
c = {c: h}
#How the data should be formatted on export
#sources2 = {
cols: [
{label: 'Week', type: 'string'},
#Each Source needs to be looped though and formatted
{label: 'Facebook', type: 'number'},
{label: 'Twitter', type: 'number'},
{label: 'Instagram', type: 'number'},
{label: 'LinkedIn', type: 'number'}
],
rows: c
}
respond_to do |format|
format.js {render json: #sources2}
end
end
when the data gets printed to the console it looks like this (shortened it a little for brevity)
"rows":{"c":[{"v":"Week one"},{"v":5},{"v":12},{"v":16},{"v":6},
{"v":"Week two"},{"v":5},{"v":12},{"v":16},{"v":6},
{"v":"Week three"},{"v":5},{"v":12},{"v":16},{"v":6}]}
If you notice the first "c" opens with an array but as it loops through the above code it does not create a new array for each week. The code should look more like this.
"rows":{"c":[{"v":"Week one"},{"v":5},{"v":12},{"v":16},{"v":6}],
{"c":[{"v":"Week two"},{"v":5},{"v":12},{"v":16},{"v":6}]},
{"c":[{"v":"Week three"},{"v":5},{"v":12},{"v":16},{"v":6}]}
Where each loop of weeks array creates a new hash with a key of "c" and a value of array.
any help pointing me in the right direction is greatly appreciated! Been stuck on this for quite a while.
You will need to re-work your code a bit to get this. The JSON you want is actually not valid, so this is the closest you can get:
"rows":[{"c":[{"v":"Week one"},{"v":5},{"v":12},{"v":16},{"v":6}],
{"c":[{"v":"Week two"},{"v":5},{"v":12},{"v":16},{"v":6}]},
{"c":[{"v":"Week three"},{"v":5},{"v":12},{"v":16},{"v":6}]}]
Code:
rows = []
#weeks.each do |i,v|
h = []
h.push({'v' => 'Week ' + i})
#sourceCount.each do |s|
h.push({'v' => s})
end
rows.push({"c" => h})
end
#How the data should be formatted on export
#sources2 = {
cols: [
{label: 'Week', type: 'string'},
#Each Source needs to be looped though and formatted
{label: 'Facebook', type: 'number'},
{label: 'Twitter', type: 'number'},
{label: 'Instagram', type: 'number'},
{label: 'LinkedIn', type: 'number'}
],
rows: rows
}

How to group-by and nest results in each group?

I tried to do this:
Things.order("name").group("category_name")
I was expecting the results to be something like this:
[
{
"category_name": "Cat1",
"things":
[
{ "name": "Cat1_Thing1" },
{ "name": "Cat1_Thing1" }
]
},
{
"category_name": "Cat2",
"things":
[
{ "name": "Cat2_Thing3" },
{ "name": "Cat2_Thing4" }
]
}
]
So I would have expected to get an array of "categories" each with an array of "items" which are within that category. Instead, it appears to give me a list of things, sorted by the field I grouped on.
Note: category_name is a column in the thing table.
Try something like
my_grouping = Category.includes(:things).
select("*").
group('categories.id, things.id').
order('name')
=> #<ActiveRecord::Relation [#<Category id: 1, name: "Oranges">, #<Category id: 2, name: "Apples">]>
Though, you'll still have to access the Thing objects via my_grouping.things, they'll already be at your hand, and you won't have to wait for the results. This is likely the sort of interaction you're looking for, vs. mapping them into an actual Array.
One option is to do the grouping in Rails (it returns a hash)
Things.order("name").group_by(&:category_name)
#=> {"cat1" => [thing1,thing2,..], "cat2" => [thing3,thing4,..],..}
ActiveRecord::Base#group performs a SQL GROUP BY. I think, but i'm not sure (depends on your db adapter) that as you don't specify any SELECT clause, you get the first record for each category.
To achieve what you want, there are different ways.
For instance, using #includes :
Category.includes(:things).map do |category|
{
category_name: category.name,
things: things.sort_by(&:name).map{|t| {name: t.name} }
}
end.to_json
Note that the standard (albeit often frowned upon) way to serialize models as json is to use (and override if need be) as_json and to_json. so you would have something along the lines of this :
class Category < ActiveRecord::Base
def as_json( options = {} )
defaults = { only: :name, root: false, include: {links: {only: :name}} }
super( defaults.merge(options) )
end
end
Use it like this :
Category.includes(:links).map(&:to_json)
EDIT
As category_name is only a column, you can do :
Thing.order( :category_name, :name ).sort_by( &:category_name ).map do |category, things|
{ category_name: category, things: things.map{|t| {name: t.name} } }
end.to_json
such thing could belong in the model :
def self.sorted_by_category
order( :category_name, :name ).sort_by( &:category_name ).map do |category, things|
{ category_name: category, things: things.map{|t| {name: t.name} } }
end
end
so you can do :
Thing.sorted_by_category.to_json
this way, you can even scope things further :
Thing.where( foo: :bar ).sorted_by_category.to_json

Rails Creating a Valid JSON object

I could use your helping creating a valid JSON object in Rails.
Here is an example of a valid JSON object that I'm using in the jQuery plugin: https://drew.tenderapp.com/kb/autosuggest-jquery-plugin
var data = {items: [
{value: "21", name: "Mick Jagger"},
{value: "43", name: "Johnny Storm"},
{value: "46", name: "Richard Hatch"},
{value: "54", name: "Kelly Slater"},
{value: "55", name: "Rudy Hamilton"},
{value: "79", name: "Michael Jordan"}]};
Within Rails I'm creating my object as follows:
#projects = Projects.all
#projectlist = Array.new
#projectlist << {
:items => #projects.map { |project|
{
:name => space.name,
:value => space.id
}
}
}
But this ends up outputting like so which ERRORs by the plugin:
[{"items":[{"value":74,"name":"XXXXXX"},{"value":71,"name":"XXXXXX"},{"value":70,"name":"XXXXXX"}]}]
Looks like there is a [] around the initial {} any idea why that's happening and how to build a valid JSON object?
Thanks!
Simply assign #projectlist to a Hash, like so:
EDIT After looking at the plugin's API, I've come to the conclusion that you need to convert your values to strings first:
#projects = Projects.all
#projectlist = {
:items => #projects.map { |project|
{
:name => space.name,
:value => space.id.to_s
}
}
}
Since you're initializing #projectlist to an Array and pushing the Hash onto it, you're getting those wrapping [] characters.

Resources