Ruby on Rails, sum of an attribute of an attribute - ruby-on-rails

I'm having some problems with my Ruby on Rails website. Let me explain.
I have a user model, it has many credits
In order to count, the credits for a user I do:
#user.credits.sum(:score)
This works fine.
Now have a model team, that has many users, and I want to find out the total number of credits, I found on another StackOverflow post this:
array.inject{|sum,x| sum + x }
So I thought for me it should look like that:
#team.users.inject{|sum,x| sum + x.credits.sum(:score)}
But this returns
#<User:0x00000101a7c180>
instead of the sum. Guess I'm doing something wrong. Don't hesitate if you have an idea.
Thanks

You have to set the initial value:
#team.users.inject(0){ |sum,x| sum + x.credits.sum(:score) }
You could also do:
#team.users.sum{ |x| x.credits.sum(:score) }

Related

Ruby On Rails - Geocoder - Near with condition

I'm using GeoCoder in my application. Now I need to search for objects in my database which are close to a position OR have specific attribute set. I would like to perform this action in one database query, because the database is realy huge.
I would like to have something like
Spot.near([lat,long],distance).where("visited = ?",true).
The distance and the visited attribute should be combined with an OR, not with an AND.
Does anyone have an idea how to do this?
Thank you!
Based off of this answer, you should be able to do something like:
near = Spot.near([lat, long], distance)
visited = Spot.where(visited: true)
near = near.where_values.reduce(:and)
visited = visited.where_values.reduce(:and)
Spot.where(near.or(visited))
I'm in the process of upgrading a Rails application from Rails 4 to Rails 7 and ran into this problem. While I have no doubt Luke's suggestion worked in earlier versions, it doesn't work in Rails 7 (I'm currently running activerecord-7.0.3.1.
In my particular case, I am using the geocoder near() method to return results that are within a 20 mile radius of the query, but I also wanted to use OR conditions to return results where the query was similar to the text values in either the name or location columns from the items table in an attempt to return relevant items that haven't been assigned latitude and longitude values.
In Rails 4, my solution was:
select("items.*").near(q, 20, select: :geo_only).tap do |near_query|
near_query.where_values.last << sanitize_sql([" OR items.location LIKE ? OR items.name LIKE ?", "%#{q}%", "%#{q}%"])
end
In Rails/ActiveRecord 7, the where_values() method no longer exists. Searching for an alternate solution led me to this post. I wound up spending a fair amount of time perusing the latest ActiveRecord and Arel code for a solution. Here's what I came up with,
Rails 7 solution:
t = Item.arel_table
arel_geo_conditions = Item.near(q, 20).where_clause.ast # ast: Abstract Syntax Tree
Item.where(arel_geo_conditions.or(t[:location].matches("%#{q}%").or(t[:name].matches("%#{q}%"))))

activerecord: check first X chars of column

I'd like to check the first two chars of a number straight in my model. First I define the number of the current logged in user (devise):
user_number = current_user.number.first(2)
then I want to take that value and check it within a where statement in a "number" mobel, so I tried this
#numbers = Number.where(:number_value.first(2) => user_number)
which is obviously the same as
#numbers = Number.where(:number_value.first(2) => current_user.number.first(2))
No, that does not work.
How can I check the first 2 chars of the :number_value column in my model?
Any help is appreciated.
Many thanks.
Solution (SQLite)
#numbers = Number.where("number_value like '" + current_user.number.first(2) + "%'")
since this is not lazy loading I'm not convinced yet that it is the smartest solution. if you know any better, would be cool if you can share
First, you should read the ActiveRecord query guide. I'd also imagine that there's a much more straight forward way for you to accomplish your goal.
But, to answer your specific question, here's an approach that'd work with Postgresql.
Number.where("number_value::text like ?", current_user.number.to_s[0,2] + "%")

rails : Ruby on Rails calculating “rank” of a join table

I have 2 tables (relationships many-to-many with sqlite3) :
-User
-Credit(with user_id & score)
And I try to compute the rank of the user.
To compute the rank of this user I need to find the SUM of all the credits of this user.
But I don't know how do this :(
I have tried something like this but it don't work :
User.all.join(:credits).order(sum(:score)).index(#user)
I get this error :
TypeError in UsersController#index
can't convert Symbol into String
Thank !
To sum (or count) you should use sum with group (that is converted in "group by"),
because you need to group the users in some way to be able to sum their score.
I did not try the following code, but it should be something like this:
User.select("users.name, sum(credits.score)").joins(:credits).group("credits.user_id")
I hope this helps you

Block or method to calculate float elements in column of data in Rails app

I am trying to show a sum of the floats of all records entered, and I can't seem to figure out how to do it. Here's the situation. My app (purely for learning purposes) has a user who can register a swimmer profile and upon doing so, can record swims for the swimmer. Swim belongs to Swimmer and Swimmer has many swims.
// swims_controller.rb
// SwimsController#index
#swims = #swimmer.swims.all
#distances = #swimmer.swims.all(:select => "distance")
In the view for this action, I iterate through swims to get swim.date and swim.distance. Then I add this line which doesn't work
<p>Total distance: <%= #distances.each { | x | x.distance.inject(:+).to_f } %></p>
The error I am getting is "undefined method `inject' for 5500.0:Float" (5500.0 is the distance of the first swim recorded for this swimmer). I used inject based on other threads (e.g., How to sum array of numbers in Ruby?) but clearly, I'm missing something. Actually, I'm probably missing quite a lot because I'd like to put this a #total_distance method in the Swim model (swim.rb) but when I try to do that, I can't get the controller to recognize the method and I read elsewhere that a view should not try to access a method defined in a model due to "caching" issues.
Anyone's useful guidance on this would greatly help. Seems like a pretty basic thing to want to do but for some reason, I find scant guidance on a question like this after numerous search queries. Thanks!
I am not that experience but try to do <%= #swims.inject(0) {|num,n| num + n[:distance] } %>
OR
<%= #distances.inject {|sum, n| sum + n } %>
I hope this would work.
Thanks.
You should take a look at active record calculation. It already supports sum:
http://ar.rubyonrails.org/classes/ActiveRecord/Calculations/ClassMethods.html

How to sum all properties of a nested collection?

Given I got User.attachments and Attachment.visits as an integer with the number count.
How can I easily count all the visits of all images of that user?
Use ActiveRecord::Base#sum:
user.attachments.sum(:visits)
This should generate an efficient SQL query like this:
SELECT SUM(attachments.visits) FROM attachments WHERE attachments.user_id = ID
user.attachments.map{|a| a.visits}.sum
There's also inject:
user.attachments.inject(0) { |sum, a| sum + a.visits }
People generally (and quite rightly) hate inject, but since the two other main ways of achieving this have been mentioned, I thought I may as well throw it out there. :)
The following works with Plain Old Ruby Objects, and I suspect the following is marginally faster than using count += a.visits, plus it has an emoticon in it:
user.attachments.map(&:visits).inject(:+)

Resources