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