Comparing two users - ruby-on-rails

I want to compare a user profile with another user profile based on education, experiences, skills, and country. If education is similar, the score will be 20, else it will be 0. And total_score will be the sum of the scores. I can then sort profiles similar to that of a given user based on the total score. Can anyone help me on how I can achieve this?
I don't know how to compare two users or two things from the same table, and I don't know where to put my code in: the profile model, helper, or what.

Add this to your User model.
def total_score
education+skills+country #modify to determine score, idk how you plan to determine this
end
When trying to sort:
User.all.sort_by{|a| a.total_score} #returns a list of users sorted by total score.
EDIT
I think you mean this:
def total_score
score=0
if education=="First School"
score+=10
elsif education=="Second School"
score+=5
end
if skill=="Skill 1"
score+=10
elsif education=="Skill 2"
score+=5
end
if country=="Country 1"
score+=10
elsif country=="Country 2"
score+=5
end
end

Related

How to rank based on a selection?

For a reservation I would like to calculate the price for extra_guests (e.g. guests not included in the price).
Therefore, I would like to get all the guests for the reservation (reservation_guests). Done
Get their age_table Done
Rank the guests based on their age_tables' column :rank. Issue
The goal is to use the ranking to start calculating the extra_guest_price of the extra_guest with the lowest age_table ranking, in case there are guests not included in the standard reservation.
Issue
I just need a specific range of age_tables to rank based on :rank. My current set-up is wrong as I cannot use order on an array, but I'm not sure how to structure it to make it work.
def total_extra_guest_price(reservation, res_guest)
sum_guest = 0
sum_amount_guests = 0
age_table_list = []
reservation.reservation_extra_guests.each do |guest|
sum_amount_guests += guest.extra_guest_quantity
end
# persons included vs persons reservation
#if more persons
if reservation.room.room_category.persons_included < sum_amount_guests
#count number of too many persons
extra_persons = sum_amount_guests - reservation.room.room_category.persons_included
# iterate over extra_guests belonging to reservation to get age_tables
reservation.reservation_extra_guests.each do |extra_guest_item|
age_table_list << extra_guest_item.extra_guest.age_table
end
#rank age tables, so lowest rank can be used to calculate price. Issue!!!
age_table_list.order(:rank)
end
end
I'm not 100% clear about your question so my suggestion may not be the best solution. But you can try the sort_by()
age_table_list.sort_by{ |age_table| age_table.rank }
read more here

Calculate average conditionally based on an attribute in a rake task (Rails)

I have a requirement where I need to calculate the average of units sold for a product based on the company they were sold at.
The scenario is we're importing data from a legacy database, and when importing I'd like to perform some calculations based on the difference between units sold for new item and the average of the existing item's, when they were sold at the same company.
The model is called Product and has attributes of:
name
interest (How many units were sold)
company (What company they
were sold at)
Now previously, I am able to calculate the average of each company on the model like so:
def self.average_interest(company)
where(company: company).average(:interest)
end
But now I am trying to do the calculation on a rake task.
Here's what I came up with and it's not working:
#company = u.Company
#u.Company is the field name from the legacy database
def average_interest
Product.average(:interest, :conditions => ['company = ?', #company])
end
Any ideas?
Thanks!
EDIT:
Have updated it from '#company' to #company however the value being returned is still incorrect
In your rake task you can pass in the variable, so something like this:
def average_interest(company)
Product.average(:interest, :conditions => ['company = ?', company])
end
unentered_legacy_companies.each do |u|
average_interest(u)
end
after playing around, looks like it was only a slight adjustment from the original code that was needed.
Just had to add the model (Product) to the query in the code:
def average_interest(company)
Product.where(company: company).average(:interest)
end
And then I am storing it in a variable like so:
#company_average = average_interest(u.Company)

Rails sort users by method

I'm trying to rank my user's in order of an integer. The integer I'm getting is in my User Model.
def rating_number
Impression.where("impressionable_id = ?", self).count
end
This gives each User on the site a number (in integer form). Now, on the homepage, I want to show an ordered list that places these user's in order with the user with the highest number first and lowest number second. How can I accomplish this in the controller???
#users = User....???
Any help would be appreciated!
UPDATE
Using this in the controller
#users = User.all.map(&:rating_number)
and this for the view
<% #users.each do |user| %>
<li><%= user %></li>
<% end %>
shows the user's count. Unfortunately, the variable user is acting as the integer not the user, so attaching user.name doesn't work. Also, the list isn't in order based on the integer..
The advice here is still all kinds of wrong; all other answers will perform terribly. Trying to do this via a nested select count(*) is almost as bad an idea as using User.all and sorting in memory.
The correct way to do this if you want it to work on a reasonably large data set is to use counter caches and stop trying to order by the count of a related record.
Add a rating_number column to the users table, and make sure it has an index defined on it
Add a counter cache to your belongs_to:
class Impression < ActiveRecord::Base
belongs_to :user, counter_cache: :rating_number
end
Now creating/deleting impressions will modify the associated user's rating_number.
Order your results by rating_number, dead simple:
User.order(:rating_number)
The advice here is just all kinds of wrong. First of model your associations correctly. Secondly you dont ever want to do User.all and then sort it in-memory based on anything. How do you think it will perform with lots of records?
What you want to do is query your user rows and sort them based on a subquery that counts impressions for that user.
User.order("(SELECT COUNT(impressions.id) FROM impressions WHERE impressionable_id = users.id) DESC")
While this is not terribly efficient, it is still much more efficient than operating with data sets in memory. The next step is to cache the impressions count on the user itself (a la counter cache), and then use that for sorting.
It just pains me that doing User.all is the first suggestion...
If impressions is a column in your users table, you can do
User.order('impressions desc')
Edit
Since it's not a column in your users table, you can do this:
User.all.each(&:rating_number).sort {|x,y| y <=> x }
Edit
Sorry, you want this:
User.all.sort { |x, y| y.rating_number <=> x.rating_number }

How can I sort on a calculated value?

I'm currently building an NFL pick'em league site. I have a Users model, a Games model, and join table which captures each user's individual picks. The games model has a "result" attribute which either consists of "W" for win, "L" for loss, "P" for push (tie).
I am running into issues building a standings page. I currently have two methods in my Users model:
def correct_games
self.games.where(result: "W").count
end
def total_games
self.games.where('result != ?', "P").count
end
The correct_games method counts the user's picks that were correct. The total_games methods counts the number of total games (not counting games that resulted in a push).
Then in my view I currently have for each user: <%= number_to_percentage(current_user.correct_games.to_f / current_user.total_games) %>
This division gives me that user's win percentage (# correct/total picks). For my standings table, I obivously want a descending order on win percentage. The issue is the only solutions to sorting seem to be using the .order method which usually requires some attribute to already be in the database which you can then call in the controller.
I've also tried adding this win percentage attribute to the database, but I can't seem to figure out a callback that will update the User's score whenever the game results are updated.
Any solutions to either sorthing on an attribute that is calculated in the view or a way to add this win percentage to the users model?
Thanks in advance!
Why not just do the calculation in the model instead of in the view? Add another method like this:
This code goes in your User model:
def percentage_correct
((self.correct_games.to_f / self.total_games) * 100).to_i
end
def self.sorted_by_percentage_correct
User.all.sort_by(&:percentage_correct).reverse
end
This is how you use it in your view:
<% User.sorted_by_percentage_correct.each do |u| %>
<div><%= u.name %> has pick percentage of <%= u.percentage_correct %>%</div>
<% end %>

Ruby: Compare two arrays for matches, and order results in DESC order

I have a user model. Each user has restaurant names associated with them. I have a view (index.html.erb) which shows all users.
I want to order the users in this view based on how many restaurants the current_user and some other user have in common in descending order... (it does the opposite!)
ex.
User1 (current_user) has been to McDonalds, Burger King, Arby's
User2 has been to Ivar's
User3 has been to McDonalds, Burger King
When User1 loads the index view, the order the users should be displayed is:
User1 (3/3 restaurants match)
User3 (2/3 restaurants match)
User2 (0/3 restaurants match)
my User.rb file
def compare_restaurants
self.restaurants.collect
end
my users_controller.rb
def index
#users = User.all.sort_by {|el| (el.compare_resturants & current_user.compare_resturants).length }
end
If you're dead set on using sort_by then you can just negate the numbers:
def index
#users = User.all.sort_by { |el|
-(el.compare_resturants & current_user.compare_resturants).length
}
end
This trick only works because you're sorting by numeric values. If you were sorting on strings then you'd have to use something like this:
reverse_sorted = a.sort_by { |x| something(x) }.reverse
but that would involve an extra copy of the array and the extra work that reverse would do. In such cases you should use a full sort with reversed comparison logic.
If you're were trying to use sort_by to avoid computing something expensive for each comparison and you were sorting on something non-numeric, then you could always use sort with an explicit Schwartzian Transform to compute the expensive things only once.
Just sort them in the controller.
my = User.find_by_id this_user # Or however you're getting "the current user"
#users = User.all.-([my]).sort do |a, b|
common_with_a = (my.restaurants & a.restaurants).length
common_with_b = (my.restaurants & b.restaurants).length
common_with_a <=> common_with_b
end
... but if you're planning on letting the user start sorting various columns or reversing the sorting a lot, you should implement your sort in Javascript so you can cut down on the number of page reloads and subsequent database hits you have to make.

Resources