I have multiples measurements and I want to render it into tables like this
| Measurements | Operator | browsings | FTP DL | FTP UL | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Location | Event | Date | Operator | avg | min | max | avg | min | max | avg | min | max |
| Verizon | ||||||||||||
| USCell | ||||||||||||
| T-Mobile |
for each measurement rendered there is always 3 operator
the operator is fixed/determined value
they are ["Verizon", "USCell", "T-Mobile"]
my current approach is to use multiple loop and using where clause to achieve this
measurements/index.html.erb
<table>
<thead>
<tr>
<th colspan="3">Measurement</th>
<th colspan="3">FTP DL</th>
<th colspan="3">FTP UL</th>
<th colspan="3">Browsing</th>
</tr>
<tr>
<th>Location</th>
<th>Event</th>
<th>Date</th>
<th>Average Browsing Speed (Mbps)</th>
<th>Minimum Browsing Speed (Mbps)</th>
<th>Maximum Browsing Speed (Mbps)</th>
<th>Average FTP Download Speed (Mbps)</th>
<th>Minimum FTP Download Speed (Mbps)</th>
<th>Maximum FTP Download Speed (Mbps)</th>
<th>Average FTP Upload Speed (Mbps)</th>
<th>Minimum FTP Upload Speed (Mbps)</th>
<th>Maximum FTP Upload Speed (Mbps)</th>
</tr>
</thead>
<tbody>
<% @measurements.each do |measurement| %>
<% @operators.each do |operator| %>
<tr>
<td><%= measurement.location %></td>
<td><%= measurement.event %></td>
<td><%= measurement.date %></td>
<td><%= operator %></td>
<% if measurement.browsings.where(operator: operator).any? %>
<td><%= measurement.browsings.where(operator: operator).first.avg %></td>
<td><%= measurement.browsings.where(operator: operator).first.min %></td>
<td><%= measurement.browsings.where(operator: operator).first.max %></td>
<% else %>
<td></td>
<td></td>
<td></td>
<% end %>
<% if measurement.ftp_dls.where(operator: operator).any? %>
<td><%= measurement.ftp_dls.where(operator: operator).first.avg %></td>
<td><%= measurement.ftp_dls.where(operator: operator).first.min %></td>
<td><%= measurement.ftp_dls.where(operator: operator).first.max %></td>
<% else %>
<td></td>
<td></td>
<td></td>
<td></td>
<% end %>
<% if measurement.ftp_uls.where(operator: operator).any? %>
<td><%= measurement.ftp_uls.where(operator: operator).first.avg %></td>
<td><%= measurement.ftp_uls.where(operator: operator).first.min %></td>
<td><%= measurement.ftp_uls.where(operator: operator).first.max %></td>
<% else %>
<td></td>
<td></td>
<td></td>
<% end %>
</tr>
<% end %>
<% end %>
</tbody>
</table>
I'm wondering if I could avoid using multiple loop and where clause on my code to achieve this?
because I think using multiple loop and where approach considered it as bad practices, isn't it?
I'm thinking since I have multiple repeated operator I could use that as a group or something, I'm thinking about joining all my has_many and group them by using group_by operator but I don't know how to do it yet (need a little guidance there if its really possible and good approach)
here are my others code
measurement.rb
class Measurement < ApplicationRecord
has_many :ftp_uls, dependent: :destroy
has_many :ftp_dls, dependent: :destroy
has_many :browsings, dependent: :destroy
end
measurement_controller.rb
class MeasurementsController < ApplicationController
before_action :authenticate_user!, only: [:index, :show]
before_action :set_measurement, only: %i[ show edit update destroy ]
def index
@measurements = Measurement.all
@operators = ["Verizon", "USCell", "T-Mobile"]
end
end
schema.rb
ActiveRecord::Schema.define(version: 2021_08_17_062327) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "browsings", force: :cascade do |t|
t.bigint "measurement_id", null: false
t.string "operator"
t.decimal "avg"
t.decimal "min"
t.decimal "max"
t.index ["measurement_id"], name: "index_browsings_on_measurement_id"
end
create_table "ftp_dls", force: :cascade do |t|
t.bigint "measurement_id", null: false
t.string "operator"
t.decimal "avg"
t.decimal "min"
t.decimal "max"
t.index ["measurement_id"], name: "index_ftp_dls_on_measurement_id"
end
create_table "ftp_uls", force: :cascade do |t|
t.bigint "measurement_id", null: false
t.string "operator"
t.decimal "avg"
t.decimal "min"
t.decimal "max"
t.index ["measurement_id"], name: "index_ftp_uls_on_measurement_id"
end
create_table "measurements", force: :cascade do |t|
t.string "location"
t.string "event"
t.date "date"
end
end