ruby on rails group by with null values problem - ruby-on-rails

I have an hour table in witch I store user time tracking information,
the table consists from the following cells
project_id
task_id (optional can be null)
worker_id
reported_date
working_hours
each worker enters several records per day so generally the table is looking like this
id project_id worker_id task_id reported_date working hours;
== =========== ========= ========= ============= ==============
1 1 1 1 10/10/2011 4
2 1 1 1 10/10/2011 14
3 1 1 10/10/2011 4
4 1 1 10/10/2011 14
the task_id is not a must field so there can be times when the user is not selecting it
and their task_id cell is empty
now i need to display the data by using group by clause
so the result will be something like this:
project_id worker_id task_id working hours
========== ========= ========= ==============
1 1 1 18
1 1 18
I did the following group by condition:
#group_hours = Hour.group('project_id,worker_id,task_id)').
select('project_id, task_id ,worker_id,sum(working_hours) as
working_hours_sum')
My view looks like this
<% #group_hours.each do |b| %>
<tr>
<td><%= b.project.name if b.project %></td>
<td><%= b.worker.First_name if b.worker %></td>
<td><%= b.task.name if b.task %></td>
<td class="center"><%= b.working_hours_sum %></td>
<td></td>
</tr>
<% end %>
This it is working but only if the task_id is not null when task id is null it present all the records without grouping them like this
project_id worker_id task_id working hours
=========== ========= ========= ==============
1 1 1 18
1 1 4
1 1 14
I will appreciate any kind of solution to this problem

Assuming you are using mysql you can use the COALESCE function to work with nulls, by changing the null value to something else
e.g.
select COALESCE(colname,0) from table where COALESCE(colname,0) > 1;
IFNULL() is another option

Related

How to select distinct name from associated columns in rails

I am working on a netflix clone project in ruby on rails and I need to get distinct genre name from an associated column in rails. That means, from the first table I have the 'genre_id' and from the second I have the 'name' of the genre. So how can I get this 'name'?
Movie Table
Title | Genre
xxxx | 1
aaaa | 1
bbbb | 1
cccc | 1
zzzz | 2
dddd | 2
eeee | 2
gggg | 2
Genre Table
id | name
1 | Action
2 | Romance
In Model
#action = Movie.where(genre_id: 1)
Try
<%= #action.select(:genre_id).distinct %>
Result
#<Movie::ActiveRecord_Relation:0x00007fb908040470>
Expected
Action
PS: These return error
<% #action.first.genre_id.name %>
<% #action.select(:genre_id).first.name %>
<% #action..select(:genre_id).distinct.as_json %> --> returns [{"genre_id"=>1, "id"=>nil}]
<% #action.first.genre_id %> --> returns 1
Because I can not comment yet, I will answer. It's an old question, for Rails 5+ you should use the following:
#action.distinct.pluck(:genre_id)
It will return an array of unique genre_id's.
I'm assuming you only have the title from the movie table or genre_id (according to the example). You would have to look up the genre table to get the 'Action' string returned.
action = Genre.where(id: 1)
If you have to make a link from the movie to genre table, that will go something like this:
movies = Movie.includes(:genre)
movies.first.genre.name # this will return the action string
# or, pick a specific movie and look up its genre
movies.where(:title => 'xyz').first.genre.name

Rails 5, Postgesql and grouping by association

I'm struggling to get my head around Postgesql and grouping by association.
I have a trial which has_many repetitions. I want to group by a column in repetitions to use in a variable. Currently i have:
#trials = Trial.joins(:repetitions).group('repetitions.repetition_index')
But get this error.
PG::GroupingError: ERROR: column "trials.id" must appear in the GROUP BY clause or be used in an aggregate function
Now from reading up about this i need to include trials.id in my group method, but when I do the output isn't grouped by repetitions.repetition_index anymore. It seems as though it groups by trials.id.
How do I go about making sure that group is only by repetitions.repetition_index?
Update
Trying:
#trials = Trial.joins(:repetitions).select('repetitions.repetition_index,repetitions.treatment_index').group('trials.id, repetitions.repetition_index,repetitions.treatment_index')
And calling:
<% #trials.each do |r| %>
<table class="table table-bordered">
<tr>
<td><%= r.repetition_index %></td>
<td><%= r.treatment_index %></td>
</tr>
</table>
<% end %>
Gives me an output of:
|1|1|
-----
|1|2|
-----
|2|1|
-----
|2|2|
-----
When I'm looking to get:
| |1|
|1|2|
-----
| |1|
|2|2|
-----
If you want to get rid of this error you can do
#trials = Trial.joins(:repetitions).group('trials.id, repetitions.repetition_index')
If you don't want to group by trails.id and want to group by repetitions.repetition_index you have to select only repetitions.repetition_index from query like
#trials = Trial.joins(:repetitions).select('repetitions.repetition_index').group('repetitions.repetition_index')
Let me know if you are clear or not
Update
As per your updated question i think you need something like below. query isn't tested . let me know if its not working
Trial.
joins(:repetitions).
select('repetitions.repetition_index,repetitions.treatment_index').
group_by {
|repetition| repetitions.repetition_index
}

Getting the winner of a match - the rails way?

In my (League) view I want to list all the matches and mark the match as played, the winning team or the match as a tie.
To know if it is a tie or who the winner is, I have to check the score of each opponent. Where do I do these calculations? view helper?, model scope?
My idea is to have three functions that check per match when i list the matches:
match.played? -> true / false
match.tie? -> true / false
match.winner? -> team_id with the highest score.
Database (postgresql)
Matches
id | league_id | date
---+-----------+----------
1 | 1 | 2016-03-21 21:00:00
2 | 1 | 2016-03-22 09:00:00
...
Opponents
(score is null if not played)
id | match_id | team_id | score
---+----------+---------+--------
1 | 1 | 1 | 0
2 | 1 | 2 | 1
3 | 2 | 3 | 1
4 | 2 | 4 | 1
4 | 3 | 1 |
4 | 3 | 2 |
....
You're definitely on the right path. I would have the methods you suggested on my Match model with one exception:
match.winner #=> returns the Team object of the winner (or nil).
I would then have a view helper that called these methods to determine how to render them. I.e., Has it been played? Was it a tie? Who won.
Your questions scope is a little broad for a definitive answer ;)
Ask 5 developers and you will get 12 different answers.
That said, here is what I would do:
Your idea to implement those instance methods is a good starting point, although I personally do not like "?" methods that do not return a boolean value, in my oppinion it should just be #winner and should return the team instance, not the id (I take it there is a "Team" model). You might want to think about a complementary #loser method.
Your view could look something like this:
<table>
<% #matches.each_with_index do |match, i| %>
<tr>
<td class="match number">
<%= i + 1 %>
</td>
<td class="team-1">
<%= match.team_1 %>
</td>
<td class="team-2">
<%= match.team_2 %>
</td>
<td class="winner">
<% if match.played? %>
<!-- this would be a view helper since you have to consider
the tie situation and we do not want that much logic
in the view. It would return a string with either the
teams name or "tie". -->
<%= winner_of_match match %>
<% else %>
N/A
<% end %>
</td>
<!-- etc... -->
</tr>
<% end %>
</table>
This is just very basic to give you an idea to build on. For example you might want to get rid of the if match.played and do it in your view helper (return "not yet played" or something).

Displaying difference of two datetime database fields in Hours:Minutes (i.e. 8:34h)

So I have two datetime fields in database -> clock_in and clock_out
On my view i have:
<td><%= ((r.clock_out - r.clock_in) / 1.hour).to_i %> </td>
This displays -> only hours, i.e. 2 or 0 or 3 etc. Doesn't display minutes.
How do I display minutes as well? i.e. 2:45h
I figured it out, I used this:
<%= Time.at(((r.clock_out - r.clock_in) / 1.second).to_i).utc.strftime("%H:%M:%S") %>

Rails - Group using 2 tables and count

I have the following models: students , groups_by_student and groups.
A row of students table is city_id, so I have to show an html table
Total group1 group2 group3
city1 30 10 5 15
city2 2 0 0 2
city3 20 10 10 0
city4 5 0 5 0
city5 10 0 2 8
This is what I did:
groups = Group.find([1,4,6]) #Array of groups id's
total = []
groups.each do |g|
total << Student.joins(:groups_by_students).where(:groups_by_students => {:group_id => g.descendants}).count(:group => :city_id)
end
#I'm using AwesomeNestedSet gem, so g.descendants gives group children.
So now I have an array of 3 hashes that contain the city id as key and the total of students as the value, but now I'm not sure how to present this data in a html table.
How can I iterate per each "total" element? or is there another way of getting this information?
Thanks in advance
Javier
EDIT:
This is the total array
total = [
{city1 =>10, city3 => 10},
{city1 => 5, city3=>10, city4=>5, city5 => 2},
{city1 => 15, city2 => 2}
]
and now I have to place each in a td label inside a html table with the 0 if theres no value for that group.
I've traversed an array of hashes like;
ary.each do |hash| puts "<tr>#{hash.keys} : #{hash.values}</tr>" end
Can you hack that to suit your needs? Am afraid your question doesn't provide a lot to work with.
This is what i did, may be it might help you a little bit: (here the total value is the last column though)
<table>
<% i = 1%>
<% total = 0%>
<% city=""%>
<% 5.times do %>
<tr>
<% city = 'city'+ "#{i}" %>
<% #total.each do |hash| %>
<% if(hash[city].nil?)%>
<% hash[city] = 0 %>
<%end%>
<% total += hash[city].to_i %>
<td><%= hash[city] %></td>
<%end %>
<td> <%= total %></td>
<% total = 0 %>
<% i += 1 %>
</tr>
<%end%>
</table>
Here the row is controlled by city and not the group. Hence i could not find any other way other than a double loop. If you need that total to be printed in the first column and then rest of the information next, then i think you need to display the total first and then loop again and display city values of each group
Also, for this you need to know the number of cities before hand or else we will not know to print '0' for a particular city in a particular group

Resources