I am new to rails and am trying to build a blog app where only signed in users can see the username of the person who created a post, however I keep getting this error NoMethodError in Posts#index undefined method `username' for nil:NilClass
screenshot of error in localhost:3000
Here is my routes.rb
```
Rails.application.routes.draw do
devise_for :users
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
# Defines the root path route ("/")
# root "articles#index"
root "posts#index"
resources :posts, only: [:new, :create, :index]
get "/posts/new.html.erb", to: "posts#create", as: "create"
get "/posts/new.html.erb", to: "posts#new", as: "new"
end
```
here is my posts_controller.rb
class PostsController < ApplicationController
before_action :authenticate_user!, except: [:index]
def new
@post = Post.new
end
def create
@post = current_user.posts.build(post_params)
@post.user = current_user
respond_to do |format|
if @post.save
format.html { redirect_to user_post_path(current_user, @post), notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: @post }
else
format.html { render :new }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
def index
@posts = Post.all.order(created_at: :desc)
end
private
def post_params
params.require(:post).permit(:title, :description)
end
end
```
here is my post.rb model
```
class Post < ApplicationRecord
belongs_to :user
end
```
here is my user.rb model
```
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :posts
validates :username, presence: true
validates :email, presence: true
validates :password, presence: true
end
``
here is my schema
```
ActiveRecord::Schema[7.0].define(version: 2022_11_14_173843) do
create_table "posts", force: :cascade do |t|
t.string "title"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "username"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
end
```
here is my AddNameToUsers migration
```
class AddNameToUsers < ActiveRecord::Migration[7.0]
def change
add_column :users, :username, :string
end
end
```
Here is my AddUserIdToPosts migration
```
class AddUserIdToPosts < ActiveRecord::Migration[7.0]
def change
add_column :posts, :user_id, :integer
end
end
```
Here is my CreatePosts Migration
```
class CreatePosts < ActiveRecord::Migration[7.0]
def change
create_table :posts do |t|
t.string :title
t.text :description
t.timestamps
end
end
end
```
CodePudding user response:
Try debugging the post object which is raising the Exception.
It looks like there is a Post
object which doesnt have a user associated with it. So post.user
returns nil and when username
method is called on the nil object an Exception is raised as it is not defined on nil
.
You may check in the rails console which post doesnt have a user associated with it and based on your requirements either correct such objects or remove the objects from being displayed in index or just do not show a username for posts if it is not present.
CodePudding user response:
I finally got it working, for the link_to error, I simply needed to remove the only: function in my routes.rb to only say resources :posts and for the username error I referenced a user in my createPosts migration and then cleared the Posts and Users in the rails console and started over from signing up to making a post to viewing all posts to seeing a single post