I dropped a table and want to create a new one - but I don't want to lose my other tables - ruby-on-rails

This is probably really simple/obvious but I am new to this -
I have a database with some tables, let's say tA, tB and tC. In a migration I dropped tC, because at that point I needed to working on a different branch. However, I'm now working on a branch in a project that needs tC to exist.
The migrations for creating all tables are present on this branch.
I don't care if tC is empty. But if I run rake db:create, will it then re-create all tables? Because I do not want to lose the data in the other tables, tA & tB.
TL;DR - How to create a table (which I dropped in an earlier creation) without also recreating (and losing the data of) the tables I did not drop?

How did you drop the table tC? Is it through console/command line? If yes, then to recreate the tC table, you have 2 choices:
Create a new migration file to only create table tC (optimal and easiest fix)
bundle exec rails g migration CreateTableTC
Then add the new migration with this conditional statement:
unless table_exists?(:table_tC)
create_table :table_tC do |t|
........
end
end
Then run this command on your terminal:
bundle exec rake db:migrate
This will create table tC if your database hasn't got one, will not erase data on other tables, and will not be executed if your database has table tC
Use GUI for your database (if you are using postgres, you may use PgAdmin)

Here's what I ended up doing: using the Rails console, I simply ran the migration that created that particular table in the first place again. See this Q&A: Run a single migration file.

Related

Remove Model and Table so can start again in Rails

I created a model for comments at the start of a project, but have now come to the realisation I need to create some polymorphic relations so I can use comments with a number of other models as well. Considering the the code I already have etc, I'm thinking it might be easier for me to just start again from scratch so I can build all the views/controllers etc in the correct way for my new polymorphic world.
I see that I can run rails destroy model comments to achieve this but I have two questions on that:
Will this delete the model, migrations AND the actual DB table?
What are the implications when I want to create a new model with the exact same name?
In order to completely remove all columns &
tables that migration has created you need to run:
rails db:migrate:down VERSION=012345678 (where 012345678 should be the version number of your migration)
.............................
rails destroy model Comments
will delete your Model, pending migration, tests and fixtures
So destroy it's the opposite of generate:
$ bin/rails destroy model Oops
invoke active_record
remove db/migrate/20120528062523_create_oops.rb
remove app/models/oops.rb
invoke test_unit
remove test/models/oops_test.rb
remove test/fixtures/oops.yml
And, you can now create a new Model with the same name, as there's no trace of your previous one :)
If you have already migrated the database after creating the model:
First, rollback the changes to the database:
rake db:migrate:down VERSION=20100905201547
where version is the timestamp identifying the migration. For example, if your migration file is called 20170411182948_create_comments.rb then your version parameter should be 20170411182948
Then run
rails destroy model comments
The first command will delete the table from the actual database. The second command will delete the model and the migration file. Make sure you run them in that order as the first command is dependent on the migration file to perform the rollback (which is deleted during the second command).
If you have have not migrated the database:
The table would not have been added to your database. You can go ahead and delete your model and migration files manually or use the destroy command.
You might need to remove the table thoroughly.
Run this :
sqlite3 db/development.sqlite3
Then :
sqlite> drop table table_name;
sqlite> .quit

How can I use SQL during migration in test database (to create a foreign key)?

I'm pretty new to rails (3.2.13) development and have not been able to find a way to do what I'm trying to do.
Background: I created a migration that, because there appears no other way to do this using sqlite, creates a new table in the database with a foreign key. Specifically, I ran:
rails g model period_type_specs period_type_id:integer start_date:datetime end_date:datetime user:references
I then wanted to ensure that the period_type_specs table had a foreign key constraint (period_type_id -> period_types(period_type_id)). After researching and trying a few things, the only thing I found that worked with sqlite was, in the CreatePeriodTypeSpecs migration file, replace what was there with pure SQL to create the table with the desired foreign key, using 'execute'. This worked - that is, after rake db:migrate, the new table, with the needed foreign key, was created in the development database.
Problem: I've so far found no "kosher" way to get the same table/schema into the test database. After the db:migrate, rake db:test:prepare creates the table, but with no foreign key. I believe this is because db:test:prepare simply uses db/schema.rb to create the missing table and schema.rb uses the standard "create_table..." operations and (I believe) raw SQL is not supported in schema.rb.
The only way I can think of at this point to create the table as I want in the test database is to simply run the sql commands, from the migration file, directly on the test database. But, of course, this would interfere with the goal of using rake to reset or remove and then automatically recreate the database schema.
So - is there a way to do what I want without cheating?
Update: I ended up putting the SQL statement to create the table with the foreign key into db/seeds.rb, which is also where the table it refers to (a static reference table) is populated.

How to keep overview of the migrations?

I have a question regarding my migrations in rails.
Normally when i want to add a colum to a model for i dont make extra migrations but instead i perform this steps:
rake db:rollback
next i change the migration file in db/migrations and rerune:
rake db:migrate
The biggest problem is that when i do this i loose my data.
Previous i wrote migrations from the command line with for example
rake g migration Add_Column_House_to_Users house:string
The problem with this approach is that my db/migrations folder afterwards get very large and not very clear! I mean at the end i dont know wich variables the object has! Im not an expert in rails and would like to ask you how to keep the overview over the migrations!Thanks
Just a minor thought - I just use the file db/migrate/schema.rb to determine whats in the database as opposed to tracking through the migrations
You definitely shouldn't use db:rollback with a table with existing data.
I have a few production RonR apps with a ton of data and there are 100+ entries in the migrations table and adding new migrations to tweak tables is the rails way to do things. Not sure what you mean by lucid, but your schema and data model are going to change over time and that is ok and expected.
One tip. The migrations are great, but they are just the beginning, you can include complex logic as needed to fix your existing data (like so)
Changing data in existing table:
def up
add_column :rsvps, :column_name_id, :integer
update_data
end
def update_data
rsvps = Rsvp.where("other_column is not null")
rsvps.each do |rsvp|
invite = Blah.find(rsvp.example_id)
...
rsvp.save
end
end
Another tip: backup your production database often (should do this anyway), but use it to test all of your migrations before deploying. I run scripts like this all the time for local testing:
mysql -u root -ppassword
drop database mydatabase_dev;
create database mydatabase_dev;
use mydatabase_dev;
source /var/www/bak/mydatabase_backup_2013-10-04-16.28.06.sql
exit
rake db:migrate

Remove a column which was added recently

There was a time when I had to a column "column" to a model. Now I have to remove it. Is there any sensible method to that except a simple one by adding a new migration?
Depending on how deep down the rabbit hole you are you can rollback then delete the migration.
rake db:rollback
rails destroy migration *name of migration*
This will run the down method of the migration undoing the column add. The second command destroys the migration resetting your schema file.
EDIT:
Turns out your rabbit hole is deep. Best thing to do is to make another migration removing the column.
You can of course run SQL directly on the database. The problem with not using a migration file to perform this "subtle change" is that if you ever have to move your application to another server, you won't be able to recreate the database: this "column" column will be there because it's removal was never documented.
Stick with migrations!

Ruby on Rails migration, change table to MyISAM

How does one create a Rails migration properly so that a table gets changed to MyISAM in MySQL? It is currently InnoDB. Running a raw execute statement will change the table, but it won't update db/schema.rb, so when the table is recreated in a testing environment, it goes back to InnoDB and my fulltext searches fail.
How do I go about changing/adding a migration so that the existing table gets modified to MyISAM and schema.rb gets updated so my db and respective test db get updated accordingly?
I didn't find a great way to do this. You could change your schema.rb like someone suggested and then run: rake db:schema:load, however, this will overwrite your data.
The way I did it was (assuming you are trying to convert a table called books):
Save the existing data from the CLI: CREATE TABLE tmp SELECT * FROM books;
In your new migration file, drop the books table and recreate it with :options => "ENGINE=MyISAM" like someone said in the comment
Copy the contents back: INSERT INTO books SELECT * FROM tmp
i think that if you change your schema format (config.active_record.schema_format) from :ruby to :sql, all sql will be saved there.
i'd do some tests on a fresh app first if i were you, see how it works.
You can run any sql in migrations. This worked for me:
class ChangeMapOnlyUsersEngine < ActiveRecord::Migration[5.1]
def change
MyModel.connection.execute("ALTER TABLE my_models ENGINE = 'MyISAM';")
end
end
When I did this in the other direction (InnoDB -> MyISAM) it worked fine, without loss of data so I don't think it's neccesary to create temporary tables or similar. Note that MyISAM doesn't support transactions, so any tests against the database for a corresponding ActiveRecord model will be persisted, with a risk of test pollution.

Resources