1

I am able to view 5 stars for a rating of 5 for a article, and 4 stars for a rating of 4 etc. I reference Ruby on Rails display half a star for a decimal rating, e.g. 4.5.

What I'd like to do is to display "star-off.png" if a rating is not 5 stars. For example, if a rating is 3, display 3 "star-on.png" and 2 "star-off.png".

Although I know some gems such as ratyrate, I'd like to know how to describe without using gems.

\app\helpers\application_helper.rb

...
  def render_stars(value)
    output = ''
    if (1..5).include?(value.floor)
      value.floor.times { output += image_tag('star-on.png')}
    end
    if value == (value.floor + 0.5) && value.to_i != 5
      output += image_tag('star-half.png')
    end
    output.html_safe
  end
...

\app\views\articles\ _article.html.erb

...
    <% if article.rating.blank? %>
    <% else %>
      <%= render_stars(article.rating) %>
    <% end %>
...
Community
  • 1
  • 1
SamuraiBlue
  • 851
  • 2
  • 17
  • 44

2 Answers2

1

I've reworked your code a little to try and handle all the cases. See comments.

def render_stars(value)
  output = ''

  # Saved to variable for efficiency
  floored = value.floor

  # Adding full stars: If value is 2.5 then floored 
  # will be 2 (two full stars)
  floored.times { output << image_tag('star-on.png') }

  # Getting the decimal part of the value by subtracting the
  # floored value, by the value. So if value is 2.7, then will be
  # 0.7 (Changed to >= to account for ability to use numbers like
  # 2.7 and will display a half star. If you would like to only
  # handle 0.5 then change back to ==)
  if (value - floored) >= 0.5
      output << image_tag('star-half.png')
  end

  # Completes sequence of 5 stars. Ex: if value is 2.7 then 5 - 2.7
  # is 2.3 The output will already have 2 full stars and 1 half star
  # so by flooring 2.3 we will get 2, which completes the total of 5
  #stars
  (5 - value).round.times { output << image_tag('star-off.png') }
  output.html_safe
end
SnareChops
  • 13,175
  • 9
  • 69
  • 91
  • Thank you for your detailed comments, @SnareChops. It works! I made a minor change `(5 - value).round.times { output << image_tag('star-off.png')}` instead of `(5 - value).floor.times { output << image_tag('star-off.png') }` in the 3rd line from the bottom because only 4 stars (not 5 stars) are displayed if value is 2.3. Thanks all the same. – SamuraiBlue Feb 14 '15 at 05:14
0

I suggest changing the approach to start with a loop of 5 (for the 5 stars) and determine whether each position in the loop is on, half or off star.

I'd also use << instead of += when appending strings - faster.

HM1
  • 1,684
  • 2
  • 18
  • 25