简体   繁体   中英

Rails - NoMethodError - undefined method `name' for nil:NilClass

I'm new to rails and recently noticed an error on one of my show views while working on a project for school. The error has to do with the name method not being defined yet I'm unsure how to remedy this. Help would be much appreciated! The error I receive is:

NoMethodError in Topics#show

Showing /Users/Jason/code/bloccit/app/views/topics/show.html.erb where line #17 raised:

undefined method `name' for nil:NilClass

<%= link_to post.title, [@topic, post] %>
         </h4>
         <small>
           submitted <%= time_ago_in_words(post.created_at) %> ago by <%= post.user.name %><br>
           <%= post.comments.count %> Comments
         </small>
       </div>

Relevant files include..

topics/show.html.erb

<h1><%= @topic.name %></h1>

<% if policy(@topic).update? %>
  <%= link_to "Edit Topic", edit_topic_path, class: 'btn btn-success' %>
<% end %>

<div class="row">
  <div class="col-md-8">
    <p class="lead"><%= @topic.description %></p>
    <% @posts.each do |post| %>
      <div class="media">
        <div class="media-body">
          <h4 class="media-heading">
            <%= link_to post.title, [@topic, post] %>
          </h4>
          <small>
            submitted <%= time_ago_in_words(post.created_at) %> ago by <%= post.user.name %><br>
            <%= post.comments.count %> Comments
          </small>
        </div>
      </div>
    <% end %>
  </div>
  <div class="col-md-4">
    <% if policy(Post.new).create? %>
      <%= link_to "New Post", new_topic_post_path(@topic), class: 'btn btn-success' %>
    <% end %>
  </div>
</div>

post.rb

class Post < ActiveRecord::Base
  has_many :comments
  belongs_to :user
  belongs_to :topic

  default_scope { order('created_at DESC') }
end

topic.rb

class Topic < ActiveRecord::Base
  has_many :posts
end

posts_controller.rb

class PostsController < ApplicationController
  def show
    @post = Post.find(params[:id])
    @topic = Topic.find(params[:topic_id])
    authorize @post
  end

  def new
    @topic = Topic.find(params[:topic_id])
    @post = Post.new
    authorize @post
  end

  def create
    @topic = Topic.find(params[:topic_id])
    @post = Post.new(post_params)
    @post.topic = @topic
    authorize @post

    if @post.save
      flash[:notice] = "Post was saved."
      redirect_to [@topic, @post]
    else
      flash[:error] = "There was an error saving the post.  Please try again."
      render :new
    end
  end

  def edit
    @topic = Topic.find(params[:topic_id])
    @post = Post.find(params[:id])
    authorize @post
  end

  def update
    @topic = Topic.find(params[:topic_id])
    @post = Post.find(params[:id])
    authorize @post

    if @post.update_attributes(post_params)
      flash[:notice] = "Post was updated."
      redirect_to [@topic, @post]
    else
      flash[:error] = "There was an error saving the post.  Please try again."
      render :new
    end
  end

  private

  def post_params
    params.require(:post).permit(:title, :body)
  end
end

topics_controller.rb

class TopicsController < ApplicationController
  def index
    @topics = Topic.all
    authorize @topics
  end

  def new
    @topic = Topic.new
    authorize @topic
  end

  def show
    @topic = Topic.find(params[:id])
    @posts = @topic.posts
    authorize @topic
  end

  def create
    @topic = Topic.new(topic_params)
    authorize @topic
    if @topic.save
      redirect_to @topic, notice: "Topic was saved successfully."
    else
      flash[:error] = "Error creating topic.  Please try again."
      render :new
    end
  end

  def edit
    @topic = Topic.find(params[:id])
    authorize @topic
  end

  def update
    @topic = Topic.find(params[:id])
    authorize @topic
    if @topic.update_attributes(topic_params)
      redirect_to @topic, notice: "Topic was updated successfully."
    else
      flash[:error] = "Error saving topic.  Please try again."
      render :edit
    end
  end

  private

  def topic_params
    params.require(:topic).permit(:name, :description, :public)
  end
end

you are not setting the user when creating a post, Im not sure about the implementation of your authorize method. However,

it should be something like

#assuming you have the user as `current_user`
class PostsController < ApplicationController
  ...
  def create
    @topic = Topic.find(params[:topic_id])
    @post = Post.new(post_params)
    @post.user = current_user
    @post.topic = @topic
    ...
  end 
  ...
end

your post has no user. you have to check why your post not saved the user. to prevent this error you have to check, user exist in post.

i would prefer to use delegate and follow the law of demeter

post.rb

class Post < ActiveRecord::Base
  has_many :comments
  belongs_to :user
  belongs_to :topic

  delegate :name, :to :user, allow_nil: true, prefix: true
  default_scope { order('created_at DESC') }
end

after this, you can receive the users name from the post like post.user_name and it will be forwarded to the name attribute of the user object.

and change in your show.html

<%= post.user.name %>

to

<%= post.user_name %>

additional: please do not use default_scope. if you dont need the order() you always have to unscope your queries.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM