Rails - Saving Objects with NOT NULL constraint - sql

I have a model called Issue that has the following database structure :
class CreateIssues < ActiveRecord::Migration
def change
create_table :issues do |t|
t.string :path, null: false
t.string :filename, null: false
t.string :name, null: false
t.string :year
t.integer :number
t.timestamps null: false
end
end
end
In my model tests, I use the following line :
issue = Issue.create path: "test_path", filename: "test_filename", name: "test_name"
... which raises an exception when saving :
SQLite3::ConstraintException: NOT NULL constraint failed:
issues.path: INSERT INTO "issues" ("created_at", "updated_at") VALUES (?, ?)
From what I understand, when calling create or new/save, rails starts by inserting an entry with only the timestamps. I would expect the insert to contain all of the values that I have passed to the create method. Am I missing a step in the creation process?
EDIT :
Basic information and steps:
Using SQLite3
Using Rails 4.2.1
Using RSpec
Generated the Issue model using be rails generate model Issue
Added the NULL constraints afterwords by hand
Did be rake db:migrate successfully
Tried my code in various model spec files
Tried other models, I get generated SQL that only includes the timestamps.
EDIT 2:
Here is my Issue model :
class Issue < ActiveRecord::Base
has_one :pending_issue
has_one :watched_issue
has_many :unmatched_issues
validates :path, presence: true
validates :filename, presence: true
validates :name, presence: true
attr_accessor :path
attr_accessor :filename
attr_accessor :name
attr_accessor :year
attr_accessor :number
end

Your result is anomalous. This is what I get:
# migration
class CreateIssues < ActiveRecord::Migration
def change
create_table :issues do |t|
t.string :path, null: false
t.timestamps null: false
end
end
end
Then in the console:
Issue.create path: "path"
# (0.1ms) begin transaction
# SQL (0.3ms) INSERT INTO "issues" ("path", "created_at", "updated_at") VALUES (?, ?, ?) [["path", "path"], ["created_at", "2015-06-21 16:55:08.304653"], ["updated_at", "2015-06-21 16:55:08.304653"]]
# (0.8ms) commit transaction
# => #<Issue id: 1, path: "path", created_at: "2015-06-21 16:55:08", updated_at: "2015-06-21 16:55:08">
My test:
require "test_helper"
describe Issue do
it "can be created" do
Issue.create path: "test_path"
end
end
passes. No exception.
What I think may have happened is that your database schema has become out of date on your test database.
Firstly, does a similar 'create' work in the development (default) rails console? If so, it's a big indication that something is very different in your test and development environments.
What happens if you force the console to use the test environment?
RAILS_ENV=test rails c
Does it work here?
I think you may need to manually rollback your test database to the migration which first created your issues table, then re-migrate
RAILS_ENV=test rake db:rollback
Keep applying until you reach the appropriate migration, then:
RAILS_ENV=test rake db:migrate
Does that help?
EDIT:
This appears to be the issue:
attr_accessor :path
attr_accessor :filename
attr_accessor :name
attr_accessor :year
attr_accessor :number
These will overwrite the Rails default accessors, at a guess. They are certainly not needed.

Did you accidentally omit attr_accessible for :path?

Related

Adding attribute to already existing model

I am trying to add user:references onto my already existing model. This is what I originally wrote:
rails g model Post title:string description:text
I do this to add the user:references by running rails generate migration add_user_to_posts user:references, I am receiving this error upon running rake db:migrate:
-- create_table(:users)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
SQLite3::SQLException: table "users" already exists
I am reading the error and I understand I already have a User model, however, I want to add this attribute to the Post model, not the User model.
Db file:
Posts:
class CreatePosts < ActiveRecord::Migration[5.0]
def change
create_table :posts do |t|
t.string :title
t.text :description
t.timestamps
end
end
end
Trying to add the user to posts:
class AddUserToPosts < ActiveRecord::Migration[5.0]
def change
add_reference :posts, :user, foreign_key: true
end
end
Users:
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :name
t.string :uid
t.string :avatar_url
t.timestamps
end
add_index :users, :uid
end
end
However, rake db:migrate gives me the error above.

using activeuuid gem for existing database in rails

I need to implement activeuuid gem to have UUIDs instead of default Rails ids. we can implement it for creating new migration as:
class CreateStudents < ActiveRecord::Migration
def change
create_table :students, :id => false do |t|
t.uuid :id, :primary_key => true
t.string :name
t.string :email
t.timestamps
end
end
end
And in model we include ActiveUUID::UUID as:
class Student < ActiveRecord::Base
attr_accessible :email, :name
include ActiveUUID::UUID
end
Now I already have a database so how can I implement the activeuuid gem to have UUIDs instead of default Rails ids for existing DB?
Need to make changes in all migrations or what?
Need help in this regard. thanks
The UUID is stored as a binary field w/ 16 positions as I found here: https://github.com/jashmenn/activeuuid/blob/master/lib/activeuuid/patches.rb#L62
It worked for me (existing table without records):
def change
reversible do |dir|
change_table :payments do |t|
dir.up { t.change :id, :binary, limit: 16, :primary_key => true }
dir.down { t.change :id, :integer }
end
end
end
Don't forget to add those lines to your model as well:
include ActiveUUID::UUID
natural_key :at_least_one_field_here
More info in the github repo: https://github.com/jashmenn/activeuuid/

Why does my users table have a no column error?

I am getting the following error after running my tests in the console:
ActiveRecord::StatementInvalid: SQLite3::SQLException: table users has no column named password: INSERT INTO "users"
user_test.rb:
class UserTest < ActiveSupport::TestCase
test "a user should enter a first name" do
user = User.new
assert !user.save
assert !user.errors[:first_name].empty?
end
test "a user should enter a last name" do
user = User.new
assert !user.save
assert !user.errors[:last_name].empty?
end
test "a user should enter a profile name" do
user = User.new
assert !user.save
assert !user.errors[:profile_name].empty?
end
test "a user should have a unique profile name" do
user = User.new
user.profile_name = users(:adam).profile_name
assert !user.save
assert !user.errors[:profile_name].empty?
end
end
users.rb:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me,
:first_name, :last_name, :profile_name
validates :first_name, presence: true
validates :last_name, presence: true
validates :profile_name, presence: true,
uniqueness: true
has_many :statuses
def full_name
first_name + " " + last_name
end
end
users.yml:
dan:
first_name: "Dan"
last_name: "Can"
email: "dan#email.com"
profile_name: "dan"
password: "123456"
password_confirmation: "123456"
database.yml:
# SQLite version 3.x
# gem install sqlite3
#
# Ensure the SQLite 3 gem is defined in your Gemfile
# gem 'sqlite3'
development:
adapter: sqlite3
database: db/development.sqlite3
pool: 5
timeout: 5000
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
adapter: sqlite3
database: db/test.sqlite3
pool: 5
timeout: 5000
production:
adapter: sqlite3
database: db/production.sqlite3
pool: 5
timeout: 5000
What I believe to be my user migrate file:
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
t.string :first_name
t.string :last_name
t.string :profile_name
## Database authenticatable
t.string :email, :null => false, :default => ""
t.string :encrypted_password, :null => false, :default => ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, :default => 0
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, :default => 0 # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
## Token authenticatable
# t.string :authentication_token
t.timestamps
end
add_index :users, :email, :unique => true
add_index :users, :reset_password_token, :unique => true
end
end
I would like to know what is causing the error, but more importantly why.
When I removed the password and password_confirmation columns from the users fixture it passed the test with no errors. I'm told by a friend that is was likely due to an upgrade in devise.
It seems to me that the problem you have is, just as the error says, there is no password column in your User table. You have to add it to your migration:
t.string :password
Note, however, that I have never used Devise so I may be wrong about this.
I think there are a couple of possibilities here but I will focus on the immediate problem. If your Rake tasks are returning No command found, then it may be because Rake isn't installed on your computer. I would start there.
To install Rake, type in your terminal:
gem install rake
The reason why your code doesn't work is because your users table doesn't have a column named password. With rake db:migrate and rake db:test:prepare you are ensuring that any migrations you created are applied to your database.
Let me know the results.

cant mass assign the protected attributes

iam working in rails 3.while trying to creating a user i am getting
cant mass assign the protected attributes error
I included following gems in the gemfile
gem 'authlogic'
gem 'gemcutter'
and run bundle install in rails console
then create a a user model and add the required authlogic columns to the migration.
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :login, :null => false
t.string :crypted_password, :null => false
t.string :password_salt, :null => false
t.string :persistence_token, :null => false
t.timestamps
end
end
end
and did rake db:migrate
Included authlogic in the user model.
# /app/models/user.rb
class User < ActiveRecord::Base
acts_as_authentic
end
while trying to create a user in rails console User.create(name: "pria",password: "priya123", password_confirmation: "priya123")
iam getting
cant mass assign the protected attributes :name, :password, :password_confirmation
How can i rectify this error!
In your User model:
attr_accessible :name, :password, :password_confirmation
You must add these attributes to the attr_accessible list in your model.
For important information about mass-assignment and its security implications: http://guides.rubyonrails.org/security.html#mass-assignment

Unique model field at databse level in Rails 3.1+ migration?

Is there a way to specify a database level uniqueness constraint on a field in a Rails 3.1+ migration? I know ActiveRecord's validates_uniqueness_of would work, but I'm curious to know if this can be specified elsewhere.
For example, in order to specify that the 'login' field should be unique in a migration such as ...
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.string :login
t.timestamps
end
end
end
... I'd like to add an option like :unique => true.
There's nothing mentioned in the Documentation so I assume that's not a great place/way to do things, but does anyone know how this might be achieved (even if it's manually added to the resulting schema)? Or is validates_uniqueness_of the preferred way to go?
You can add unique index so:
def change
create_table :users do |t|
t.string :name
t.string :login
t.timestamps
end
add_index :users, :login, :unique => true
end