ruby-on-railsforeign-keys

Ruby on Rails Foreign Keys Issue


I am trying to get a handle on how to use foreign keys in Rails,

$ rails g scaffold categories cat:string value:integer
$ rails db:migrate

Then create a new table with a foreign key connecting to the first table categories,

$ rails g scaffold subcategories subcats:string subcatsvalue:integer categories:references 
$ rails db:migrate

Then I append /categories to the url and the form is there as expected and I can do all CRUD operations.

Then I append /subcategories to the url and try to add some data to the form such as,

Subcats: blah Subcatsvalue: 123 Categories: cat1

should this be the id of the category or the name of the category?

/RubyLearningApp/db/migrate/20200413195730_create_categories.rb

class CreateCategories < ActiveRecord::Migration[5.0]
  def change
    create_table :categories do |t|
      t.string :cat
      t.integer :value

      t.timestamps
    end
  end
end

/RubyLearningApp/db/migrate/20200413200303_create_subcategories.rb

class CreateSubcategories < ActiveRecord::Migration[5.0]
  def change
    create_table :subcategories do |t|
      t.string :subcats
      t.integer :subcatsvalue
      t.references :categories, foreign_key: true

      t.timestamps
    end
  end
end

Is this correct way to set up a foreign key between tables?

When I fill in the Categories with 'cat1' I get the following error,

enter image description here

Schema.rb

ActiveRecord::Schema.define(version: 20200413200303) do

  create_table "categories", force: :cascade do |t|
    t.string   "cat"
    t.integer  "value"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "subcategories", force: :cascade do |t|
    t.string   "subcats"
    t.integer  "subcatsvalue"
    t.integer  "categories_id"
    t.datetime "created_at",    null: false
    t.datetime "updated_at",    null: false
    t.index ["categories_id"], name: "index_subcategories_on_categories_id"
  end

end

The model files:

category.rb

class Category < ApplicationRecord
end

subcategory.rb

class Subcategory < ApplicationRecord
  belongs_to :categories
end

Solution

  • There are a few things wrong with your scaffolds that may be causing the problems. The correct way to generate a scaffold is to use a singular scaffold name:

    rails g scaffold Category
    

    and

    rails g scaffold SubCategory
    

    This will use Rails built in Inflector to pluralize the names where necessary.

    When using references, you should also use the singular:

    category:references
    

    This is the Rails Way and it will sort out most of the problems you are having. The other issue is if you want to add the category to the url, you should nest your routes:

    resources :categories do
      resources :sub_categories
    end
    

    This will allow you to use routes like

    http://localhost:3000/categories/1/subcategories
    

    and

    http://localhost:3000/categories/1/subcategories/1
    

    The first number (the one closest to the left) is the category id and can be access by using params[:category_id] in the sub_categories_controller.rb file. The second number (the one closest to the right) is the sub_category id and can be accessed by params[:id] in the sub_categories_controller.rb file.