Getting the winner of a match - the rails way? - ruby-on-rails

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).

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

Different behavior of "each" method in development and production

I have table in my ERB-template. Like this:
<table>
<% #users.each do |user| %>
<tr>
<td><%= user.id %></td>
<td><%= user.name %></td>
</tr>
<% end %>
</table>
It works fine. Suppose I have 2 users.
Table will be like this:
1 | foo
2 | bar
But for example, I decide to edit user with id1.
In development it will be correct. Like this:
1 | oof
2 | bar
But in production it will be:
2 | bar
1 | oof
After editing user always jumps to the end of table.
I think it because I use SQLite in local but Heroku uses PostgreSQL.
I'm newbie, so I can be wrong.
&nbsp
My question is: how should I change my code to make the code work correctly everywhere?
Explicitly specify order in your controller. If the order is unspecified, PostgreSQL does not guarantee any order, so assume it will be randomized.
#users = User.order(:id)#.limit/pagination
I would also advise you to have the same databases in development and production, if you take some time to setup PostgreSQL locally, it will pay off.

Find matching values of 2 columns in Ruby on Rails

I am reading a CSV file with RoR and printing out an HTML table but need to mark when the values of 2 separate columns match with another row.
The CSV looks like
name | value1 | value2| value3
bob | 2 | 3 | foo
jim | 4 | 5 | bar
tim | 2 | 7 | foo
I want to find when VALUE1 and VALUE3 match the values of VALUE1 and VALUE3 of another row in this CSV file (in this case: "2" & "foo" match on bob and tim)
The result would be something like:
name | value1 | value2| value3 | duplicate
bob | 2 | 3 | foo | Y
jim | 4 | 5 | bar | N
tim | 2 | 7 | foo | Y
I'm printing the table out
<% file.each do |row| %>
<tr>
<% row.each do |k, v| %>
<td><% v %></td>
<% end %>
</tr>
<% end %>
What I'd like to do is flag the table row when I find the matching columns.
Another version of the answer above, in plain ruby rather than ERB, so it's easier to test
I wanted to show my small ruby program to show how I did this. It's not as easy to read in the ERB version and this can be copied and pasted into IRB or piped into a file.
puts '<head></head>'
puts '<body>'
puts '<table>'
puts '<tr><th>#</th><th>col1</th><th>col2</th><th>col3</th><th>col4</th><th>Matching Previous Rows:</th></tr>'
file = [%w(Bob foo 32 3), %w(Joe zip 4 foo), %w(Joe baz 4 foo), %w(Steve foo 44 3), %w(Bob baz 32 foo), %w(Mary baz 4 wow), %w(Lisa 34 wow 2), %w(Art 45 foo E),%w(Bob foo 32 3)]
output_file = []
file.each do |row|
row.unshift 0x00FFFF #make first value the background color of 0xFFFFFF
row.push '' #add a column for matches
output_file.each_with_index do |prev_row,i| # look for current row values in previous entries
if prev_row[2] == row[2] and prev_row[4] == row[4]
if prev_row[0] == 0x00FFFF
prev_row[0] = rand(0xFFFF0)
row[0] = prev_row[0]
else
row[0] = prev_row[0]
end
row[-1] += "#{(i + 1)}, "
end
end
output_file << row #add the new row to the look-back array
end
output_file.each_with_index do |output_row,i|
print "<tr bgcolor=##{output_row[0].to_s(16).upcase}F >"
output_row.shift
print "<td>#{i + 1}</td>"
output_row.each do |v| #why the k? you don't use it here.
print '<td>' + "#{v}" + ' </td>'
end
puts '</tr>'
end
puts '</table>'
puts '</body>'
I am reminded of a certain XKCD comic about determining if a photo was taken in a National Park,
And if the photo is of a bird... LOL
So you need a bit more complex data structure to do comparison of each row with all previous rows.
OK, final edit: I added code to only set a new color if this is the first time a set of values repeats, that way if it repeats again it will get the same color. Also added code that appends columns showing what rows also match.
<% output_file = [] %>
<% color_offset = 26214 %>
<% file.each do |row| %>
<% row.unshift 0x00FFFF # add last 4 digits of bgcolor as first item in each row %>
<% row.push '' #add a column at the end for row match numbers
<% output_file.each_with_index do |prev_row,i| # look for current row values in previous entries %>
<% if prev_row[2] == row[2] and prev_row[4] == row[4] %>
<% if prev_row[0] == 0x00FFFF %>
<% prev_row[0] -= color_offset %>
<% row[0] = prev_row[0] %>
<% else %>
<% row[0] = prev_row[0] %>
<% end %>
<% color_offset -= 52 %>
<% row[-1] += "#{(i + 1)}, " %>
<% end %>
<% end %>
<% output_file << row # add the new row to the look-back array %>
<% end %>
<% output_file.each do |output_row| %>
<tr bgcolor=#FF<% output_row[0].to_s(16).upcase %> >
<% output_row.shift %>
<% output_row.each do |v| # why the k? you don't use it here. %>
<td> <% v %> </td>
<% end %>
</tr>
<% end %>
So you take each row, loop through the array of rows previously checked, if it matches change both their first items to a matching 4 digit color in hex (G and B, R is added at the end), then copy the new row into the array of rows previously checked.
This breaks if a row matches more than once, as it will only give the same color to the new match and the one previous. BUT I added a final column that tells you which row each one matched previously. So if it is highlighted you can jump back to that row.
There are other ways to do the highlighting, maybe copy the new color forward, that way more than two of the exact same row would be the same color.

Ruby each do loop 'n' number of times

Hi I'm having trouble with the below loop in a .erb view
<% my_list.each do | list | %>
.. loop stuff.....
<% end %.
This works fine for looping through my list, but I only want to loop through the first 4 items in 'my_list' and not the whole list. I tried some things like:
<% my_list.each do | product | 3.times %>
but didn't seem to work as I think my ruby knowledge is limited to say the least!
Use Array#take like this:
<% my_list.take(4).each do | product | %>
Take first 4 element from my_list Array#first:
<% my_list.first(4).each do | product | %>
use Array#each_slice for slice your array
<% my_list.each_slice(4) do | products | %>
<% products.each do | product | %>
It is apparent that you want to iterate through your list in groups of four (you really should amend your question, because this is an important piece of information). It is also apparent you are using Rails. Fortunately Rails has in_groups_of built into ActiveSupport:
<% my_list.in_groups_of(4) do |products| %>
<% products.each do | product | %>
One advantage of this approach (over alternatives such as each_slice) is that in_groups_of will pad the end to make sure you always get four groups. It will pad with nil by default, but you can specify the padding yourself:
<% my_list.in_groups_of(4, " ") do |products| %>
If you pass false as the pad, it will not pad at all and behaves just like each_slice.
<% my_list[0..3].each do | list | %>

ruby on rails group by with null values problem

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

Resources