Ruby How to iterate over an array of instances - ruby-on-rails

I have this array from Order.all
[#<Order:0x00007f1d219f7028 id: 1, time: "01.00", amount: 21, created_at: Mon, 16 Apr 2018 17:44:41 UTC +00:00, updated_at: Mon, 16 Apr 2018 17:44:41 UTC +00:00>,
#<Order:0x00007f1d219f6ee8 id: 2, time: "02.00", amount: 23, created_at: Mon, 16 Apr 2018 17:44:41 UTC +00:00, updated_at: Mon, 16 Apr 2018 17:44:41 UTC +00:00>]
When I do Order.all.first[:time] I get "01.00" so that 'works'.
But when I do
a = []
Order.all.each do |e|
b = Array(e[:time])
b << e[:amount]
a << b
end
I just get the above array again???
How do I iterate over the array to get
[['01.00', 21], ['02.00', 23]]

You don't need that. Try this one
Order.all.pluck(:time, :amount)
A more verbose and expensive way to do it
Order.all.map { |order| [order.time, order.amount] }
Even more verbose, probably what you're trying to do
result = []
Order.all.each do |order|
result << [order.time, order.amount]
end

Your solution may be correct. You should keep in mind that #each return the enumerated collection. The collection of orders in your case.
The result you are expecting is the variable a

Related

Rails query where dates are greater than or less than two dates

I have a model where I am trying to come up with a query where I wanna select data if the starts_at is greater than today and the ends_at is less than today. The other caveat is checking if either one of those dates a NULL and if they aren't then the dates need to be checked against todays date also.
my_model.where("? >= starts_at AND ? <= ends_at OR (starts_at IS NULL OR ends_at IS NULL)", Ti
me.now.beginning_of_day, Time.now.end_of_day)
That code seems to pull back data sometimes and other times it doesn't.
** UPDATE **
Here are a few code examples
=> Menu Load (0.9ms) SELECT "menus".* FROM "menus" WHERE "menus"."account_id" = $1 AND ('2021-09-24 00:00:00' >= starts_at AND '2021-09-24 23:59:59.999999' <= ends_at OR (starts_at IS NULL OR ends_at IS NULL)) [["account_id", 1]]
[#<Menu:0x00005635d5657028
id: 4,
menu_type: "standard",
name: "Promo Menu",
starts_at: Fri, 24 Sep 2021 00:00:00.000000000 UTC +00:00,
ends_at: Fri, 01 Oct 2021 15:19:32.075844000 UTC +00:00,
never_ends: false,
account_id: 1,
created_at: Fri, 24 Sep 2021 00:37:44.127698000 UTC +00:00,
updated_at: Fri, 24 Sep 2021 16:03:06.558332000 UTC +00:00,
available: true>]
The above loads menus correctly, but heres a menu with a starts_at and ends_at within the query time frame and doesn't return
=> #<Menu:0x00005635d56d6e40
id: 1,
menu_type: "standard",
name: "Main Menu",
starts_at: Fri, 24 Sep 2021 00:37:43.512403000 UTC +00:00,
ends_at: Sat, 25 Sep 2021 17:46:13.450433000 UTC +00:00,
never_ends: false,
account_id: 1,
created_at: Fri, 24 Sep 2021 00:37:43.532613000 UTC +00:00,
updated_at: Fri, 24 Sep 2021 17:46:13.455113000 UTC +00:00,
available: true>
I think your query is correct. I guess you couldn't get the records sometimes because of the time zone. What's the timezone of the Rails app?

Search for all records that have a particular value using case insensitive in a JSONB array field

I'm using postgres database and trying to query all records with "Value"=>"Black" in this JSONB field. That field contain an array of objects, e.g. {"id"=>"1", "key"=>"size", "value"=>"P"}
How do I query(case-insensitive) this records?
This is my code so far
def by_feature_value(value)
relation.where('features #> ?', [{ value: value }].to_json)
end
Records
#<ProductSku:0x000055de9cc01ba8
id: 33,
product_id: 3,
code: "1234",
ean: "12345",
created_at: Mon, 30 Apr 2018 11:47:00 UTC +00:00,
updated_at: Mon, 30 Apr 2018 11:47:00 UTC +00:00,
features: [{"id"=>"2", "key"=>"Color", "Value"=>"Black"}]>
#<ProductSku:0x000055de9cc01ba8
id: 33,
product_id: 3,
code: "1234",
ean: "12345",
created_at: Mon, 30 Apr 2018 11:47:00 UTC +00:00,
updated_at: Mon, 30 Apr 2018 11:47:00 UTC +00:00,
features: [{"id"=>"2", "key"=>"Color", "Value"=>"black"}]>,
The correct answer to this is
ProductSku.where('lower(features::text)::jsonb #> lower(?)::jsonb', [{ Value: value }].to_json)
Without type casting the first comment on your post does not work.

Rails: find attachments without user OR without comment

Attachment has_one :comment, optional: true
Attachment has_one :user, through :comment, comment - through task, task - through project
I want to find all current_user attachments plus attachments without owner -> no parent comment
Query Attachment.joins(comment: [task: [:project]]).where('projects.user_id = ? OR attachments.comment_id IS NULL', user.id) doesnt include attachments without comment, why?
[10] pry(#<CommentResource>)> Attachment.all
=> [#<Attachment:0x00000008a6f3a8
id: 1,
file: "attachments.rb",
comment_id: 1,
created_at: Sun, 21 May 2017 14:18:21 UTC +00:00,
updated_at: Sun, 21 May 2017 14:18:21 UTC +00:00>,
#<Attachment:0x00000008a6f268
id: 2,
file: "attachments.rb",
comment_id: 1,
created_at: Sun, 21 May 2017 14:18:21 UTC +00:00,
updated_at: Sun, 21 May 2017 14:18:21 UTC +00:00>,
#<Attachment:0x00000008a6f128
id: 3,
file: "attachments.rb",
comment_id: nil,
created_at: Sun, 21 May 2017 14:29:51 UTC +00:00,
updated_at: Sun, 21 May 2017 14:29:51 UTC +00:00>]
[11] pry(#<CommentResource>)> Attachment.joins(comment: [task: [:project]]).where('projects.user_id = ? OR attachments.comment_id IS NULL', user.id).to_sql
=> "SELECT \"attachments\".* FROM \"attachments\" INNER JOIN \"comments\" ON \"comments\".\"id\" = \"attachments\".\"comment_id\" INNER JOIN \"tasks\" ON \"tasks\".\"id\" = \"comments\".\"task_id\" INNER JOIN \"projects\" ON \"projects\".\"id\" = \"tasks\".\"project_id\" WHERE (projects.user_id = 1 OR attachments.comment_id IS NULL)"
[12] pry(#<CommentResource>)> Attachment.joins(comment: [task: [:project]]).where('projects.user_id = ? OR attachments.comment_id IS NULL', user.id)
=> [#<Attachment:0x0000000891c7a8
id: 1,
file: "attachments.rb",
comment_id: 1,
created_at: Sun, 21 May 2017 14:18:21 UTC +00:00,
updated_at: Sun, 21 May 2017 14:18:21 UTC +00:00>,
#<Attachment:0x0000000891c668
id: 2,
file: "attachments.rb",
comment_id: 1,
created_at: Sun, 21 May 2017 14:18:21 UTC +00:00,
updated_at: Sun, 21 May 2017 14:18:21 UTC +00:00>]
The joins method on active record queries the records by using inner join, which means in your case it only returns attachments with comments. If you want to include attachments without comments, you need to left outer join.
http://guides.rubyonrails.org/active_record_querying.html#left-outer-joins

How to group date by day and sum in postgres?

I got this model:
[#<Account:0x007fcf32153098
id: 1,
profit: 100,
user_id: 1,
created_at: Sun, 15 Nov 2015 02:27:43 UTC +00:00,
updated_at: Sun, 15 Nov 2015 02:27:43 UTC +00:00>,
#<Account:0x007fcf32152df0
id: 2,
profit: 500,
user_id: 1,
created_at: Sun, 16 Nov 2015 15:05:07 UTC +00:00,
updated_at: Sun, 15 Nov 2015 15:05:07 UTC +00:00>,
]
And for now I got this to group them in date:
Account.all.group_by{|a| a.created_at.strftime("%Y-%m-%d")}
{"2015-11-15"=>
[#<Account:0x007fcf3247b1a8
id: 1,
profit: 100,
user_id: 1,
created_at: Sun, 15 Nov 2015 02:27:43 UTC +00:00,
updated_at: Sun, 15 Nov 2015 02:27:43 UTC +00:00>],
"2015-11-16"=>
[#<Account:0x007fcf3247afc8
id: 2,
profit: 500,
user_id: 1,
created_at: Sun, 16 Nov 2015 15:05:07 UTC +00:00,
updated_at: Sun, 15 Nov 2015 15:05:07 UTC +00:00>]}
My question is: How can I group them and at the same time sum the profit together if there are more than one record for that day? Seems like I can't use sum(:profit) with postgres?
I think you can just do this simply with:
Account.order("DATE(created_at)").group("DATE(created_at)").sum(:profit)

How do I group by day instead of date?

ok so i have
>> list = Request.find_all_by_artist("someBand")
=> [#<Request id: 1, artist: "someBand", song: "someSong", venue: "Knebworth - Stevenage, United Kingdom", showdate: "2011-07-01", amount: nil, user_id: 2, created_at: "2011-01-01 18:14:08", updated_at: "2011-01-01 18:14:09".............
and then
list.group_by(&:created_at).map {|k,v| [k, v.length]}.sort
=> [[Sat, 01 Jan 2011 18:14:08 UTC +00:00, 10], [Sun, 09 Jan 2011 18:34:19 UTC +00:00, 1], [Sun, 09 Jan 2011 18:38:48 UTC +00:00, 1], [Sun, 09 Jan 2011 18:51:10 UTC +00:00, 1], [Sun, 09 Jan 2011 18:52:30 UTC +00:00, 1], [Thu, 10 Feb 2011 02:22:08 UTC +00:00, 1], [Thu, 10 Feb 2011 20:02:20 UTC +00:00, 1]]
the problem is I have a few Sun, 09 Jan and a couple for the 10th, instead of one like this
this is what i need
=> [[Sat, 01 Jan 2011 18:14:08 UTC +00:00, 10], [Sun, 09 Jan 2011 18:34:19 UTC +00:00, 4], [Thu, 10 Feb 2011 20:02:20 UTC +00:00, 2]]
I think this is a much more elegant and simple solution
list.group_by{|x| x.created_at.strftime("%Y-%m-%d")}
Time is a quite complex object to group by. Assuming you want to group by the creation date, instead of the full Time, start creating a custom method in your model to return the group criteria.
The method should return the creation date, possibly as string.
def group_by_criteria
created_at.to_date.to_s(:db)
end
Then, group by that method.
list.group_by(&:group_by_criteria).map {|k,v| [k, v.length]}.sort
There is a gem for that: groupdate.
Usage (from the docs):
User.group_by_day(:created_at).count
# {
# 2013-04-16 00:00:00 UTC => 50,
# 2013-04-17 00:00:00 UTC => 100,
# 2013-04-18 00:00:00 UTC => 34
# }
Ipsum's answer is actually good and probably the best:
In Arel:
requests = Arel::Table.new(:requests)
query = requests.project("COUNT(*), CAST(requests.created_at AS DATE) as created_at")
query = query.group("CAST (requests.created_at AS DATE)")
Request.find_by_sql(query.to_sql)
you can use GROUP BY DATE(created_at) in MySQL
On ruby code you can use like this
list.group('DATE(created_at)').map {|k,v| [k, v.length]}.sort
Group without extra gems:
def self.group_by_day items
data = items.group_by{|x| x.created_at.to_date}
chart_data = {}
data.each do |a,b|
chart_data.merge!({a => b.count})
end
return chart_data
end

Resources