Will renaming Rails migration files affect my live app? - ruby-on-rails-3

I edited to contents of some of my migration files to solve an issue between Paperclip and an Attachment model, renaming it to Upload.
01234_create_attachments.rb
class CreateAttachments < ActiveRecord::Migration
def change
create_table :attachments do |t|
t.string :name
t.string :attachment_url
t.timestamps
end
end
end
became this:
01234_create_attachments.rb
class CreateUploads < ActiveRecord::Migration
def change
create_table :uploads do |t|
t.string :name
t.string :upload_url
t.timestamps
end
end
end
Note that I only edited the file contents, not the file name.
The existing app runs fine but now I can't git clone the repo to a new server because rake db:migrate fails. If I then edit the actual migration filenames on the new server it runs properly:
01234_create_attachments.rb > 01234_create_uploads.rb
My question is if I rename the migration files in my master branch will it cause problems with my existing live app when I rake db:migrate in the future?

Your file name and class name of migration should match.
schema_migrations table is used to determine if the migration should run or not. Since that table only has timestamp, unless you change the timestamp, it wouldn't rerun the migration.
Its not advised to change existing migration after it has been run on production environment. Add a new migration if you have to change anything.

Related

Rails removing a column from activerecord not working

I want to remove container:references from my table, I have tried:
rails generate migration RemoveContainerfromCreateTasks container:references
followed by rails db:migrate, but it my reference field is still not removed.
Below is my ActiveRecord
class CreateTasks < ActiveRecord::Migration[6.1]
def change
create_table :tasks do |t|
t.string :title
t.text :body
t.references :container, null: false, foreign_key: true
t.text :tag
t.datetime :due
t.integer :priority
t.timestamps
end
end
end
class RemoveContainerfromCreateTasks < ActiveRecod::Migration[6.1]
def change
end
end
The issue here is really a sneaky capitalization error. Running:
rails generate migration RemoveContainerfromCreateTasks container:references
Will generate a migration with an empty change block which will do absolutely nothing when you migrate it except modify the migrations meta table (a table that AR uses to keep track of which migrations have been run). But if you properly capitalize From:
rails generate migration RemoveContainerFromCreateTasks container:references
It will generate:
class RemoveContainerFromCreateTasks < ActiveRecord::Migration[6.0]
def change
remove_reference :create_tasks, :container, null: false, foreign_key: true
end
end
Rails isn't actually intelligent. It just casts the name argument into snake case and compares it to a set of patterns like:
remove_something_from_tablename foo:string bar:integer
create_tablename foo:string bar:integer
create_foo_bar_join_table foo bar
And it then uses a template to generate the according type of migration. If you don't properly pluralize it will be cast into:
remove_containerfrom_create_tasks
Which Rails does not know what to do with as it does not match a known pattern.
Also note despite popular belief migrations are just a DSL to create SQL transformations which is completely unaware about your tables or models. In this case the resulting migration will just blow up when you attempt to run it since you don't have a create_tasks table.
I would roll the missnamed migration back. Delete it then run:
rails g migration RemoveContainerFromTasks container:references
rails db:migrate
Your issue here is that "CreateTasks" is not table in your database. "Tasks" is, however.
rails g migration RemoveContainerFromTasks container:references
will provide you
class RemoveContainerFromTasks < ActiveRecord::Migration[6.1]
def change
remove_reference :tasks, :container, null: false, foreign_key: true
end
end
A migration of this will successfully remove container from your schema.rb file, and subsequently the database system you're using.
Here's some console output, because why not:
unclecid#home:~/Desktop/sample_app$ rails db:migrate
== 20201227150512 CreateTasks: migrating ======================================
-- create_table(:tasks)
-> 0.0022s
== 20201227150512 CreateTasks: migrated (0.0023s) =============================
== 20201227151021 RemoveContainerFromTasks: migrating =========================
-- remove_reference(:tasks, :container, {:null=>false, :foreign_key=>true})
-> 0.0330s
== 20201227151021 RemoveContainerFromTasks: migrated (0.0331s) ================

Migration file updated not reflect in Schema.rb file

I am running a migration like this:
class CreatePages < ActiveRecord::Migration
def change
create_table :pages do |t|
t.string :name
t.string :permalink
t.integer :position
t.boolean :visible
t.timestamps
end
end
end
And then I figure I forgot to set the default value for the boolean, so I go back to the migration file and add the following:
t.boolean :visible, :default => false
I then run the rake db:migrate again. However, the schema.rb file does not update. I had run the migration before for quite awhile so it is not possible to rollback and redo the migration.
I know that I should not update the Schema file directly.
Anyone can help me to make the schema.rb file to update according to what I have change in the migration file.
Thank you
You have to add new migration to change default value for the column.
See this post

How do i make rails 3 model type cast according to migration?

The problem that i have is when i run my migrations the updates is applied to the database, but rails does not do the same.
To be more accurate. I have a address model with a house number. Recetly i was told that the house number should be able to contain letters, like (35B). Therefore i would like to convert the integer colum to a column of strings. This is no problem in any case with my data, red. only integers.
The migration that i applied works as expected. It changes the type of the column in the postgres database and preserves the data content. I was using this migration.
class ConvertIntToStringOnNumber < ActiveRecord::Migration
def change
change_table :addresses do |t|
t.change :number, :string
end
end
end
Migration result with this schema.rb
create_table "addresses", :force => true do |t|
t.string "street"
t.string "number"
t.integer "zip"
t.string "floor"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
After running the migration on my heroku server i am not able to query the database using data from the form, this was no problem before. Rails is trying to look for an integer, but the database is containing strings.
Rails is trying to run this query, even though the schema.rb says something different. This is where the party stops.
SELECT "addresses".* FROM "addresses" WHERE "addresses"."street" = 'xxxx' AND "addresses"."number" = 63 AND "addresses"."floor" = '' AND "addresses"."zip" = 9000 LIMIT 1):
I have seen a lot of problems with forigen keys, but this is NOT one of those problems.
Did you restart your application after running the migration?
ActiveRecord loads information about your tables into each class when they are instantiated. See #columns for more info. Since Heroku runs your app in production mode, your classes won't be automatically reloaded on each request.
Try running heroku restart on your application - Rails should pick up the changes then.

database migration in rails3.1

Recently I got a question about rails3.1's migration.Here is the one of the migration file code.
def change
create_table :books do |t|
t.string :title
t.decimal :price
end
end
Now I need to add a foreign key, let's say comment_id, I used to create another migration and use add_column method in it to get it done.
But since we are in rail3.1,so I thought there might be a new way to do it.so I alter the code
def change
create_table :books do |t|
t.string :title
t.decimal :price
t.references :comment
end
end
OK,now I run rake db:migrate and nothing happens. Any idea?
did you run rake db:rollback before running rake db:migrate? You need to roll back the migration before reapplying it with the changes.

Adding a column to an existing table in a Rails migration

I have a Users model which needs an :email column (I forgot to add that column during the initial scaffold).
I opened the migration file and added t.string :email, did rake db:migrate, and got a NoMethodError. Then I added the line
add_column :users, :email, :string
again rake db:migrate, again NoMethodError. Am I missing a step here?
Edit: here's the migration file.
class CreateUsers < ActiveRecord::Migration
def self.up
add_column :users, :email, :string
create_table :users do |t|
t.string :username
t.string :email
t.string :crypted_password
t.string :password_salt
t.string :persistence_token
t.timestamps
end
end
def self.down
drop_table :users
end
end
If you have already run your original migration (before editing it), then you need to generate a new migration (rails generate migration add_email_to_users email:string will do the trick).
It will create a migration file containing line:
add_column :users, email, string
Then do a rake db:migrate and it'll run the new migration, creating the new column.
If you have not yet run the original migration you can just edit it, like you're trying to do. Your migration code is almost perfect: you just need to remove the add_column line completely (that code is trying to add a column to a table, before the table has been created, and your table creation code has already been updated to include a t.string :email anyway).
Use this command on the terminal:
rails generate migration add_fieldname_to_tablename fieldname:string
and
rake db:migrate
to run this migration
Sometimes rails generate migration add_email_to_users email:string produces a migration like this
class AddEmailToUsers < ActiveRecord::Migration[5.0]
def change
end
end
In that case you have to manually an add_column to change:
class AddEmailToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :email, :string
end
end
And then run rake db:migrate
You can also do
rake db:rollback
if you have not added any data to the tables.Then edit the migration file by adding the email column to it and then call
rake db:migrate
This will work if you have rails 3.1 onwards installed in your system.
Much simpler way of doing it is change let the change in migration file be as it is.
use
$rake db:migrate:redo
This will roll back the last migration and migrate it again.
To add a column I just had to follow these steps :
rails generate migration add_fieldname_to_tablename fieldname:string
Alternative
rails generate migration addFieldnameToTablename
Once the migration is generated, then edit the migration and define all the attributes you want that column added to have.
Note: Table names in Rails are always plural (to match DB conventions). Example using one of the steps mentioned previously-
rails generate migration addEmailToUsers
rake db:migrate
Or
You can change the schema in from db/schema.rb, Add the columns you want in the SQL query.
Run this command: rake db:schema:load
Warning/Note
Bear in mind that, running rake db:schema:load automatically wipes all data in your tables.
You can also add column to a specific position using before column or after column like:
rails generate migration add_dob_to_customer dob:date
The migration file will generate the following code except after: :email. you need to add after: :email or before: :email
class AddDobToCustomer < ActiveRecord::Migration[5.2]
def change
add_column :customers, :dob, :date, after: :email
end
end
You also can use special change_table method in the migration for adding new columns:
change_table(:users) do |t|
t.column :email, :string
end
When I've done this, rather than fiddling the original migration, I create a new one with just the add column in the up section and a drop column in the down section.
You can change the original and rerun it if you migrate down between, but in this case I think that's made a migration that won't work properly.
As currently posted, you're adding the column and then creating the table.
If you change the order it might work. Or, as you're modifying an existing migration, just add it to the create table instead of doing a separate add column.
You can also do this ..
rails g migration add_column_to_users email:string
then rake db:migrate
also add :email attribute in your user controller ;
for more detail check out http://guides.rubyonrails.org/active_record_migrations.html
You can also force to table columns in table using force: true, if you table is already exist.
example:
ActiveRecord::Schema.define(version: 20080906171750) do
create_table "authors", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
end
You could rollback the last migration by
rake db:rollback STEP=1
or rollback this specific migration by
rake db:migrate:down VERSION=<YYYYMMDDHHMMSS>
and edit the file, then run rake db:mirgate again.