I am a Rails beginner and trying to understand how rails migration works.
I have created a scaffold like:
script/generate scaffold Item col1:string col2:text
rake db:migrate
I would like to add another col4 using migration:
I created a migration as follows:
class AddCol4 < ActiveRecord::Migration
def self.up
add_column :items, :col4, :numeric
Item.reset_column_information
end
def self.down
remove_column :items, :col4
end
end
When I run rake db:migrate the new column gets added. However the view is out of sync.
Am I supposed to manually add the new column to the view? Is there a way to auto-regenerate the model/view using the new table columns?
Sorry, it is a basic question but from my experience with other frameworks, it should have been automatic.
The rails guide on migration does not make this obvious regarding how the synchronization is supposed to work after you perform a migration.
Unfortunately you will need to modify the view manually. The view is created by running the script/generate scaffold command. Migrations only change the database. Technically, you can rerun the scaffold command and have it regenerate the view. It will ask you if you want to overwrite the previous file, however, if you go this route, you will still need to specify ALL of the columns that you want. You can't simply add some here and there.
If you are early in development, then you might take this route. Simply run
script/destroy scaffold Item
and then rerun
script generate scaffold Item col1:string col2 string col3:numeric
There are some dynamic scaffolding extensions available such as ActiveScaffold if you are creating something that only a few users will see, but I would recommend doing the HTML yourself as it will always come out the way you want.
I can't seem to find any of the other dynamic scaffolding plugins. There used to be quite a few...
Related
Among my migrations, I have 3 that pertain to this question. In order, there is CreateEvents < ActiveRecord::Migration. The next down the line is CreateYears < ActiveRecord::Migration. Then the last is AddYearIdToEvents < ActiveRecord::Migration. The last one looks like this...
class AddYearIdToEvents < ActiveRecord::Migration
def change
add_column :events, :year_id, :integer, null: false, index: true
end
end
Now the problem is, whenever I try to drop the entire database (not near deploying to production), I get an obvious error of
ERROR: cannot drop table years because other objects depend on it
DETAIL: constraint events_year_id_fk on table events depends on table seasons
HINT: Use DROP ... CASCADE to drop the dependent objects too.
Now, I'm not a rails expert, but I believe I need to define a def down in that last migration. Rather than def change, do I need a def up and def down? The def down to drop this particular column.
If so, how can I do this. This migration is 20 migrations old. You can't just edit a migration like that can you? Do I add a new migration and just specify a def down? Or is the answer something completely different?
Have you tried rolling back your migrations? This undoes your migrations in reverse order, i.e. starting with the most recent migration.
$ rake db:rollback
If you have 20 migrations and you'd like to rollback all of them, you can use STEP=20
$ rake db:rollback STEP=20
Once you rollback past a migration that you'd like to change, you can change it.
In addition, you should be able to use rake db:drop, which drops the entire database rather than going through each migration in reverse order. If you'd like to drop the database, then recreate it and re-run all the migrations, you can run rake db:reset. Keep in mind this also runs rake db:seed if you have a db/seed.rb file.
And in response to your question of "Rather than def change, do I need a def up and def down?", the answer is no. Newer versions of Rails use def change since (among other reasons) it makes it easier to edit migrations once they are generated, i.e. if you spell a column name incorrectly when adding a column to a table.
I'm new to rails...I made a scaffold "Reviews" but want to add another field "ratings", as an integer. I did the following:
added t.integer :ratings in the migration file..ran rake db:migrate
in spec folder: added it in views/app/ edit, index, new, show
in app/views/app added it in the json files
in app/controllers/app added it in the review_params function
still however whenever I try to reference (by showing a Review) it I get
undefined method `ratings' for #
There must be something else I need to add somewhere to have it be part of my Reviews scaffold. I've been trying to figure it out for 5 hours but still have not. When I try to remake a scaffold and run rake db:migrate I get an error saying that the databases already exist so I would like to just manually add it to my existing one if possible, I just can't seem to figure out how even though I've already done it once for a string.
Any help is appreciated thank you.
To add an integer field to a model you can do something like this.
rails generate migration AddRatingToReviews rating:integer
This should handle everything for you by generating a new migration file like so.
class AddRatingsToReviews < ActiveRecord::Migration
def change
add_column :reviews, :rating
end
end
Then you can run rake db:migrate to add the column to your review model.
NOTE: Before doing all of this, please delete all your manual changes. If necessary use rake db:rollback which will rollback your most recent rake db:migrate.
Recommendation
If you are new to rails and don't understand MVC, I suggest not using scaffolding because you'll have a tough time knowing what it is doing. Go through this awesome tutorial by Michael Hartl to really learn rails quickly. http://ruby.railstutorial.org/
*Awesome gem *
Use the annotate gem to display the attributes contained within your model directly in your name_of_model.rb files.
https://github.com/ctran/annotate_models
rails generate migration AddRatingsToReviews ratings:integer
Then
rake db:migrate
If you have not done any major changes in your generated scaffold.
Simplest way to get the ratings across views would be as below:
Rollback the changes that you have migrated
rake db:rollback VERSION=version_number
Where replace version_number with the version_number prefixed on your migration file.
For eg: If your migration filename is 20140314190622_create_reviews.rb then command should be
rake db:rollback VERSION=20140314190622
Destroy the scaffold of Review
rails d scaffold Review
After this generate the scaffold again with the integer field
rails g scaffold Review ratings:integer .... ## Add other field in place of ....
I am pretty new to Ruby on Rails, and I was wondering if there was a way to edit the database schema for a model.
For example, I have the Subscriber model in my application -- the way I created it was by using rails generate scaffold Subscriber email:string
But now, I want a name in the subscriber model as well. Is there any easy way to do this? I have put a lot of code in my current controllers and views, so I don't necessarily want to destroy the scaffold, but I would like to edit the model.
Thanks in advance,
hwrd
P.S. I am using Ruby on Rails 3
An ActiveRecord Model inspects the table it represents. You don't actually need to change your model just to add a new field (unless you want to add validations, etc).
What you want to do is make a new migration and then migrate your database up:
rails g migration AddNameToSubscribers name:string
rake db:migrate
Then you can start referencing the name field in your controllers and views.
(This generator command might seem a little magical, but the rails generator recognizes this format and will generate the appropriate add_column and remove_column code. See the Rails migration guide for further reading.)
If you mean changing the database schema of your model, you'll want to use migrations.
You'll do things like
add_column :city, :string
remove_column :boo
http://guides.rubyonrails.org/migrations.html
If you do only mean finding models and updating the data inside each instance, go with #apneadiving's answer.
Let's say I used the following command to create a "User" model:
script/generate model User username:string
This creates the user.rb file along with the migration rb file to create the Users table. Now, I want to add an email column to my User model. What's the best way to do that? Do I do it manually and write the migration file by hand or is there a shortcut for doing it? If I write the migration by hand, do I have to name it the same way as the previous migration script (with a timestamp in front) to guarantee that it runs after the previous migration?
Don't worry about the timestamp. It will be generated automatically.
You can do a
rails generate migration add_email_to_user email:string
This would automatically create a migration file which would look like this:
class AddEmailToUser < ActiveRecord::Migration
def self.up
add_column :email, :string
end
def self.down
remove_column :email
end
end
the file would have the timestamp in the format YYYYMMDDHHMMSS (For Rails 2.1 and above) appended in front of the filename.
The Guide has information about generating migrations. If you use the rails generator, it will create correctly named files:
ruby script/generate migration AddEmailToUser email:string
Well you can do two things:
1) If you haven't deployed this anywhere yet, or you don't mind dumping the db and running your migrations again, then modify the file. Remove the tables from your db, and run db:migrate. Easy to do this in development.
2) If this app is in production, or you don't want to drop all your tables. Then create a new migration file. Then in this new migration add/modify/drop the column. Then run db:migrate and the new changes will take effect in your table. This is the best practice.
As for naming your migration, timestamps are used because rails will create a table that keeps track of the latest migrations ran. For this, it is better to use the timestamps. But if you choose, you can use your own convention instead of timestamps. Maybe name them 001_migration.rb, 002_migration.rb, etc.
Hope that helps.
I have a bunch of rails models that I'm re-writing into a single model to simplify my code and reduce unnecessary tables.
I'm wondering what the best way to delete a model class and its table is. I want past migrations to still succeed, but I don't want to leave the empty models lying around.
Do I have to manually delete the old migrations that reference these models, then manually delete the class files?
Does anyone have any tips for the best way to do this?
All in one solution.
Run the following commands:
rails destroy model ModelName
rails g migration DropTableModelName
The former will generate a new migration file which should looks like this:
class DropTableModelName < ActiveRecord::Migration
def change
drop_table :model_name
end
end
Now run db:migrate and you're done.
If you'd like to completely get rid of of a model and its table do this:
rails destroy model Name
The question is a bit stale now, but I just did:
rails destroy scaffold <ModelName> -p
The -p flag shows "pretend" output, which is good for seeing what will happen. Remove the '-p' flag and the results will match the output. This cleaned the entire collection of M-V-C files + testing + js files + the original migration, no problem.
I guess if you are one who likes to hand edit your migrations and include multiple steps in each, losing the original migration could break db:setup, so buyer beware. Keeping one action == one migration file should avoid this potential snafu.
What about doing ruby script/destroy model? That should take care of the model and the migration.
Depending on how far into development or production you are, you may want to migrate the models out safely using a migration to remove/backup data or what not. Then as bobbywilson0 suggested, using
script/destroy model
or if you rspec anything
script/destroy rspec_model
This will remove any spec tests as well.
Or you can always just drag them to the trash folder.
You can take a look at this one at rails guide.
But I suggest, if it is possible, you should delete the models and all references to the models. This will probably save time later as you don't need to maintain the dead code in the codebase.
If you'd rather have a manual based answer:
First run the following command to identify which migrations you want removed:
rake db:migrate:status
Feel free to grep -i on it too if you're confident of your naming scheme.
Make note of all the "add x to model name" and similar alterations to your Model. These can be removed using:
rails d migration AddXToModelName
Do this for every migration besides the initial create migration. The following command will take care of the initial create migration and the files associated with the model:
rails d model ModelName