0

I feel like I am making a syntax error.

I am trying to define an instance method in the model, that then gets called with an instance receiver. but the output is nilClass.

What am I doing wrong?

model

class Park < ActiveRecord::Base

  has_many :reviews

  def percentages
    @percentages = Array.new(5, 0)
    if reviews.any?
      5.downto(1).each_with_index do |val, index|
        @percentages[index] = (reviews.with_stars(val).size) * 100 / (reviews_count)
      end
      @percentages
    end
  end

end

controller

class ParksController < ApplicationController

  def show
     @park = Park.find(params[:id])
     @percentages = @park.percentages
  end

end

view

= @percentages[0]

output

undefined method `[]' for nil:NilClass
ahnbizcad
  • 10,491
  • 9
  • 59
  • 85
  • Does your `@park` have any reviews? Because if it doesn't, `nil` will be returned from `Park#percentages`. – Marek Lipka Nov 17 '14 at 08:19
  • You're saying the condition overrides the defined array? – ahnbizcad Nov 17 '14 at 08:20
  • `Park#percentages`? I thought I was defining an instance method. I am confused =] – ahnbizcad Nov 17 '14 at 08:21
  • Not exactly. I'm saying if the condition isn't fulfilled, array isn't even created. And yes, `Park#percentages` indicates instance method of `Park` class. – Marek Lipka Nov 17 '14 at 08:21
  • But am I not creating it before the condition? My intention is that if review records are found, it overwrites the array. – ahnbizcad Nov 17 '14 at 08:22
  • 1
    Yes, my bad. You create array, but remember in Ruby the last evaluated value is returned from the method (it's called implicit return), so if your condition returns `false`, the value of `if` expression is `nil`, which is returned. – Marek Lipka Nov 17 '14 at 08:24
  • oh so I should put `@percentages` completely after the `if end` block. I forgot implicit returns also pick up on if conditions. – ahnbizcad Nov 17 '14 at 08:27
  • Yes, it will solve your problem. – Marek Lipka Nov 17 '14 at 08:28

1 Answers1

2

You should explicitly return the @percentages after the if.

def percentages
  @percentages = Array.new(5, 0)
  if reviews.any?
    5.downto(1).each_with_index do |val, index|
      @percentages[index] = (reviews.with_stars(val).size) * 100 / (reviews_count)
    end
  end
  @percentages
end

Moreover, you don't need an instance variable in the method. A simple variable would be enough.

def percentages
  percentages = Array.new(5, 0)
  if reviews.any?
    5.downto(1).each_with_index do |val, index|
      percentages[index] = (reviews.with_stars(val).size) * 100 / (reviews_count)
    end
  end
  percentages
end
Simone Carletti
  • 173,507
  • 49
  • 363
  • 364
  • Thank you. I initially used an ordinary variable, but thought making it an instance would be worth a try. (If you're stuck you do anything else you can think of!) – ahnbizcad Nov 17 '14 at 08:35