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
