I'm working on a web app that basically interacts with a db table through a form. Recently I had to make some changes which resulted in me adding another column to the db table. I'm using RubyMine for developing and can't figure out how to update the model so that it contains the new column. I've added it inside the model as so:
class Student < ActiveRecord::Base
attr_accessible :f_name, :floor_pref, :l_name, :is_active
validates_presence_of :f_name, :floor_pref, :l_name
end
I've also added it inside the schema.rb:
ActiveRecord::Schema.define(:version => 20130620140537) do
create_table "students", :force => true do |t|
t.string "f_name"
t.string "l_name"
t.string "floor_pref"
t.boolean "is_active"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
end
And also inside the migrate as so:
class CreateStudents < ActiveRecord::Migration
def change
create_table :students do |t|
t.string :f_name
t.string :l_name
t.string :floor_pref
t.boolean :is_active
t.timestamps
end
end
end
Problem is when I run the rails console and look up my model object it doesn't show the new column that I have added (:is_active). It only shows the old columns:
>> Student
Loading development environment (Rails 3.2.13)
Switch to inspect mode.
Student(id: integer, f_name: string, l_name: string, floor_pref: string, created_at: datetime, updated_at: datetime)
What am I missing?
What you should do know, is to delete all changes you have added to model app/models/Student.rb and to db/schema.rb
Then you should go to your terminal/console and type
$ rails g migration add_column_name_to_student column_name:type
This command will create new file in db/migrate/ folder.
$ rake db:migrate
After updating your database schema with rake db:migrate. Go to your app/models/Student.rb and add new column_name into attr_accessible, if you want to setup this value by form.
This whole procedure has nothing to do with your IDE.
Here are some other resources, where you can get information how to add new column to models.
Generate Rails Migrations That Automagically Add Your Change
Rails 3: How to add a new field to an existing database table
You should definitely avoid adding new columns the way you did that. It's messy and makes your code difficult to maintain.
This is not the correct way to add a new column to your table. You want to open your console and run the following command your after is rails g migration add_column_name_to_table column_name:type then run a bundle exec rake rake db:migrate. Its not good to just shove things in.
Ex: If I want to add the postedon column to posts table, then:
rails g migration AddPostedOnToPosts posted_on:date
This will add column in your migration file automatically.
Related
In my Rails 5 application I've accidentally created a column with no data type. Database is SQLite.
create_table "students", force: :cascade do |t|
t.integer "club_id"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "picture"
t.integer "payment_plan_id"
t. "activity"
t.index ["club_id"], name: "index_students_on_club_id"
end
When I attempt rails db:rollback I get this error:
Rhys-MacBook-Pro:classmaster Rhys$ rails db:rollback == 20161011105423 AddActivitiesRefToStudents: reverting =======================
-- remove_column(:students, :activity, :reference)
rails aborted! StandardError: An error has occurred, this and all later migrations canceled: undefined method `to_sym' for nil:NilClass
I've tried running this migration:
class RemoveColumn < ActiveRecord::Migration
def up
execute "ALTER TABLE students DROP COLUMN activity";
end
end
But I think SQLite doesn't support dropping columns. Is there a fix for this?
I am assuming it is the activity column you want to drop based on it not having a type in that file, if it is a different column then just change the column name below.
What you want to do is drop a column from the table, which you absolutely can do. In the command line do something like the line below (or exactly like the line below) to create the migration to drop the column.
rails g migration drop_activity_column_from_students
Then open that file, the method inside should be this.
def change
remove_column :students, :activity
end
Then run
rake db:migrate
and you should see that one column get dropped from the table.
You can find a ton of information here about migrations, if that is something you want to learn more about.
I had the same problem, and after trying various migrations and running rails db:reset without success, I just deleted my schema.rb file and ran rails db:migrate, which rebuilt my schema from scratch without the column that didn't have a data type. Just make sure that none of your migrations contain the addition of the "activity" column, so you don't repeat the problem.
Try to change the type of the column by:
rails g migration FixActivityTypeStudents
Then on the migration add this part.
def change
change_column :students, : activity, :string
end
I was only able to discouver this problem by slowly walking through running my migrations. For the last two days I've been trying to do somthing simple. Remove one column verdict:text from my simulations table and add another column: opinions:hash.
Doing this caused a variety of errors, such as no method 'my_sym' and saying the simulation table didn't exist.
I initially thought I had resolved this by doing:
rake db:drop
rake db:schema:dump
rake db:migrate VERSION="<Migration1>"
rake db:migrate VERSION="<Migration2>"
rake db:setup ENV="test"
Migration 1:
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :email, :null => false, :default => "", limit: 96
t.string :encrypted_password, :null => false, :default => "", limit: 60
t.timestamps
t.index :email, unique: true
end
end
end
Migration 2:
class CreateSimulations < ActiveRecord::Migration
def change
# Needs the hash column worked out before this is run
create_table :simulations do |t|
t.integer :x_size
t.integer :y_size
t.string :verdict
t.string :arrangement
end
add_reference :simulations, :user, index: true
end
end
This got me back to square one (all my tests worked everything seemed to be in my initial state I had before started having problems), so I re-wrote the two offending migrations thinking they might be the problem, ran the two migrations in this order (I removed the column then added the other one, the opposite order of what I tried previous, thinking maybe the order had some effect).
Migration 3:
class RemoveVerdictFromSimulation < ActiveRecord::Migration
def change
remove_column :simulations, :verdict, :string
end
end
Migrations 4:
class AddOpinionToSimulations < ActiveRecord::Migration
def change
add_column :simulations, :opinion, :hash
end
end
Edit: With further investigation it is this 4th migration that is causing the problem of dropping the simulations table without error.
Both these migrations worked without error. However I know doing anything else will cause an error (example running rspec), because it looks like the problem is that one of these migration causes an error with the schema.rb file.
After running these last migrations 3&4 my schema.rb which previously had both users and simulations tables now looks like this:
ActiveRecord::Schema.define(version: 20150807193122) do
# Could not dump table "simulations" because of following NoMethodError
# undefined method `[]' for nil:NilClass
create_table "users", force: :cascade do |t|
t.string "email", limit: 96, default: "", null: false
t.string "encrypted_password", limit: 60, default: "", null: false
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
end
The particular line of interest here being:
# Could not dump table "simulations" because of following NoMethodError
# undefined method `[]' for nil:NilClass
Can anyone shed some light on whats happening here or how I can fix it? I've been stuck on this for hours.
One thing maybe worth noting, when I re-run the rake db:schema:dump I need too comment out my factories for some reason, as they seem to cause errors with simulation table existing. Not sure why they're being called just thought this info might help, here they both are:
FactoryGirl.define do
factory :simulation do |f|
f.id (Simulation.last.nil? ? 1 : Simulation.last.id + 1)
f.x_size 3
f.y_size 3
f.user_id 1
end
end
--
FactoryGirl.define do
factory :user do
email "user_#{User.last.nil? ? 1 : User.last.id + 1}#home.com"
password "password"
end
end
I think the problem is right here:
class AddOpinionToSimulations < ActiveRecord::Migration
def change
add_column :simulations, :opinion, :hash
end
end
There's no such thing as hash column type. SQLite will, unfortunately, let you create columns with any type you want (with unrecognized things being treated as strings) but ActiveRecord won't know what to do with them. The result is that your migration works but the schema dump fails because ActiveRecord can't say:
t.hash :opinion
in the schema.rb file.
If you really think you want to store a Hash in a column, you'd create a text column:
add_column :simulations, :opinion, :text
and then use serialize in your model:
serialize :opinion, Hash
Of course that leaves you with an opaque blob of YAML in your database that you won't be able to (sanely) query so it should only be used if you are okay with that.
A better solution would be to normalize your opinion Hashes so that you could store their information in separate tables/models.
I'm running into a LOT of problems just trying to do basic model generations and migrations in Rails 4 with Postgres. I have the pg gem installed, version 0.17.1.
In the beginning, I couldn't even run migrations without errors, because the schema_migrations table was created with the version column having a dimension of 1. Once I manually changed it to zero, it worked fine.
Now, if I look at all of the migrations that resulted from me using the Rails model generator, I see that every single column, with the exception of the id column in each table, was created with dimension of 1.
Is there some default setting I need to change? Is this somehow correct and I am messing up something else? This is my first Rails 4 project, so I'm just trying to figure out why it would want all of those columns to default to an Array.
Here is one of my migration files:
class CreateCatalogs < ActiveRecord::Migration
def change
create_table :catalogs do |t|
t.string :name
t.text :description
t.string :schema_name
t.string :catalog_type
t.boolean :billable
t.timestamps
end
end
end
And this is from schema.rb:
create_table "catalogs", force: true do |t|
t.string "name", array: true
t.text "description", array: true
t.string "schema_name", array: true
t.string "catalog_type", array: true
t.boolean "billable", array: true
t.datetime "created_at", array: true
t.datetime "updated_at", array: true
end
What in the heck!
As luck would have it, Ruby on Rails v4.0.3 was released today. I did the following:
Upgrade Rails
deleted db/migrate/schema.rb
Delete all 3 databases (dev, test, production)
ran rake db:setup
ran rake db:migrate
Looked at the new db/migrate/schema.rb to make sure it was OK
ran rake db:test:prepare
Sure enough, the problem is fixed in this new release. I couldn't find a record of the problem anywhere! It's been an issue for a few weeks. Anyway, fixed!
It may be your migration that specifies each column to be array
I created a new scaffold using the command:
rails generate scaffold level
But then I destroyed it using the command
rails destroy scaffold level
And then again added it back using the command
rails generate scaffold level question:string answer:string prev_q:integer next_q:integer
But now when I try rake db:migrate then I get the following error
SQLite3::SQLException: table "levels" already exists: CREATE TABLE "levels" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "question" varchar(255), "answer" varchar(255), "prev_q" integer, "next_q" integer, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL)
My migrate/create_level.rb is
class CreateLevels < ActiveRecord::Migration
def change
create_table :levels do |t|
t.string :question
t.string :answer
t.integer :prev_q
t.integer :next_q
t.timestamps
end
end
end
But my schema.rb is:
create_table "levels", :force => true do |t|
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
I want to know that how can I update the levels table in the schema. Also I would like to know that why doesn't the table get deleted when I destroy the scaffold. Do I need to run another command to do it?
Using destroy scaffold does not run the rollback to the migration. The correct way of doing it would have been
rake db:rollback
rails destroy scaffold level
now, as you don't have that other migration anymore, you cannot roll it back. You'll need to delete that table manually:
rails dbconsole
DROP TABLE levels;
What I had to do was:
First I followed the steps specified by #Alex Siri.
But after doing that using
rake db:migrate
Did not add the values question,answer etc to the table, so I did the following steps
I again deleted the scaffold using the command
rails destroy scaffold level
After that I again created the scaffold using the command:
rails generate scaffold level question:string answer:string prev_q:integer next_q:integer
Finally I ran migration using
rake db:migrate
This solved my problem. I wrote all the steps so that if anyone else has the same problem then they can easily solve it.
For Rails 3.2 I have written this migration to rename the column name as seen in the migration
class RenameKpiColumn < ActiveRecord::Migration
def change
rename_column(:key_performance_intervals, :kpi_id, :key_performance_interval_id)
end
end
And then I said bundle exec rails db:migrate
If I go to Schema.rb I see this for that table, so looks likes it picked the new column name from Migration:
create_table "key_performance_intervals", :force => true do |t|
t.integer "key_performance_interval_id"
t.integer "interval"
t.integer "interval_unit"
t.decimal "count"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
But if I open the pgAdmin tool and look at the tables and column names in there, it is still using the old column name of kip_id .
Is there any step I am missing?
Since migrating the database gives no output, it seems that the migrations ran fine. Just restart pAdmin and the changes should be reflected there.
To also prepare your test database, run
$ rake db:test:prepare