What's wrong with my database migrations? - ruby-on-rails

I'm trying to create a situation in which I have the ability to create a series of studies. So I have a table called Series. Each Series will have a name. Each Series also has_many :parts. So I have a table called Part and it belongs_to :series. Then each Part has_many :questions and my Question table belongs_to :part. I have to attribute each of these tables to each other so I have the migrations setup like this:
class CreateSeries < ActiveRecord::Migration
def self.up
create_table :series do |t|
t.string :name
t.timestamps
end
end
def self.down
drop_table :series
end
end
class CreateParts < ActiveRecord::Migration
def self.up
create_table :parts do |t|
t.date :date
t.string :book
t.integer :series_id
t.timestamps
end
add_index :parts, [:series_id, :created_at]
end
def self.down
drop_table :parts
end
end
class CreateQuestions < ActiveRecord::Migration
def self.up
create_table :questions do |t|
t.text :body
t.integer :part_id
t.timestamps
end
add_index :questions, [:part_id, :created_at]
end
def self.down
drop_table :questions
end
end
So I migrated the database and using SQLite DB Browser, my Questions table has a parts_id which it should. And my Parts table should have a series_id column, but it does NOT. Could someone please help with this issue? Thanks.

I wonder why the series column is not in your database. ok to perform a safe check if i may call it try running the model generator again. This time run it like this
rails g model part date:date book series:belongs_to and see if you get the same issue. I hope this helps. Or you can also check with your console window try creating a new part with a random series id and check if it has pluralization issues.

Open the application console rails c and type Part.
You should see the attribute series_id.
If you do, the solution is simply restarting the server.

Related

What is the best practice when it comes to deleting a table in the Ruby on Rails migration?

I created a few tables last week and I was told to delete them. The suggested way in which I should do it looks like this:
Sample table:
class CreateMenuTable < ActiveRecord::Migration
def change
create_table :menus do |t|
t.string :name
t.timestamps null: false
end
end
end
class CreateSpreeMenuRole < ActiveRecord::Migration
def change
create_table :menu_roles do |t|
t.belongs_to :role, class_name: 'Role'
t.belongs_to :menu, class_name: 'Menu'
t.timestamps null: false
end
end
end
step 1. bin/rake db:rollback STEP=6
step 2. after rolling back I have to comment out those tables then
step 3. bin/rake db:migrate
Btw we still have multiple tables created after that, that's why we still need to run migrate.
Generate a migration to drop these tables rails g migration DropMenuTable and rails g migration DropMenuRolesTable
Drop the Tablet by either
migration not reversible
class DropMenuTable < ActiveRecord::Migration
def up
drop_table :menus
end
def down
fail ActiveRecord::IrreversibleMigration
end
end
class DropMenuRolesTable < ActiveRecord::Migration
def up
drop_table :menu_roles
end
def down
fail ActiveRecord::IrreversibleMigration
end
end
or
migration is reversible
class DropMenuTable < ActiveRecord::Migration
def change
drop_table :menues do |t|
t.string :name
t.timestamps null: false
end
end
end
class DropMenuRolesTable < ActiveRecord::Migration
def change
drop_table :menu_roles do |t|
t.belongs_to :role, class_name: 'Role'
t.belongs_to :menu, class_name: 'Menu'
t.timestamps null: false
end
end
end
run rake db:migrate
There will be unsuitable commit if you just comment out migration.
Also you will delete all data in other tables.
So the best practice to drop table via migration like this:
class DropMenuTable < ActiveRecord::Migration
def change
drop_table :menus
end
end
class DropMenuRolesTable < ActiveRecord::Migration
def change
drop_table :menu_roles
end
end
Migrations allow you to evolve your database schema overtime.
When your app is in development it may seem easy to just rollback the migration and make changes, or even delete it. But you shouldn't do it when you have code deployed to production or is sharing code with another developer. Your database will likely become corrupted and will produce hard to fix bugs.
The best thing you can do to delete a table is to create a new migration and drop_table as suggested by spickermann.

Dropping table in Rails 5 - Adding it back later throws table already exists error

I am building an application with Rails 5 and SQLite. I was trying to make a table for a many to many relationship and created a join table without the 'CreateModelXModelYJoinTable', rather I created a migration with two foreign keys. Once I realized my mistake, I dropped the table via a migration and recreated it with the above syntax, but now when I migrate I am getting this error:
SQLite3::SQLException: table "ingredients_recipes" already exists
Here are the three offending migrations in order:
class CreateIngredientRecipes < ActiveRecord::Migration[5.1]
def change
create_table :ingredient_recipes do |t|
t.references :recipe, foreign_key: true
t.references :ingredient, foreign_key: true
t.timestamps
end
end
end
class DropIngredientsRecipes < ActiveRecord::Migration[5.1]
def change
drop_table :ingredient_recipes
end
end
class CreateIngredientsRecipesJoinTable < ActiveRecord::Migration[5.1]
def change
create_join_table :ingredients, :recipes
create_join_table :ingredients, :recipes do |t|
t.index :ingredient_id
t.index :recipe_id
end
end
end
Any help is greatly appreciated. I checked in the console and the association is no longer there. Even went into rails db and listed the tables and it is not there. Looked everywhere for a solution.
Your mistake is you have the create_join_table repeated twice:
Your code:
class CreateIngredientsRecipesJoinTable < ActiveRecord::Migration[5.1]
def change
create_join_table :ingredients, :recipes
create_join_table :ingredients, :recipes do |t|
t.index :ingredient_id
t.index :recipe_id
end
end
end
It should be :
class CreateIngredientsRecipesJoinTable < ActiveRecord::Migration[5.1]
def change
create_join_table :ingredients, :recipes do |t|
t.index :ingredient_id
t.index :recipe_id
end
end
end
You can notice that the created Join table is ingredients_recipes and not ingredient_recipes, which explains the issue.

Rails: trouble understanding database relationships

So I am trying to create three models, Project, Entry and User. A Project has many Entries, and a a User has many Entries. I scaffolded the above three models with the following commands:
rails g scaffold Project title:string
rails g scaffold Entry project:project_id entry_for:user_id created_by:userid \
date:string start_time:string end_time:string total:string type_of_work:string \
on_off_site:string phase:string description:text
rails g scaffold User name:string
I realize that I probably totally goofed up the part where I manually put in the foreign keys for the other tables in the Entry model. I don't know how much has_many belongs_to automates the relationship between different models in terms of keys so I tried to add the foreign key fields manually. Is this wrong?
When I try to run db:migrate I get the following error:
undefined method `user_id' for #<ActiveRecord::ConnectionAdapters::TableDefinition:0x007fc1bdf37970>
Here are my migrations, as I tried to remove all of the foreign key fields but got the above error.
class CreateProjects < ActiveRecord::Migration
def change
create_table :projects do |t|
t.string :name
t.timestamps
end
end
end
class CreateEntries < ActiveRecord::Migration
def change
create_table :entries do |t|
t.string :project
t.string :project_id
t.user_id :entry_for
t.user_id :created_by
t.string :date
t.string :start_time
t.string :end_time
t.string :total
t.string :type_of_work
t.string :on_off_site
t.string :phase
t.text :description
t.timestamps
end
end
end
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.timestamps
end
end
end
class RemoveColumns < ActiveRecord::Migration
def self.up
remove_column :entries, :created_by
remove_column :entries, :entry_for
remove_column :entries, :project_id
end
def self.down
add_column :entries, :created_by, :user_id
add_column :entries, :entry_for , :user_id
add_column :entries, :project_id, :string
end
end
Thank you for your help!
In your migrations, instead of t.user_id you can try t.integer or t.index. That should at least get your migrations running.
I am going to use t.references entry_for and then write belongs_to :entry_for, class_name: "User" in the Entry model as a means of writing my own foreign key name. For the project column in entries I realized I can similarly write t.references project.

Best way to add_index to database

I have the following two migrations already in my database:
When I created Prices:
class CreatePrices < ActiveRecord::Migration
def self.up
create_table :prices do |t|
t.string :price_name
t.decimal :price
t.date :date
t.timestamps
end
# add_index :prices (not added)
end
def self.down
drop_table :prices
end
end
and when I added a user_id to Prices:
class AddUserIdToPrices < ActiveRecord::Migration
def self.up
add_column :prices, :user_id, :integer
end
# add_index :user_id (not added)
end
def self.down
remove_column :prices, :user_id
end
end
Is there a way from the command line to add prices and user_id to index? I looked at this question and still was confused on how to go about adding indexes and the parts where I put "not added" seem like they would be error-prone because they were earlier migrations.
My question is, what is the best way for me to add indexing to prices and user_id?
Thank you for the help!
I think one extra migration fits well:
class AddIndexes < ActiveRecord::Migration
def self.up
add_index :prices, :user_id
add_index :prices, :price
end
def self.down
remove_index :prices, :user_id
remove_index :prices, :price
end
end
Or you can use change syntax with newer versions of rails, look at DonamiteIsTnt comment for details:
class AddIndexes < ActiveRecord::Migration
def change
add_index :prices, :user_id
add_index :prices, :price
end
end
Once an app is in production, the intent is that migrations will be applied once.
If you're still developing your app, you can always add them as you've noted followed by a rake db:migrate:reset this will wipe your database and re-create it.
Otherwise, create a new migration rails g migration add_user_id_index.
class AddUserIdIndex < ActiveRecord::Migration
def self.up
add_index :prices, :user_id
end
def self.down
remove_index :prices, :user_id
end
end
FWIW, add_index :prices doesn't make sense. Indexes are per-column, not per-table.
You can always manually create indexes by logging into your database.
CREATE INDEX prices__user_id__idx ON prices (user_id);
Simple solution:
create a new migration
add the indexes there (they don't need to be in the older migrations)
run the migrations

How do I remove a model and its table in Ruby on Rails?

I'm diving into RoR and I need to remove a model and its table, as well as update the other models that reference it. I did a search on google and SO and the best answer I found was this, but the answer is unclear to me. The final consensus was to use the ruby script/destroy model method and then "manually edit any migrations that might contain refs to these deleted models" It's this last part that I'm unclear about. I want to delete the models for my user and profile models and tables...
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :email
t.string :password
t.timestamps
end
end
def self.down
drop_table :users
end
end
class CreateProfiles < ActiveRecord::Migration
def self.up
create_table :profiles do |t|
t.string :name
t.integer :user_id
t.timestamps
end
end
def self.down
drop_table :profiles
end
end
and update the article model and table that references them...
class CreateArticles < ActiveRecord::Migration
def self.up
create_table :articles do |t|
t.string :title
t.text :body
t.datetime :published_at
t.string :image
t.timestamps
end
end
def self.down
drop_table :articles
end
end
class AddUserIdToArticles < ActiveRecord::Migration
def self.up
add_column :articles, :user_id, :integer
end
def self.down
remove_column :articles, :user_id
end
end
Can I just do ruby script/destroy user and then call the self.down methods in the article migrations? If so, how do I call the 'self.down` methods and in what order?
Thanks so much in advance for your help!
Yep. Just delete it with
ruby script/destroy model user
ruby script/destroy model profile
And then rollback your database, or self.down with this :
rake db:rollback
Now you can safely delete your migration file.

Resources