I am newbie with rails and here is my problem.
I created a very simple rails program and in the db > migrate > 2023.._add_columns_to_user.rb file, I added this code to this file
class AddColumnsToUser < ActiveRecord::Migration[7.0]
def change
add_column :users, :full_name, :string
add_column :users, :from, :string
add_column :users, :about, :text
add_column :users, :language, :string
add_column :users, :status, :boolean
add_column :users, :status, :boolean, default: false
end
end
Then I ran this code
rails db:migrate
But it gave me this error
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
PG::UndefinedTable: ERROR: relation "users" does not exist
May be I must create the database first?
Could you please give me some advices for this problem?
Here is all of my code, if you need for reference.
https://github.com/nguyencuc2586/Addcustomfieldsoutusermodel
Thank you in advance.
You can't alter a table that hasn't yet been created. Your migration should be wrapped in a table defintion:
class CreateUsers < ActiveRecord::Migration[7.0]
def change
create_table :users do |t|
t.string :full_name # shorthand for add_column :users, :full_name, :string
t.string :from
t.text :about
t.boolean :status, default: false # why on earth is this a boolean?
t.timestamps
end
end
end
This results in CREATE TABLE users (...) while your migration would result in ALTER TABLE users (...).
Related
For example, I have a migration file for posts:
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.text :text
t.integer :ip
t.timestamps
end
end
end
And want to change it to:
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.text :text
t.integer :ip, :limit => 8
t.timestamps
end
end
end
Would I add a line:
change_column :posts, :ip, :limit => 8
Below so that the file is:
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.text :text
t.integer :ip, :limit => 8
t.timestamps
change_column :posts, :ip, :limit => 8
end
end
end
And then run heroku run rake --trace db:migrate
I'm having trouble understanding how migrations work, and especially to production, so any help would be greatly appreciated.
There is http://guides.rubyonrails.org/active_record_migrations.html#changing-columns a section 3.5 on column modifiers but it doesn't specify how to pass them.
Thanks!
You should create a separate migration for adding the limit on the ip column.
Generate your migration:
rails generate migration ChangeIpLimitOnPosts
Inside the generated migration file, update the contents:
class ChangeIpLimitOnPosts < ActiveRecord::Migration
def up
change_column :posts, :ip, :integer, limit: 8
end
def down
change_column :posts, :ip, :integer
end
end
Take note here: you need to specify the column type when changing the column, even though in your case, you're not changing the type.
Also, in this case, Active Record will not know how to reverse the transaction if you need to rollback, so you need to explicitly tell Active Record how to do that — this can be done using the up and down methods, rather than change.
Run your migration:
rake db:migrate
On Heroku:
heroku run rake db:migrate
Hope that helps.
I have a devise Users Model
class DeviseCreateUsers < ActiveRecord::Migration
def change
...
end
end
I want to add these columns to the model. I think I might be confusing myself with the automatic pluralize that Rails does.
When I use the command rails g migration AddDetailsToUsers and I added following code inside the change method.
class AddDetailsToUsers < ActiveRecord::Migration
def change
add_column :Users, :username, :string
add_column :Users, :firstname, :string
add_column :Users, :lastname, :string
add_column :Users, :billing_address, :string
add_column :Users, :credit_card, :string
add_column :Users, :total_earned, :string
add_column :Users, :home_address, :string
add_column :Users, :leeway_time, :string
end
ends
I did rake db:migrate to try to update the DB, I get
== 20141012065730 AddDetailsToUsers: migrating ================================
-- add_column(:Users, :username, :string)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
PG::UndefinedTable: ERROR: relation "Users" does not exist
I try to see if I can play with this table in `rails c
User.first
User Load (0.9ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1
=> nil
Table name is case sensitive. Change all occurrences of :Users to :users in the migration file
eg:
add_column :users, :username, :string
add_column :users, :firstname, :string
..
I have a model created called "users" and i created a new migration to add some columns to the users table. Now when i run rake db:migrate, I get the error below b/c it's trying to create the users table again
$ rake db:migrate
== DeviseCreateUsers: migrating ==============================================
-- create_table(:users)
rake aborted!
An error has occurred, all later migrations canceled:
Mysql::Error: Table 'users' already exists: CREATE TABLE `users`.....
Why is it trying to create the table again?
Here's the command i used to create the new migration
$ rails generate migration AddDetailsToUsers home_phone:decimal cell_phone:decimal work_phone:decimal birthday:date home_address:text work_address:text position:string company:string
The new migration looks like this:
class AddDetailsToUsers < ActiveRecord::Migration
def change
add_column :users, :home_phone, :decimal
add_column :users, :cell_phone, :decimal
add_column :users, :work_phone, :decimal
add_column :users, :birthday, :date
add_column :users, :home_address, :text
add_column :users, :work_address, :text
add_column :users, :position, :string
add_column :users, :company, :string
end
end
EDIT
20120511224920_devise_create_users
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :email, :null => false, :default => ""
t.string :username, :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
## Encryptable
# t.string :password_salt
## 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
# add_index :users, :confirmation_token, :unique => true
# add_index :users, :unlock_token, :unique => true
# add_index :users, :authentication_token, :unique => true
end
end
20120619023856_add_name_to_users
class AddNameToUsers < ActiveRecord::Migration
def change
add_column :users, :first_name, :string
add_column :users, :last_name, :string
end
end
20121031174720_add_details_to_users.rb
class AddDetailsToUsers < ActiveRecord::Migration
def change
add_column :users, :home_phone, :decimal
add_column :users, :cell_phone, :decimal
add_column :users, :work_phone, :decimal
add_column :users, :birthday, :date
add_column :users, :home_address, :text
add_column :users, :work_address, :text
add_column :users, :position, :string
add_column :users, :company, :string
end
end
Rails keeps track of the migrations in the "schema_migrations" table of your database. Unless there is an entry for "20120511224920", which is the Devise migration, it will attempt to run it again, which it appears to already exists.
You can add that manually to the table if that is the case.
The error is saying that it's trying to run the original DeviseCreateUsers migration again and can't because the users table already exists.
To fix this, you can run the down migration for DeviseCreateUsers and then run migrations as normal. You can do that with:
rake db:migrate:down VERSION=20121031XXXXXXXX
rake db:migrate
Where 20121031XXXXXXXX is the date stamp of the migration name. In other words, you'll have a migration named 20120410214815_devise_create_users.rb and you copy the date stamp from the filename and paste it into the command. Here's the Rails Guide on Migrations for reference.
Edit: This is noted in the comments, but just a word of warning. Running the down migration for a table will lose any entries that table has. I assume you're running in development mode, so this shouldn't be a problem. If you're in production, you will need to take extra steps to backup the table data and reload it afterwards, otherwise you're going to have a bad day (or week maybe).
Can you try make a fresh database and then migrate it again:
rake db:drop:all
rake db:create:all
rake db:migrate
So from what I have gathered from this:
You already had a User model
You have a version of this in production
You ran a default rails generate devise:install
You then ran rails generate devise User
I am hoping that:
You use source control
You check code in a lot
NOTE: If not, you are about to learn why you need to do so.
Revert your code to before you generated Devise
Hopefully, you can just create a new sandbox of a point right before generating Devise. If not, copy your project directory and do it by hand. The only other option is manually edit all the files that Devise generated.
Rerun your Devise generation
readd gem 'devise' to your Gemfile
rails generate devise:install
rails generate devise MODEL
Make sure that model does not exist! If you don't you get into the problem you are currently having.
Migrate current users from one model to the other
If you can generate a script to completely move authentication information from your old user model to the new, good for you. If you are using a different hashing algorithm from Devise for your current authentication, then you are going to either invalidate all of their passwords and require your users to create a new password using a confirmation code in their email OR you could migrate users as they log in. The first method is clean, complete, and rude. The second method is ugly, incomplete, and silent. Choose your method however you like.
Edit: You could probably find a way to customize Devise to use your algorithm instead. That would probably be even better, but a little more work and fairly brittle.
Another thing is that your authentication model should not be overloaded with account data. You should have a model that only handles authentication which has_a account data model that stores whatever you might want to track about accounts.
use up and down methods. It will be useful for rollback and running specific migration file.
Please follow the syntax..
class AddDetailsToUsers < ActiveRecord::Migration
def self.up
add_column :users, :home_phone, :decimal
add_column :users, :cell_phone, :decimal
add_column :users, :work_phone, :decimal
add_column :users, :birthday, :date
add_column :users, :home_address, :text
add_column :users, :work_address, :text
add_column :users, :position, :string
add_column :users, :company, :string
end
def self.down
remove_column :users, :home_phone
remove_column :users, :cell_phone
remove_column :users, :work_phone
remove_column :users, :birthday
remove_column :users, :home_address
remove_column :users, :work_address
remove_column :users, :position
remove_column :users, :company
end
end
In this case please try to migrate using version number.
Like rake db:migrate:down VERSION=version number #version number is which version you wants to migrate.
I guess you ran rails generate devise user sometime which generated DeviseCreateUsers. If you have already created User model and users table, you can delete the generated migration file from db/migrate.
Check for some environmental variables that might be supplying an unexpected value for the version of your migration. I found an old question on Stack Overflow (and forgive me if it is way out of date) where db:migrate was destroying the table, instead of applying an existing new migration.
They eventually found that an environmental variable was causing db:migrate to run with a version parameter of "0" which is functionally equivalent to rake db:migrate:down
Is it possible that your situation could be caused by the version being unexpectedly changed to include or match the previous migration DeviseCreateUsers?
just try
in the first file
create_table(:users), :force => true do |t|
this will override any other table
According to what you said you used this command to create a new migration
$ rails generate migration AddDetailsToUsers home_phone:decimal cell_phone:decimal work_phone:decimal birthday:date home_address:text work_address:text position:string company:string
Im not sure if its just a typo but it should be "AddDetailsToUser" and not "Users". Just check again and we will be able to help you. This is for devise generated model. When you mention User, in db it looks for Users.
Ruby on Rails follow linguistic convention.table_name is Plural but model_name is Singular. You have to use model_name in the command you used.
If you want to use table_name then use this
rails g migration add_details_to_users home_phone:decimal......etc
And if you need to do some dirty migrations manually:
class A < ActiveRecord::Migration
def up
add_column :images, :name
end
end
A.new.migrate(:up)
I'm in the process of adding Devise to an existing Rails app, with a Users table already defined. The devise generator pushed out the following migration:
class AddDeviseToUsers < ActiveRecord::Migration
def self.up
change_table(:users) do |t|
## 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
blah blah blah....
end
add_index :users, :email, :unique => true
add_index :users, :reset_password_token, :unique => true
end
The downward migration isn't generated, and I'm having a heck of a time removing those indexes. I'm seeing different suggested notation in the documentation, and different suggestions online, but none of them seem to be working for me. For example...
def self.down
change_table(:users) do |t|
t.remove :email
t.remove :encrypted_password
t.remove :reset_password_token
blah blah blah...
end
remove_index :users, :email
remove_index :users, :reset_password_token
end
results in...
An error has occurred, this and all later migrations canceled:
Index name 'index_users_on_email' on table 'users' does not exist
which is odd, because if I check the database, sure enough, 'index_users_on_email' is right there...
I've tried other variations, including
remove_index :users, :column => :email
remove_index :users, 'email'
or:
change_table(:users) do |t|
t.remove_index :email
end
...but no dice. I'm running Rails 3.1.0, Ruby 1.9.2, rake 0.9.2.2, with Postgres.
The command that's letting me down is:
bundle exec rake db:rollback STEP=1
after successfully apply the migration up. Any advice?
For the record, the way to remove an index by name is
remove_index(:table_name, :name => 'index_name')
so in your case
remove_index(:users, :name => 'index_users_on_email')
You can also remove the index specifying the columns, which from my point of view is less error prone than writing the name
remove_index :actions, :column => [:user_id, :action_name]
Depending on the database type, you don't need to worry about removing the indexes in the self.down method since the index will automatically be removed from the database when you drop the column.
You can also use this syntax in your self.down method:
def self.down
remove_column :users, :email
remove_column :users, :encrypted_password
remove_column :users, :reset_password_token
end
I'd like to expand on #iWasRobbed's answer. If you have index on just single column then worrying about remove_index doesn't make sense since (just an assumtion!) the DB should be smart enough to cleanup the resources used by that index. But in case you have multiple columns index removing the column will reduce index to still existing columns, which is totally sensible thing to do, but kind of shows where you might want to use remove_index explicitely.
Just for illustration - migration below has that flaw that after being applied up and down it will leave the unique index on email (meaning the down part is not doing its job properly)
class AddIndexes < ActiveRecord::Migration
def up
add_column :users, :action_name, :string
add_index :users, [:email, :action_name], unique: true
end
def down
remove_column :users, :action_name
end
end
Changing the down block to
def down
remove_index :users, [:email, :action_name]
remove_column :users, :action_name
end
will fix that flaw and allow the migration to correctly return DB to the previous state with rake db:rollback
To alter a table and/or its indeces use #change_table inside #change action of a migration. Then you be able to create reversable index removal as follows:
def change
change_table :users do |t|
t.index :email, :unique => true
t.index :reset_password_token, :unique => true
end
end
When you have to drop a table with its index of course with reversable action you can use #drop_table method for SchemaStatements with the #index method of Table class for ConnectionAdapter:
def change
drop_table :users do |t|
t.index :email, :unique => true
t.index :reset_password_token, :unique => true
end
end
In case you have need exactly the #up/down pair in a migration. Use just a #change_table method along with #remove_index method of Table class for ConnectionAdapter:
def up
change_table :users do |t|
t.index :email, :unique => true
t.index :reset_password_token, :unique => true
end
end
def down
change_table :users do |t|
t.remove_index :email, :unique => true
t.remove_index :reset_password_token, :unique => true
end
end
All of the methods are available in Rails version of 2.1.0 or of earlier ones.
Here is my full run of this(in Rails 5):
I have team_id as an index in table vendors. I no longer need this relation. To get rid of it. Did the following:
1) create the migration.
$ rails generate migration RemoveTeam_idFromVendor team_id:integer
2) Running the migration, give me this error. And that is because vendor table has rows whose foreign key references the primary key value of the team table
== 20170727202815 RemoveTeamIdFromVendor: migrating ===========================
-- remove_column(:vendors, :team_id, :integer)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
SQLite3::ConstraintException: FOREIGN KEY constraint failed: DROP TABLE "vendors"
3) To solve this and get the migration running, I did the following(Note: i am in dev):
$ rake db:drop
Dropped database 'db/development.sqlite3'
Dropped database 'db/test.sqlite3'
$ rake db:create
Created database 'db/development.sqlite3'
Created database 'db/test.sqlite3'
$ rake db:migrate
~
~
~
== 20170727202815 RemoveTeamIdFromVendor: migrating ===========================
-- remove_column(:vendors, :team_id, :integer)
-> 0.0185s
== 20170727202815 RemoveTeamIdFromVendor: migrated (0.0185s) ==================
I created a model ruby script/generate model Article (simple enuff)
Here is the migration file create_articles.rb:
def self.up
create_table :articles do |t|
t.column :user_id, :integer
t.column :title, :string
t.column :synopsis, :text, :limit => 1000
t.column :body, :text, :limit => 20000
t.column :published, :boolean, :default => false
t.column :created_at, :datetime
t.column :updated_at, :datetime
t.column :published_at, :datetime
t.column :category_id, :integer
end
def self.down
drop_table :articles
end
end
When I run the rake:db migrate command I receive an error rake aborted! "Uninitialized constant CreateArticles."
Does anyone know why this error keeps happening?
Be sure that your file name and class name say the same thing(except the class name is camel cased).The contents of your migration file should look something like this, simplified them a bit too:
#20090106022023_create_articles.rb
class CreateArticles < ActiveRecord::Migration
def self.up
create_table :articles do |t|
t.belongs_to :user, :category
t.string :title
t.text :synopsis, :limit => 1000
t.text :body, :limit => 20000
t.boolean :published, :default => false
t.datetime :published_at
t.timestamps
end
end
def self.down
drop_table :articles
end
end
It's possible to get the given error if your class names don't match inflections (like acronyms) from config/initializers/inflections.rb.
For example, if your inflections include:
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym 'DOG'
end
then you might need to make sure the class in your migration is:
class CreateDOGHouses < ActiveRecord::Migration[5.0]
rather than:
class CreateDogHouses < ActiveRecord::Migration[5.0]
Not super common, but if you generate a migration or a model or something, and then add part of it to inflections afterwards it may happen. (The example here will cause NameError: uninitialized constant CreateDOGHouses if your class name is CreateDogHouses, at least with Rails 5.)
If you're getting this error and it's NOT because of the migration file name, there is another possible solution. Open the class directly in the migration like this:
class SomeClass < ActiveRecord::Base; end
It should now be possible to use SomeClass within the migration.
The top answer solved for me. Just leaving this here in case it helps.
Example
If your migration file is called
20210213040840_add_first_initial_only_to_users.rb
then the class name in your migration file should be
AddFirstInitialOnlyToUsers
Note: if the class name doesn't match, it will error even if the difference is just a lower case t instead of an upper case 'T' in 'To' - so be careful of that!