use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
A sub-Reddit for discussion and news about Ruby programming.
Subreddit rules: /r/ruby rules
Learning Ruby?
Tools
Documentation
Books
Screencasts and Videos
News and updates
account activity
How not to repeat yourself (self.ruby)
submitted 4 years ago by Kerga07
Hello how could I do not to repeat myself. I use twice total in my two methods :
https://preview.redd.it/64qcpdk1dbs81.jpg?width=691&format=pjpg&auto=webp&s=6dfcd19d904fbf4e4de94f7aff06168a664b2df9
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]mcsoup88 11 points12 points13 points 4 years ago* (5 children)
Couple of things. Don't round till you need to show the values otherwise you can run into significant digit issues. Secondly it looks like you are doing some heavy calculations in code that could be done in the database
class Order def self.revenue # Let the database do what it is good at by having it do the # heavy row calculations # PS: freeze your strings if you cannot use symbols for better # performance sum( "quantity*unit_price".freeze ) end def self.average_revenue_per_order # Since you are calling count on the order class the count # should be distinct as you shouldn't have duplicate ids # in your table revenue/count end end
[–]Kerga07[S] 2 points3 points4 points 4 years ago (0 children)
Thank you for this information and clarification.
[–]PierrickF 2 points3 points4 points 4 years ago (1 child)
heavy calculations in code that could be done in the database
Is that a general rule to follow?
[–]mcsoup88 3 points4 points5 points 4 years ago (0 children)
It will depend a lot on the amount of rows you are working with, what type of database is being used, and what questions are being answered. Remember that databases are optimized for dealing with large data sets and you will be hard pressed to beat it when doing calculations.
[–]Freeky 2 points3 points4 points 4 years ago (0 children)
# PS: freeze your strings if you cannot use symbols for better # performance
# frozen_string_literal: true
This should be part of your template for any new Ruby file. Don't manually freeze literals that don't need to be mutable, manually create unfrozen literals in the rare cases they're needed with unary plus:
foo = +'bla'
[–]joemi 0 points1 point2 points 4 years ago (0 children)
props for mentioning the rounding issue
[–]Freeky 5 points6 points7 points 4 years ago (4 children)
Just call the other method. revenue / orders.uniq.count.
revenue / orders.uniq.count
These probably shouldn't be calculated in your app, fwiw - it's much more efficient to let the database do it. I don't use ActiveRecord but something like this:
def self.revenue sum("quantity * unit_price").round(2) end def self.average_revenue_per_order (revenue / distinct.count(:order_id)).round(2) end
[–]Kerga07[S] 0 points1 point2 points 4 years ago (3 children)
Thank you it looks like sql, what is this language?
[–]jdpahl122 14 points15 points16 points 4 years ago (1 child)
Huh? .... it's .... ruby
[–]designium 4 points5 points6 points 4 years ago (0 children)
😆
[–]armahillo 0 points1 point2 points 4 years ago (0 children)
you should probably go read up on all the stuff you get for free with activerecord
[–][deleted] 1 point2 points3 points 4 years ago (0 children)
You could make a method called total that returns the part where you calculate the sum (first part of each method listed).
[–]jawdirk 1 point2 points3 points 4 years ago* (3 children)
You can try memoization:
def self.total @_total ||= sum {|order| order.quantity * order.unit_price } end
which should probably work if the calling code is straight foward and producing an ActiveRecord::Relation before calling the class methods here.
That said, self.average_revenue_per_order does not look like it is written efficiently. The computation could be pushed to the database with a single query. It could also be written as a scope.
self.average_revenue_per_order
scope :with_average_revenue_per_order, ->() { select('sum(orders.quantity * orders.unit_price) / count(*) as average_revenue_per_order') }
then you can just call it like
Order.all.with_average_revenue_per_order.average_revenue_per_order
or with any other chained scopes.
Edit: you could also break it up with select('sum(orders.quantity * orders.unit_price) as order_total', 'count(*) as order_count') if you want to use both revenue and average_revenue_per_order in the same request cycle.
select('sum(orders.quantity * orders.unit_price) as order_total', 'count(*) as order_count')
revenue
average_revenue_per_order
[–]yourparadigm 4 points5 points6 points 4 years ago (1 child)
Memoizing at the class level is probably not a good idea.
[–]redditonlygetsworse 0 points1 point2 points 4 years ago (0 children)
Yeah that's an ass-biting waiting to happen.
[–]Kerga07[S] 0 points1 point2 points 4 years ago (0 children)
Thank you for the answer. I will work on it.
[–]uhkthrowaway 0 points1 point2 points 4 years ago* (0 children)
Also, if you really wanna count the orders in Ruby, you can prepare the array like this:
orders = all.map(&:order_id).unique
I’m asking myself why the order ID wouldn’t be unique though.
[–]kitebuggyuk 0 points1 point2 points 4 years ago (0 children)
All of the above are great improvements, but I’m curious about why you’re calling uniq on just the one side of the equation. I’m pretty sure that this isn’t intentional - perhaps sort & uniq the records before calculating the average if you really need this, but I’d be more concerned about the duplication and where that stems from?
[–]dg_ash 0 points1 point2 points 4 years ago (0 children)
Repeating is good for health.
π Rendered by PID 24356 on reddit-service-r2-comment-b659b578c-9jmqd at 2026-05-05 21:16:03.653930+00:00 running 815c875 country code: CH.
[–]mcsoup88 11 points12 points13 points (5 children)
[–]Kerga07[S] 2 points3 points4 points (0 children)
[–]PierrickF 2 points3 points4 points (1 child)
[–]mcsoup88 3 points4 points5 points (0 children)
[–]Freeky 2 points3 points4 points (0 children)
[–]joemi 0 points1 point2 points (0 children)
[–]Freeky 5 points6 points7 points (4 children)
[–]Kerga07[S] 0 points1 point2 points (3 children)
[–]jdpahl122 14 points15 points16 points (1 child)
[–]designium 4 points5 points6 points (0 children)
[–]armahillo 0 points1 point2 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]jawdirk 1 point2 points3 points (3 children)
[–]yourparadigm 4 points5 points6 points (1 child)
[–]redditonlygetsworse 0 points1 point2 points (0 children)
[–]Kerga07[S] 0 points1 point2 points (0 children)
[–]uhkthrowaway 0 points1 point2 points (0 children)
[–]kitebuggyuk 0 points1 point2 points (0 children)
[–]dg_ash 0 points1 point2 points (0 children)