merit-gem / merit

Reputation engine for Rails apps
Other
1.52k stars 197 forks source link

Leaderboard? #322

Closed monroemann closed 5 years ago

monroemann commented 5 years ago

Hello!

We are trying to add a leaderboard page, but this code:

  def leaderboard
    leaderboard = Merit::Score.top_scored(since_date: 1.week.ago, limit: 25)    
  end

This results in a 'undefined method top_score error.

We also tried to manually create a leaderboard by creating an array, i.e.

leaderboard = User.all.score_points(category: 'Total')

but that also resulted in an undefined method, this time for score_points

Do you happen to know what we are doing incorrectly? Thank you!

monroemann commented 5 years ago

@tute thank you! :D

tute commented 5 years ago

Hi @monroemann! You have to define that method in a new file in your Rails app, copying the contents from https://github.com/merit-gem/merit/wiki/How-to-show-a-points-leaderboard. You can do it in a model or an initializer and it will work (the wiki suggests an initializer but I'd now do it within app/models/merit/).

Best!

monroemann commented 5 years ago

Hi @tute thanks for the quick response! Two follow ups:

  1. So I should create a file called app/models/merit/merit_scores_override.rb or just take that code and insert it directly into an already existing file?
  2. If we want to list only users with more than 50 points earned over last 7 days, is that possible? This one would be for admin, so we know who is an โ€œactive userโ€.

Thanks very much! cc: @chen-robert @bhavyabh @shreepatel95

tute commented 5 years ago
  1. It would be a new file called app/models/merit/score.rb
  2. Have to recheck the script, not exactly sure now but should be possible!

:)

monroemann commented 5 years ago

Hi @tute Thanks again for your generous assistance!

We created the app/models/merit/score.rb file and pasted the code you listed on https://github.com/merit-gem/merit/wiki/How-to-show-a-points-leaderboard

And then, I put this code in the view:

<%= Merit::Score.top_scored %>

I reset the server and went to the leaderboard page and I'm still getting the same error:

undefined methodtop_scored' for Merit::Score(id: integer, sash_id: integer, category: string):Class`

Is there still something I may be missing? Thanks!

tute commented 5 years ago

:thinking: And does putting it as an initializer work?

monroemann commented 5 years ago

I shall try that @tute

monroemann commented 5 years ago

Doing that gives me this:

image

So it seems to be accessing something in the database, but it's not a leaderboard. Does this look like we're on the right track?

The view code is: <%= Merit::Score.top_scored %>

Is that an array it is displaying?

monroemann commented 5 years ago

Ahh, it's a hash. I am getting closer: image

I'm working on displaying the user's name, and the point value.

monroemann commented 5 years ago

I'm getting closer. I was able to map them to just display user_id and sum_points. But I'm stuck on how to then access that user_id to turn it into the user's .full_name (which is a method we defined).

image

monroemann commented 5 years ago
      <% Merit::Score.top_scored.map.each do |x|  %>
        <% array = [] %>
        <% array = x.values[0] %>
        <% i = 0 %>
          <% while i < x.length %>
            <%= User.find(user_id: array[i]).first_name %>
            <% i += 1 %>
          <% end %>
      <% end %>

This is what I am working on, but I think I'm probably making it too complicated.

monroemann commented 5 years ago

Progress:

      <% Merit::Score.top_scored.map.each do |x|  %>
        <% array = [] %>
          <% x.each do |user| %>
            <% array << x.values[0] %>
          <% end %>
        <% i = 0 %>
          <% while i < x.size %>
            <%= User.find(array[i]).first_name %>
            <% i += 1 %>
          <% end %>
      <% end %>

give this output, which works, but is duplicating the first name: image

Trying to figure out why there are duplicates.

I guess I'll stop at this point. Is there an easier way to display the leaderboard? ๐Ÿ˜„

tute commented 5 years ago

I think you'd want something like:

<%= Merit::Score.top_scored.map do |top_score_hash|
  User.find(top_score_hash[:user_id]).first_name
end.to_sentence %>

Closing this issue as it's not a bug in merit or its docs, but happy to continue further discussion. Good luck!

monroemann commented 5 years ago

Hi @tute Sorry to bother you again, but I'm getting this error:

image

Thoughts?

monroemann commented 5 years ago

And does this only show the first name? Is the score also included in this code?

tute commented 5 years ago

top_score_hash should have the score, too. To debug, what does the following show for you?

<%= p Merit::Score.top_scored.map(&:inspect).inspect %>
<%= p Merit::Score.top_scored.inspect %>
monroemann commented 5 years ago

Hi @tute

Here is the output from each of those lines of code, separated by two line breaks:

image

Does this help you?

tute commented 5 years ago

Yes, and it might help you too! The keys are strings not symbols so:

<%= Merit::Score.top_scored.map do |top_score_hash|
  User.find(top_score_hash["user_id"]).first_name + " " + top_score_hash["sum_points"]
end.to_sentence %>
monroemann commented 5 years ago

Another error! ๐Ÿ˜„

image

Thoughts on this one @tute

monroemann commented 5 years ago

Do we need to turn sum_points into a string? Or maybe I'll just try displaying it without quotation marks?

monroemann commented 5 years ago

I found this, but it's not quite clear to me: https://stackoverflow.com/questions/20450497/ruby-on-rails-no-implicit-conversion-of-string-into-integer-for-getting-json

monroemann commented 5 years ago

Ahh! I got it work by adding .to_s !!

<%= Merit::Score.top_scored.map do |top_score_hash|
        User.find(top_score_hash["user_id"]).first_name + " " + top_score_hash["sum_points"]**.to_s**
  end.to_sentence %>

That produces this: image

My final questions: how to display them in distinct columns. Can I just do two different User.find queries, each displayed within a different column? Or better, perhaps I should move these queries into the controller or model, and save the results as instance variables? Thanks so much @tute

tute commented 5 years ago

I wish we were closer so we could pair in a meetup, I think it will be way easier for you to grasp this in a collaborative space like that.

No need of another find, as you already have the score. The line in the middle of my snippet contains the data you need, you may now display it as you please in an erb template.

Best!

monroemann commented 5 years ago

HOORAY! I got it to work! This is the code I wrote:

image

And this is the result. Not bad, do you agree?

image

Does this look like it works okay?

monroemann commented 5 years ago

Follow up question: If on this one page, I'd like to display four leaderboards: Today, Last 7 Days, Last 30 days, and Last 365 days, can I manually override that here in the view? Or do I have to do something in that initializer file?

monroemann commented 5 years ago

I just looked at your documentation again. Would this work appropriately:

        <% Merit::Score.top_scored(since_date: 1.week.ago,
        limit: 25).map do |top_score_hash| %>
monroemann commented 5 years ago

I wish we were closer so we could pair in a meetup, I think it will be way easier for you to grasp this in a collaborative space like that.

No need of another find, as you already have the score. The line in the middle of my snippet contains the data you need, you may now display it as you please in an erb template.

Best!

We shall meet one day in person! :smile:

monroemann commented 5 years ago

And, it worked! Looks like this:

image

Is it okay that I have all that code in the erb template?

monroemann commented 5 years ago

And (thanks for being so patient with all my questions), is there a way to show "This Month", "This Week", "This Year", etc that uses the calendar? And what exactly does 1.day.ago do? Does that show today, or the last 24 hours? It would be great to show 'Today' and 'Yesterday' based on clock time.

tute commented 5 years ago

Glad you made it work! Check Rails' DateTime API:

monroemann commented 5 years ago

Thank you very much! Shall start researching! ๐Ÿ˜„ ๐Ÿš€

monroemann commented 5 years ago

Where do you live, incidentally? You are Argentinian?