Ivan Velchev
Ivan Velchev

Reputation: 75

Ruby on Rails SQLite3::ConstraintException: NOT NULL constraint failed:

I am developing a simple app where a user can add a subject to a cart. Before I add the authentication I was able to add a subject to the cart but as I want a user to be able to has access to just his/her cart I used Devise to create User with authentication. Now, when I click on the button to add a subject to the cart I have the following error:

This is a snapshot of the error I get: 1

SQLite3::ConstraintException: NOT NULL constraint failed: carts.user_id: INSERT INTO "carts" ("created_at", "updated_at") VALUES (?, ?)

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  private

    def current_cart
      Cart.find(params[:user_id])
    rescue ActiveRecord::RecordNotFound
      cart = Cart.create
      params[:user_id] = cart.id
      cart
    end
end


    class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  has_one :cart
end

class Cart < ActiveRecord::Base
  belongs_to :user
  has_many :line_items, dependent: :destroy

  scope :user_carts, ->(user) { where(['user_id= ?', user.id]) }

end

class AddUsersToCarts < ActiveRecord::Migration

  def up
    add_reference :carts, :user, index: true
    Cart.reset_column_information
    user = User.first

    Cart.all.each do |cart|
      cart.user_id = user.id
      cart.save!
    end

    change_column_null :carts, :user_id, false
    add_foreign_key :carts, :users
  end

  def down
    remove_foreign_key :carts, :users
    remove_reference :carts, :user, index: true
  end

end

Edit: I added the schema.rb below:

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

  create_table "carts", force: :cascade do |t|
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer  "user_id",    null: false
  end

  add_index "carts", ["user_id"], name: "index_carts_on_user_id"

  create_table "line_items", force: :cascade do |t|
    t.integer  "subject_id"
    t.integer  "cart_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "subjects", force: :cascade do |t|
    t.string   "title",       null: false
    t.string   "code",        null: false
    t.text     "description", null: false
    t.integer  "credits",     null: false
    t.string   "lecturer",    null: false
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
  end

  add_index "subjects", ["title"], name: "index_subjects_on_title", unique: true

  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.integer  "sign_in_count",          default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string   "current_sign_in_ip"
    t.string   "last_sign_in_ip"
    t.datetime "created_at",                          null: false
    t.datetime "updated_at",                          null: false
  end

  add_index "users", ["email"], name: "index_users_on_email", unique: true
  add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true

end

Upvotes: 2

Views: 10804

Answers (1)

spickermann
spickermann

Reputation: 106882

You current_cart method does not make much sense.

  1. You cannot find the user's cart by calling Cart.find(params[:user_id]), because that looks for a cart by an id (not by an user_id).
  2. Cart.create fails, because you do not provide an user_id that is required (your database migrations says that the filed cannot be null).
  3. Furthermore, params[:user_id] = cart.id changes the params hash, but not the new cart.

Change that method to something like this (using find_or_create_by) and use the current_user.id instead of params[:user_id]:

def current_cart
  Cart.find_or_create_by(user_id: current_user.id)
end

Upvotes: 1

Related Questions