My controller:
def index
#unique_bug = Rating.find_by_sql("SELECT bug FROM ratings WHERE bug <> '' GROUP BY bug")
end
Rating Model:
def self.metrics_bug_count(bug)
count = where(bug:"#{bug}").count
total = Rating.find_by_sql("SELECT bug FROM ratings WHERE bug <> ''").count
percentage = (count.to_f/total.to_f * 100)
return count, percentage
end
My view:
<table class="table table-bordered">
<tr>
<th><h3>Bug</h3></th>
<th><h3>Total Occurrences</h3></th>
<th><h3>Frequency</h3></th>
</tr>
<tr>
<%#unique_bug.each do |rating| %>
<% count, percentage = Rating.metrics_bug_count(rating.bug)%>
<td><p class="text-center"><h4><%= rating.bug.capitalize %></h4></p></td>
<td><p class="text-center"><h4><%= count %></h4></p></td>
<td><p class="text-center"><h4><%= number_to_percentage(percentage, :precision => 2)%></h4></p></td>
</tr>
<%end%>
</table>
How can I make each row (Bug, Total, Frequency) to each be sortable? I watch the Railscast episode on sortable tables, however the sorting there is done in the controller. How can I sort my table with a more complex find that is being performed in my model.
you can use .order
For example, Rating.order("count DESC").
Besides, I think you can avoid using find_by_mysql and use some rails method to do your query which is more readable and easier.
You can get the unique 1 using .uniq as well.
try have a look at
http://guides.rubyonrails.org/active_record_querying.html
Related
There are multiple calculations I'd like to be able to perform on my database, all centred around a user id, but I don't know how to recombine them after.
Let's say I have three tables for User, Purchases, and DiscountUsage. I want to find the last date a user made a purchase and the total number of discounts used. I would run two separate commands:
User.joins(:purchases).group("users.id").select("users.id", "MAX(purchases.purchase_date)")
User.joins(:discount_usages).group("users.id").select("users.id", "COUNT(*)")
I want my final output to be one table though, joined on users.id, but the output from select isn't the right data type to work on with Rails functions. How can I represent that the users.id values from both calls are the same and thus join them based on those columns?
I assume a User may not have any purchases and not all purchases use discount codes.
However, you want a full listing of each user with their last purchase date and total discount usages over all purchases. You may need to use a right join.
Something like:
query = User.select('users.id AS user_id', 'MAX(purchases.purchase_date) AS last_purchase_date', 'COUNT(discount_usages.id) AS total_discount_usages')
.joins('LEFT JOIN purchases ON purchases.user_id = users.id')
.joins('LEFT JOIN discount_usages ON discount_usages.user_id = purchases.user_id')
.group('users.id')
.to_sql
Then in order to grab the fields you could use:
rows = ApplicationRecord.connection.select_all(query).to_hash
https://guides.rubyonrails.org/active_record_querying.html#select-all
This will give you an array of hashes with keys: 'user_id', 'last_purchase_date', 'total_discount_usages'.
...
<% rows.each do |row| %>
<% row.symbolize_keys! %>
<tr>
<td><%= row[:user_id] %></td>
<td><%= row[:last_purchase_date] %></td>
<td><%= row[:total_discount_usages] %></td>
<tr>
...
You can select aggregates from joined tables and access them in the model by using aliases:
#users = User.joins(:purchases, :discount_usages)
.select(
"users.id",
"MAX(purchases.purchase_date) AS latest_purchase",
"COUNT(discount_usages.*) AS discount_usages_count"
)
.group("users.id")
If you want to hydrate the other attributes of the records select users.* instead of just users.id.
<table>
<thead>
<tr>
<th>Id</th>
<th>Latest Purchase</th>
<th>Discount usages</th>
</tr>
</thead>
<tbody>
<% #users.each do |user| %>
<tr>
<td><%= user.id %></td>
<td><%= user.latest_purchase %></td>
<td><%= user.discount_usages_count %></td>
</tr>
<% end %>
</tbody>
</table>
I want my final output to be one table though, joined on users.id, but
the output from select isn't the right data type to work on with Rails
functions.
Not sure quite what you mean here. This example will return a collection of user records just like a normal query.
If you want a "raw" result with just an array of arrays use .pluck instead of .select.
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
}
I have two tables in my web app: one is for Donors (called "donors") and the other is for Donation Amounts (called "donations). When you click on a donor, you can see all of their donations.
I'm trying to average values associated with a particular date, for a particular charity. For example, if these records exist for Donor A:
*Donor A*
Date Donation Amount
05/04/2013 30
05/04/2013 40
05/05/2013 15
05/05/2013 75
I'd like the system to also calculate and display that the average donation amount for 05/04/2013 was 35 and the average donation amount for 05/05/2013 was 45.
Currently I've tried using the group attribute in my donor model:
def self.average_donateperdate
Donation.average(:donateamount, conditions: ["donor_id = ?", #donor], group: "donatedate")
end
This doesn't seem to work. Since I'm new to Rails, I'm not entirely sure whether this is the right way to do it or not. There are a few other posts that touch on this topic, but none that have helped me solve the issue. Any help would be greatly appreciated!
The simplest syntax to do this is:
#donor.donations.group(:donatedate).average(:donateamount)
This will return a hash in the format { 'donatedate' => 'average donateamount' }.
Naturally, this assumes you have a has_many :donations association on your Donor model. A reusable method would look like:
def average_donation_by_date
donations.group(:donatedate).average(:donateamount)
end
And you can now simply call:
#donor.average_donation_by_date
To see this visually, you can call this in your controller:
#average_donations = #donor.average_donation_by_date.to_a.sort_by(&:first)
And your view might contain something like this:
<table>
<thead>
<tr>
<th>Date</th>
<th>Average Donation</th>
</tr>
</thead>
<tbody>
<% #average_donations.each do |date, amount| %>
<tr>
<td><%= date.strftime('MM/dd/yyyy') %></td>
<td><%= amount %></td>
</tr>
<% end %>
</tbody>
</table>
Reference
Rails api - calculate grouped values
I've been having a lot of trouble with this:
For an RPI application, all my results are within one table: results
I'm trying to print a table based on a specific data range: 2011-07-31..2012-07-01
In my controller:
class SeasonsController < ApplicationController
def s2012
#results = Result.all
#s2012 = Result.where(:date => (2011-07-31)..(2012-07-01))
end
end
In my view:
<table>
<tr>
<th>Event ID</th>
<th>Date</th>
</tr>
<% #s2012.each do |result| %>
<tr>
<td><%= result.event_id %></td>
<td><%= result.date %></td>
</tr>
<% end %>
</table>
This doesn't output any errors (small miracle), but nothing is displayed in the view. #results = Result.all prints all the whole table just fine. But how can I limit it to a specific data range?
I know you're trying to do this all ActiveRecordy, but imo it's actually less readable than if you just wrote the SQL where clause yourself.
Result.where('date BETWEEN ? AND ?',
Date.parse('2011-07-31'),
Date.parse('2012-07-01'))
maybe try:
Date.parse('2011-07-31')..Date.parse('2012-07-01')
In your current example rails will think you are doing arithmetic. You are looking at a date between the number 1973 and 2004. Instead you want to convert them to date objects first. Do
#s2012 = Result.where(:date => DateTime.parse('2011-07-31')..DateTime.parse('2012-07-01'))
The following code always uses more then ten seconds. I have upgraded the server, but it doesn't help. I know I have some database design problems, but I can't modify that.
I am showing all the prices from differents locations of products of a category also in different time range, because the prices change every 15 days in each location.
controller
def prods_x_cat
# This will load all the products of a category
#products = Product.prods_x_cat(params[:id],:include => :raw_datas)
#cortes = RawData.cortes
respond_to do |format|
format.js { render :layout=>false}
end
end
prods_x_cat.js.erb
var jqxhr1 = $.ajax($("#loading_overlay .loading_message, #loading_overlay").fadeIn());
$('#datos').html("<%= escape_javascript render :partial=>'/shared/prods_x_cat'%>")
view
<%#cortes.each do |c|%>
<%=c.corte%>
<%end%>
<%#cortes.each do |c|%>
<%#fecha = c.corte_real%>
<div id="<%=c.corte%>" class="block no_padding">
<table class="display datatable">
<thead>
<tr>
<th>SKU</th>
<%Company.active.order('table_field ASC').each do |c|%>
<th><%=c.abbr%></th>
<%end%>
<th>Average</th>
<th>Mode</th>
<th>Minimum</th>
<th>Maximum</th>
</tr>
</thead>
<tbody>
<%#products.each do |p|%>
<tr class="gradeA">
<td><%=p.name%></td>
<%p.raw_datas.where("product_id='#{p.id}' and corte_real='#{#fecha}'").each do |prd|%>
<td><%=prd.location1.to_f.round(2)%></td>
<td><%=prd.location2.to_f.round(2)%></td>
<td><%=prd.location3.to_f.round(2)%></td>
<td><%=prd.location4.to_f.round(2)%></td>
<td><%=prd.location5.to_f.round(2)%></td>
<td><%=prd.location6.to_f.round(2)%></td>
<td><%=prd.location7.to_f.round(2)%></td>
<td><%=prd.location8.to_f.round(2)%></td>
<td><%=prd.promedio.to_f.round(2)%></td>
<td><%=prd.moda%></td>
<td><%=prd.minimo.to_f.round(2)%></td>
<td><%=prd.maximo.to_f.round(2)%></td>
<%end%>
</tr>
<%end%>
</tbody>
</table>
</div>
<%end%>
</div>
This kind of question is pretty much impossible to answer without seeing all the code involved. Instead I can help you try to figure out where the problem is.
There are good tools for finding where your performance problems are (e.g. ruby-prof) but if you want a quick primitive way to find where your issue is, just use Time.now. For example, you could change your controller action to be:
def prods_x_cat
# This will load all the products of a category
a1 = Time.now
#products = Product.prods_x_cat(params[:id],:include => :raw_datas)
b1 = Time.now
p "Time for finding products: #{b1 - a1}"
a2 = Time.now
#cortes = RawData.cortes
b2 = Time.now
p "Time for finding cortes: #{b2 - a2}"
respond_to do |format|
format.js { render :layout=>false}
end
end
If the printouts suggest that the time is taken up elsewhere, start doing something similar in your template. Focus on the database calls.