Search code examples
rubyactiverecord

"NameError - uninitialized constant" error when creating new association in has_many object. Plural issue?


I'm getting error: NameError - uninitialized constant List::Listfavourite:

This is referencing: list.listfavourites.create(...) from my controller. The List exits. Its association seems to be broken.

In other errors I've worked around, it sometimes looked for 'list_favourite', so I'm not sure where I've messed up with naming? I've checked other answers here and plural can be an issue.

When db:migrate was ran, a table called - listfavourites was made in my Postgres db.

Schema:

create_table "listfavourites", force: :cascade do |t|
  t.bigint "list_id"
  t.integer "user_id"
  t.integer "word_id"
  t.datetime "created_at", precision: 6, null: false
  t.datetime "updated_at", precision: 6, null: false
  t.index ["list_id"], name: "index_listfavourites_on_list_id"
end

create_table "lists", force: :cascade do |t|
  t.integer "word_id"
  t.string "text"
  t.integer "user_id"
  t.datetime "created_at", precision: 6, null: false
  t.datetime "updated_at", precision: 6, null: false
end

List:

class List < ActiveRecord::Base
  has_many :listfavourites, dependent: :destroy
end

ListFavourite:

class ListFavourite < ActiveRecord::Base
  belongs_to :list
end

Controller

class ListsController < ApplicationController
  post '/list/:list_id/:word_id' do
    list_id = params["list_id"]
    word_id = params["word_id"]
    list = List.find_by(id: list_id, user_id: @user_id) # the list exists
    list.listfavourites.create(list_id: list_id, user_id: @user_id, word_id: word_id)
    list.to_json
  end
end

Solution

  • Please take a moment to read the documentation on ActiveRecord Naming Conventions:

    The Rails pluralization mechanisms are very powerful, being capable of pluralizing (and singularizing) both regular and irregular words. When using class names composed of two or more words, the model class name should follow the Ruby conventions, using the CamelCase form, while the table name must use the snake_case form. Examples:

    • Model Class - Singular with the first letter of each word capitalized (e.g., BookClub).
    • Database Table - Plural with underscores separating words (e.g., book_clubs).

    In your case, the table name listfavourites should be list_favourites because your class name is ListFavourites. Likewise your has_many call should be to has_many :list_favourites.

    The cheat-sheet version of how to remember this is: object names that contain multiple words require a separator of some kind between them, whether it's capitalization in CamelCase or underscores in snake_case.

    You should make a new migration that renames the table to list_favourites (and renames the index to index_list_favourites_on_list_id) and then update your code to ensure all references to listfavourites and Listfavourite have been corrected.

    Do not try to go the other direction and rename everything to be Listfavourite and listfavourites -- Rails follows convention over configuration and the convention is as I've described above.