Put data in specific header - ruby-on-rails

headers = ["05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22"]
data = ["05:01", "05:23", "05:43", "06:03", "06:33", "06:53", "07:03", "07:23", "07:46", "08:04", "08:24", "08:44", "09:14", "09:24", "09:44", "10:19", "10:39", "11:02", "11:22", "11:42", "12:12", "12:32", "12:52", "13:12", "13:32", "13:52", "14:12", "14:32", "14:42", "15:02", "15:32", "15:52", "16:12", "16:32", "16:52", "17:12", "17:32", "17:52", "18:12", "18:47", "19:23", "19:48", "20:28", "21:03", "21:33", "22:08", "22:40"]
I must put specific data to correct header. For example
05 06
05:01 06:03
05:23 06:33
05:43 06:53
Rails 3.0.3
Ruby 1.9.2
Prawn 0.8.4
How I can do that ?
Basically i want do something like this.
Prawn::Document.generate(path) do
table([['05','06']] + [['05:01','06:03'],['05:23','06:33'],['05:43','06:53']], :header => true) do
end
end

mapped_headers = headers.map do |header|
data_array = data.select {|d| header == d[0,2]}
[header, data_array]
end
This code will give output like this:
[["05", ["05:01", "05:23", "05:43"]], ["06", ["06:03", "06:33", "06:53"]], ["07", ["07:03", "07:23", "07:46"]], ["08", ["08:04", "08:24", "08:44"]], ["09", ["09:14", "09:24", "09:44"]], ["10", ["10:19", "10:39"]], ["11", ["11:02", "11:22", "11:42"]], ["12", ["12:12", "12:32", "12:52"]], ["13", ["13:12", "13:32", "13:52"]], ["14", ["14:12", "14:32", "14:42"]], ["15", ["15:02", "15:32", "15:52"]], ["16", ["16:12", "16:32", "16:52"]], ["17", ["17:12", "17:32", "17:52"]], ["18", ["18:12", "18:47"]], ["19", ["19:23", "19:48"]], ["20", ["20:28"]], ["21", ["21:03", "21:33"]], ["22", ["22:08", "22:40"]]]
You can also create a hash by editing last line
{header => data_array}
You can acheive Prawn requirement by doing this
rows = 3
datas = (0...rows).map do |row|
mapped_headers.map{|header| header[1][row]}
end
Prawn::Document.generate(path) do
table([headers] + datas, :header => true) do
end
end

If you are asking about how to add a new element to an array, method push will do the job:
headers.push "05"
data.push "05:01"

Related

Is there a way to transform only some keys in Rails using transform_keys method?

I have a hash that looks like this:
"properties": [
{
"accommodates": 14,
"adr": 1336.69,
"host_id": 23724674,
"property_id": 4576625,
"bathrooms": 4.5,
"bedrooms": 5,
"business_ready": false,
"cancellation": "strict",
"check_in": "Anytime after 4PM",
"check_out": "11AM",
"cleaning_fee": 200,
"days_a_ltm": 138,
"days_b_ltm": 24,
"days_r_ltm": 203,
"extra_person_charge": 50,
"img_count": 26,
"img_cover": "",
"instant_book": true,
"last_calendar_update": "2018-02-16",
"latitude": 39.7610167973274,
"listed_dt": "2014-10-24",
"listing_url": "rooms/4576625",
"location": {
"city": "Denver",
"country": "United States",
"msa": "Denver-Aurora-Lakewood, CO Metro Area",
"neighborhood": [
"Highland"
],
"state": "Colorado",
"zipcode": "80211"
},
"longitude": -105.008507384098,
"minimum_stay": 2,
"num_res_ltm": 64,
"occ": 0.595308,
"price_monthly": 17000,
"price_nightly": 725,
"price_weekly": 5600,
"property_type": "Entire house",
"rating_overall": 9.9,
"response_rate": 100,
"response_time": 229,
"revenue": 271348,
"reviews": 124,
"room_type": "Entire home/apt",
"scraped_dt": "2018-02-25",
"security_deposit": 1000,
"superhost": true,
"title": "Huge Home in the Heart of Lohi! Groups Welcome!"
},
{
"accommodates": 15,
"adr": 781.576,
"host_id": 14178014,
"property_id": 9944575,
"bathrooms": 5,
"bedrooms": 6,
"business_ready": true,
"cancellation": "strict",
"check_in": "Anytime after 3PM",
"check_out": "12PM (noon)",
"cleaning_fee": 200,
"days_a_ltm": 46,
"days_b_ltm": 7,
"days_r_ltm": 312,
"extra_person_charge": 15,
"img_count": 49,
"img_cover": "",
"instant_book": true,
"last_calendar_update": "2018-02-15",
"latitude": 39.7349220878173,
"listed_dt": "2015-12-11",
"listing_url": "rooms/9944575",
"location": {
"city": "Denver",
"country": "United States",
"msa": "Denver-Aurora-Lakewood, CO Metro Area",
"neighborhood": [
"Capitol Hill"
],
"state": "Colorado",
"zipcode": "80218"
}
]
There are some keys inside the properties array hashes that I want to change and I would like to use something simple like transform_keys or deep_transform_keys; however, those methods replace all keys which would require that a create a new map with all the keys below in order to change two or 3. In particular, I'm looking to rename adr, revenue, and occ. Does anybody know if there is a way to execute the transform_key or deep_transform_key method only on some keys? Something like:
hash_name.deep_transform_keys{|k| {:adr=>'adr_ltm', :revenue => 'revenue_ltm'}[k] if k == 'adr'||'revenue'}
Is there a specific reason you can't just loop through?
hash[:properties].each_with_index do |property, i|
hash[:properties][i][:adr_ltm] = property.delete(:adr)
hash[:properties][i][:revenue_ltm] = property.delete(:revenue)
end
There are serializing/deserializing gems that help you in these situations. They allow both rendering json from your models and parsing json to update your Ruby objects. its soo much flexible to maintain code in long term.
# deserialize
song = Song.new
SongRepresenter.new(song).from_json('{"id":1, "title":"Fallout"}')
song.id #=> 1
song.title #=> "Fallout"
# serialize
SongRepresenter.new(song).to_json #=> {"id":1, title":"Fallout"}
jsonapi-rb
roar
you can monkey patch the private method in Class Hash,or re-implement your own one, this is the idea
class Hash
private
def _deep_transform_keys_in_object(object, &block)
case object
when Hash
object.each_with_object({}) do |(key, value), result|
# define what key you want to run
return unless key != :key_name
result[yield(key)] = _deep_transform_keys_in_object(value, &block)
end
when Array
object.map {|e| _deep_transform_keys_in_object(e, &block) }
else
object
end
end
end
this method is used by deep_transform_keys in this way:
def deep_transform_keys(&block)
_deep_transform_keys_in_object(self, &block)
end
this is the basic idea, not the fully functional code, you need make sure it work by yourself.

I am adding datetime using daterangepicker in my rails application but not updated as parameter datetime

I am adding date-time using date-range-picker in my rails application, But when we create or update date-time is updated on server but +6 hour extra.
Added in my configuration file: config.time_zone = "Mexico City"
for select daterange:
$('#ordenes_servicio_OS_FECHAASIGNACION, \
#ordenes_servicio_OS_FECHALLEGADA, \
#ordenes_servicio_OS_FECHAINCIO, \
#ordenes_servicio_OS_FECHAFIN, \
#ordenes_servicio_OS_FECHATERMINO').daterangepicker({
"singleDatePicker": true,
"timePicker": true,
"timePickerSeconds": true,
"autoApply": true,
"locale": {
"format": "DD/MM/YYYY h:mm:ss A",
"separator": " - ",
"fromLabel": "From",
"toLabel": "To",
"customRangeLabel": "Custom",
"weekLabel": "W",
"daysOfWeek": [ "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" ],
"monthNames": [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
],
"firstDay": 1
},
"showCustomRangeLabel": false,
"opens": "center"
});
Parameter from params =
"OS_FECHAASIGNACION"=>"20/04/2018 6:53:08 AM"
Update query:
UPDATE `ordenes_servicios` SET `OS_FECHAASIGNACION` = '2018-04-20 11:53:08', `updated_at` = '2018-04-03 05:57:30' WHERE `ordenes_servicios`.`ID` = 5
Please Give me exact answer, How can we update datetime as utc-6 to server? As we set from parameter.
To fix the time in database, such that it will always dealt with UTC, you can set the following.
config.active_record.default_timezone = :utc
config.active_record.default_timezone determines whether to use Time.local (if set to :local) or Time.utc (if set to :utc) when pulling dates and times from the database. The default is :utc.

Rails merge multiple json response

Can anyone help me with this problem?
So, here is the problem, I want to merge this query response:
#energy = Alert.where(["alert_type = ?", "Energy"]).last.as_json
#cost = Alert.where(["alert_type = ?", "Cost"]).last.as_json
Then I merge those object with:
#current_notif = #energy.merge(#cost)
But those just give me #cost object like this:
{
"alert_type": "Cost",
"value": 30000000,
"status": "Cost exceeds limit",
"created_at": "2017-06-03T15:31:21.156+07:00",
"updated_at": "2017-06-03T15:31:21.156+07:00",
"home_id": 2
}
Rather than a merged #energy + #cost like this:
{ {"alert_type": "Energy",
"value": 384455.813978742,
"status": "Energy too high",
"created_at": "2017-05-31T11:31:12.907+07:00",
"updated_at": "2017-05-31T11:31:12.907+07:00",
"home_id": 2 },
{
"alert_type": "Cost",
"value": 30000000,
"status": "Cost exceeds limit",
"created_at": "2017-06-03T15:31:21.156+07:00",
"updated_at": "2017-06-03T15:31:21.156+07:00",
"home_id": 2
}
}
If you want you could "join" both values, and then over that use as_json:
[#energy, #cost].as_json
# [{"alert_type": "Energy", ... }, {"alert_type": "Cost", ... }]
Or if you want you could use the IN expression, in order to deal with ActiveRecord instead having to customize the result this gives you:
Alert.where(alert_type: ['Energy', 'Cost']).as_json
# [{"alert_type": "Energy", ... }, {"alert_type": "Cost", ... }]
This is happening because that's how merge works.
hash = {:name => "Ade", :gender => "Male"}.merge(:name => "Bob")
puts hash # {:name=>"Bob", :gender=>"Male"}
Solution:
results = [ #energy, #cost ]
results.each do |result|
puts result['alert_type'] # Energy, Cost
end

Get specific information from multi-dimensional array

Let say I have a array in this format:
arr = [{
"id":"11",
"children":[
{ "id":"9"},
{ "id":"5", "children":[ {"id":"4"} ] }
]
},
{
"id":"10",
"children":[{ "id":"7"} ]
}
]
And now I would like to get all ID's that are apparent in this array:
11,9,5,4,10,7
For that I would use a recursive code similar to this one:
ids = []
def find_ids arr
arr.each do |entry|
ids << entry["id"] if entry["id"]
find_ids(entry["children"]) if entry["children"]
end
end
What would you do to get the ids?
Do you maybe know a really short version?
Thanks
def grab_ids(arr)
arr.each_with_object([]) do |h,a|
h.each do |k,v|
case v
when Array
a.concat(grab_ids(v))
else
a << v if k == :id
end
end
end
end
grab_ids arr
#=> ["11", "9", "5", "4", "10", "7"]
Other way is to use lambda:
def get_ids(arr)
p = ->(a, exp) do
a.each do |hsh|
exp << hsh["id"]
p.(hsh["children"], exp) if Array === hsh["children"]
end
exp
end
p.(arr, [])
end
get_ids(arr)
# => ["11", "9", "5", "4", "10", "7"]
Or if you wanna to use shorter version:
def get_ids(arr)
p =->(hsh) { Array === hsh["children"] ? ([hsh["id"]] + hsh["children"].map(&p)) : hsh["id"] }
arr.map(&p).flatten
end
get_ids(arr)
# => ["11", "9", "5", "4", "10", "7"]

Most efficient way to convert a ruby hash with array as keys to one with single values as keys

I'm stuck on what is the best way to re-arrange my ruby hash.
The main goal is to group results from mysql by month and count.
To do it, i make this request:
#data = Model.find(params[:id])
.jobs
.group('year(created_at)')
.group('month(created_at)')
.count(:id)
Which gives me:
#=> {[2013, 12]=>9, [2014, 1]=>4, [2014, 3]=>3,
# [2014, 4]=>1, [2014, 6]=>1, [2014, 7]=>1, [2014, 10]=>2}
I'm trying to have a cleaner hash or array to convert to json, where the years are not duplicated.
How can I have something workable like {"Year" => [Month,Count value]}? (or other form)
Idea? (I run ruby 2.2)
The answer proposed by #mudosobwa might be correct, but because your target is a json file, you may want some 'named' keys. I suggest you this one :
formated_results = #data.group_by{|k, v| k[0]}.collect{|k,v| {year: k, datas: v.collect{|vv| {month: vv.first.last, count: vv.last}}}}
# {:year=>2013, :datas=>[{:month=>12, :count=>9}]}
# {:year=>2014, :datas=>[{:month=>1, :count=>4}, {:month=>3, :count=>3}, {:month=>4, :count=>1}, {:month=>6, :count=>1}, {:month=>7, :count=>1}, {:month=>10, :count=>2}]}
EDIT : An other solution without the group_by method :
formated_results = Hash.new{|h,k| h[k] = []}
#data.each{|k,v| formated_results[k[0]] << {month: k[1], count: v}}
formated_results = formated_results.collect{|k, v| {year: k, datas: v}}
# {:year=>2013, :datas=>[{:month=>12, :count=>9}]}
# {:year=>2014, :datas=>[{:month=>1, :count=>4}, {:month=>3, :count=>3}, {:month=>4, :count=>1}, {:month=>6, :count=>1}, {:month=>7, :count=>1}, {:month=>10, :count=>2}]}
Then you just have to
formated_results.to_json
The json result shall be :
[
{
"year": 2013,
"datas": [
{ "month": 12, "count": 9 }
]
},
{
"year": 2014,
"datas": [
{ "month": 1, "count": 4 },
{ "month": 3, "count": 3 },
{ "month": 4, "count": 1 },
{ "month": 6, "count": 1 },
{ "month": 7, "count": 1 },
{ "month": 10, "count": 2 }
]
}
]
Given you already have your hash in #data, you might:
#data.inject({}) do |memo, ((y, m), cnt)|
(memo[y] ||= {})[m] = cnt
memo
end
#⇒ {
# 2013 => {12 => 9},
# 2014 => {1 => 4, 10 => 2, 3 => 3, 4 => 1, 6 => 1, 7 => 1}
# }
As it was noted by #Surya in comments, it should be hash Year => Hash[Month, Count]. While you still want to have arrays of Month, Count:
#data.inject({}) do |memo, ((y, m), cnt)|
memo[y] ||= []
memo[y] << [m, cnt]
memo
end
To json:
require 'json'
result.to_json
#=> "{\"2013\":{\"12\":9},\"2014\":{\"1\":4,\"3\":3,\"4\":1,\"6\":1,\"7\":1,\"10\":2}}"
#data.to_a.group_by{|ym, c| ym.first }.map{|year, months| [year,months.map{|m,cnt| [m.last, cnt] }] }.to_h
=> {2013=>[[12, 9]], 2014=>[[1, 4], [3, 3], [4, 1], [6, 1], [7, 1], [10, 2]]}

Resources