sandypockets
sandypockets

Reputation: 427

NoMethodError - Rails - Can't track down the problem

I am currently working on a blog app. The blog has users, stories, and favourites. 1 user can have many stories and many favourites, and one story can have many favourites (1 from each user) too.

When I try to save a new favourite on the front end (the create route), I receive the following error:

undefined method `favourites' for #<Class:0x00007f850e24e290>

Extracted source (around line #11):
9  def create
10 @story = Story.find(params[:story_id])
11 @favourite = Story.favourites.new
12 @favourite.user = @current_user
13 @favourite.save
14 redirect_to story_path(@story) 

I feel like this should be defined, and is almost the same way that I am using create with other controllers. Based on what I've found so far, I suspect that it is because the favourites in Story.favourites.new is nested within the Story, but I haven't found a way to sort it out yet. I'm quite new to Rails, so apologies if the answer is obvious. Any guidance is appreciated! Thanks for your help!

Below are some of the pertinent files.

favourites_controller.rb

class FavouritesController < ApplicationController

  before_action :logged_in, except: [:index, :show]

  def show
  end

  def create
    @story = Story.find(params[:story_id])
    @favourite = Story.favourites.new
    @favourite.user = @current_user
    @favourite.save
    redirect_to story_path(@story)
  end

end

stories_controller.rb

class StoriesController < ApplicationController

  before_action :logged_in, except: [:index, :show]

  # Stories list page (also homepage)
  def index
    # Topic filtering
    @topic = params[:topic]
    @stories = if @topic.present?
                 Story.where(topic: @topic)
               else
                 Story.all
               end
  end

  def new
    @story = Story.new
  end

  def create
    @story = Story.new(form_params)
    @story.user = @current_user
    if @story.save
      redirect_to root_path
    else
      render 'new'
    end
  end

  def show
    @story = Story.find(params[:id])
  end

  def destroy
    @story = Story.find(params[:id])
    @story.destroy if @story.user == @current_user
    redirect_to root_path
  end

  def edit
    @story = Story.find(params[:id])
    redirect_to root_path if @story.user != @current_user
  end

  def update
    @story = Story.find(params[:id])
    if @story.user == @current_user
      if @story.update(form_params)
        redirect_to story_path(@story)
      else
        render 'edit'
      end
    else
      redirect_to root_path
    end
  end

  def form_params
    params.require(:story).permit(:title, :topic, :body)
  end

end

models/favourite.rb

class Favourite < ApplicationRecord
  belongs_to :story
  belongs_to :user

  validates :story, uniqueness: { scope: :user }
end

models/story.rb

class Story < ApplicationRecord

  has_many :comments
  has_many :favourites
  belongs_to :user

  validates :title, presence: true
  validates :body, presence: true, length: { minimum: 10 }

  def to_param
    id.to_s + '-' + title.parameterize
  end

end

config/routes.rb

Rails.application.routes.draw do

  resources :stories do
    resources :comments
    resource :favourite
  end

  resources :users
  resource :session

  root 'stories#index'

end

Upvotes: 0

Views: 40

Answers (1)

amrrbakry
amrrbakry

Reputation: 599

the issue is in this line:

11 @favourite = Story.favourites.new

it should be:

11 @favourite = @story.favourites.new

because the class Story itself doesn't have the favourites method but its instances do.

Upvotes: 3

Related Questions