I'm looking to build a basic app that provides a score based on how enjoyable users found a given lunch.
In my view, the voting buttons look like this:
<%= form_for :lunch, url: upvote_lunch_lunch_path(params[:id]), method: :put, :html => {:class => 'form-inline'} do |f| %>
<%= f.hidden_field :liked %>
<%= f.hidden_field :id %>
<%= f.submit "Like Lunch", class: "btn btn-large btn-success" %>
<% end %>
<%= form_for :lunch, url: downvote_lunch_lunch_path(params[:id]), method: :put, :html => {:class => 'form-inline'} do |f| %>
<%= f.hidden_field :disliked %>
<%= f.hidden_field :id %>
<%= f.submit "Dislike Lunch", class: "btn btn-large btn-danger" %>
<% end %>
Displaying the value (in a partial) looks like this:
<%= number_to_percentage(@enjoy_score * 100, precision: 0, format: "%n") %>
and finally, in my "lunches" controller, I have the following:
def show
@lunch = Lunch.find(params[:id])
@provider = @lunch.provider
@total_enjoy_votes = (@lunch.liked + @lunch.disliked)
@enjoy_score = (@lunch.liked.to_f / @total_enjoy_votes)
end
def downvote_lunch
@lunch = Lunch.find(params[:id])
@lunch.increment!(:disliked)
redirect_to @lunch
end
def upvote_lunch
@lunch = Lunch.find(params[:id])
@lunch.increment!(:liked)
redirect_to @lunch
end
Everything works as expected, so long as the database already has values for liked and disliked against that particular lunch ID. If, for example, you are the first person to attempt to answer this question (lets say just after a lunch was created) the application errors out with the message "undefined method +' for nil:NilClass" at this line:@total_enjoy_votes = (@lunch.liked + @lunch.disliked)`
Two questions:
- Why is it if I open the database (with sqlitebrowser) and "seed" a row of data with liked = 1 and disliked = 1 the methods will work as expected, but if I don't, it errors out? What should I do to "initialize" @lunch.liked and @lunch.disliked so that there isn't an error for the initial user?
- (Bonus Point) How can I keep the controller code DRY so I don't have to type
@lunch = Lunch.find(params[:id])at the beginning of every method?
Thanks so much in advance. I apologize if this is a insanely simple question.