Shane Shane - 5 months ago 21
Ajax Question

Using Ajax and getting NoMethodError (undefined method `[]' for nil:NilClass)

I'm super new to Rails and jQuery and am feeling a bit in over my head. I'm just trying to make a single page app that lets me log offensive things my friend has said and then uses an up and downvote system to order them. I'm having trouble getting to posts to reorder once scores are updated using Ajax. Right now I'm only trying to get this to implement on the downvote action. I've tried to include all relevant information here, but let me know if I need to include more.

Error

Completed 500 Internal Server Error in 39ms (ActiveRecord: 3.2ms)

NoMethodError (undefined method `[]' for nil:NilClass):
app/views/posts/_posts.html.erb:3:in `_app_views_posts__posts_html_erb__962868812775721276_70166010949980'
app/views/posts/downvote.js.erb:2:in `_app_views_posts_downvote_js_erb__4067496276046646679_70165971968540'
app/controllers/posts_controller.rb:39:in `downvote'


Rendered /Users/shaneboyar/.rvm/gems/ruby-2.3.1@myapp/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_source.erb (3.0ms)
Rendered /Users/shaneboyar/.rvm/gems/ruby-2.3.1@myapp/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_trace.text.erb (1.5ms)
Rendered /Users/shaneboyar/.rvm/gems/ruby-2.3.1@myapp/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/_request_and_response.text.erb (0.8ms)
Rendered /Users/shaneboyar/.rvm/gems/ruby-2.3.1@myapp/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates/rescues/diagnostics.text.erb (47.0ms)


Posts Controller

class PostsController < ApplicationController

def index
@new_post = Post.new
@all_posts = Post.order(score: :desc).all
end

def create
@new_post = Post.new(post_params)
if @new_post.save
flash[:success] = "Yeah... he probably would say that."
redirect_to root_path
end
end

def destroy
@post = Post.find(params[:id])
@post.delete
respond_to do |format|
format.html { redirect_to root_path }
format.js
end
end

def upvote
@post = Post.find(params[:id])
@post.score += 1
@post.save
respond_to do |format|
format.html { redirect_to root_path }
format.js
end
end

def downvote
@post = Post.find(params[:id])
@post.score -= 1
@post.save
respond_to do |format|
format.html { redirect_to root_path }
format.json { render json: @post }
format.js
end
end


Views/Posts/_Index.html.erb

<div class="jumbotron center">
<div class="container">
<h1>@MattBatt</h1>
<h4>Things Matt has probably said at one point.</h4>
</div>
</div>

<div class="container">

<!--BEGIN FORM -->
<%= form_for(@new_post) do |f| %>

<div class="form-group">
<div class="field">
<%= f.label :'What\'d that motherfucker say now?' %><br>
<%= f.text_area :comment, :class => 'form-control' %>
</div>

</div>
<div class="actions">
<%= f.button "Create", :class => 'btn btn-default btn-lg btn-block' %>
</div>

<% end %>
<!-- END FORM -->

<!--BEGIN ALERT -->
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %>"><%= message %></div>
<% end %>
<!--END ALERT -->

<!--BEGIN POSTS -->
<%= render 'posts' %>
<!--END POSTS -->

</div>


Views/Posts/_Posts.html.erb (I feel like maybe this is a mess?)

<div class="container-fluid comments" id="comments">
<ul>
<% @all_posts[0..9].each do |p| %>
<li class="row">
<div class="col-sm-2">
<div class='post-<%=p.id%>-score score'><%= p.score %></div>
<div class="voters">
<div class="upvoter"><%= link_to( image_tag("upArrow.png"), upvote_post_path(p), method: :patch, remote: true, :class => 'upvoter_button') %></div>
<div class="downvoter"><%= link_to( image_tag("downArrow.png"), downvote_post_path(p), method: :patch, remote: true, :class => 'downvoter_button') %></div>
</div>
</div>
<div class="comment col-sm-9">
<%= p.comment %>
<div class="timestamp">Posted <%= time_ago_in_words(p.created_at) %> ago.
<% if Rails.env.development? %>
<%= link_to "delete", p, method: :delete, remote: true, :class => 'deleter' %>
<% end %>
</div>
</div>
</li>
<% end %>
</ul>
</div>


routes.rb

Rails.application.routes.draw do

root 'posts#index'

get 'posts/index'

get 'posts/create'

resources :posts do
member do
patch 'upvote'
patch 'downvote'
end
end


Views/Posts/downvote.js.erb

$(".post-<%=@post.id%>-score").html('<%= @post.score %>');
$("#comments").html("<%= escape_javascript(render('posts/posts')) %>");


Thanks. I tried looking up the answer here and while it seems like a lot of people get a similar error, it's under different circumstances. Any advice would be really appreciated.

Answer

If you want to re-order the posts on downvote/upvote, I'd assume, you'd be using Rails to do that, although I think you could do same with JS effeciently.

You're receiving the error because @all_posts is not set in your downvote action, in your controller.

You could add it to a before_action call.

before_action :set_all_posts, only: [:index, :downvote, :upvote]
def set_all_posts
  @all_posts = Post.order(score: :desc)
end
Comments