changing the association and deleting corresponding migration - ruby-on-rails

I am new to ruby on rails. I have created a many-to-many association and a migration, such as follows:
in Foo model:
has_and_belongs_to_many bars
in Bar model:
has_and_belongs_to_many foos
and the migration for join table has the following content:
def change
create_table :foos_bars, id: false do |t|
t.references :foo
t.references :bar
end
end
Now I see that the association should be one-to-many as: foo has many bars.
I don't know if I have generated controllers after the above migration, but I know that the file of the above migration is the last one that was created in the migrate folder. Also I have not made any connection yet between any foo and any bar.
Can I do the following to start fresh (change the association and also remove the file of the migration):
use 'rake db:rollback'
delete the file of the join table migration (i.e. timestamp_create_bars_foos.rb file)
change the 'has_and_belongs_to_many' in foo to 'has_many', and in bar to 'belongs_to'
run: 'rails generate migration CreateFoosBars'
run: 'rake db:migrate'
If not, what can I do to make the above modification for the association?
Thanks in Advance!

The steps you have listed looks good.
The only thing that stands out is the intention to CreateFoosBars again in Step 4 : rails generate migration CreateFoosBars'.
Since the foos and bars tables are already created, and this is a has_many relationship, you just need to add a reference for foo in the bars table, and not create a new table.
Something along the lines of:
rails g migration add_foo_id_to_bar foo_id:integer
Would advise reviewing Rails 3 migrations: Adding reference column? to figure out what the migration should do.

Related

Join table error on running migration

I have two models in rails 5.1
class Category < ActiveRecord::Base
has_and_belongs_to_many :sub_categories, join_table: "categories_join_table"
end
class SubCategory < ActiveRecord::Base
has_and_belongs_to_many :categories, join_table: "categories_join_table"
end
I have added multiple migrations the problem is when I try to run migration I get the error ERROR: relation "comfort_factor_sub_categories" does not exist because in the migration to create table comfort_factor_sub_categories will run in later migrations. How can I handle this?
Note: I can't change the name of join_table as it is just an example I have long names.
This question is over three years old at the time of this writing, but I just ran into the same problem so I thought I'd share my solution here.
In my case, I was running Rails 6.1, so my error message looked a bit different:
StandardError: An error has occurred, this and all later migrations canceled:
Could not find table 'officers_users'
The officers_users table is a join table that is created in a later migration, but the migration in question doesn't make any use of it, so why was I getting this error?
At first, I thought it might be a Rails bug as my migration was using update_columns to modify the users table, which shouldn't run any callbacks, but then I noticed that the values that I was updating them with were dependent on a computed attribute, which in turn was dependent on the officers_users join table. So Rails was right and I was wrong (once again, hah)! The solution was simply to make the failing migration self-sufficient without needing that computed attribute. Once I did that, everything was good again.
So if you run into the same problem, I would suggest checking your migration with a fine toothed comb and look for any hidden dependencies that might be using the later migration's join table.
If I understood your problem correctly, you have added several migrations and you cannot run them because some relationship is not found.
In that case, you should duplicate the classes in migrations:
class CreateCategories < ActiveRecord::Migration[5.1]
class Category < ActiveRecord::Base
# without declaring the relationship with the table which does not exist yet
end
def up
create_table :categories do |t|
# t.something
end
end
def down
drop_table :categories
end
end
You should then do the same thing for SubCategory.
For creating a proper join_table, you can refer to Rails official documentation

rails associations between two tables

I've got two tables in my Postgres database: categories and products.
I have a one to many relationship defined, one category can have many products.
After I've defined these in the two models in Rails, is there something else I need to do to the tables? I still have only the primary key that Rails defined when I set up each model separately.
You can run a migration generator with the right parameters to set up the foreign key.
bin/rails generate migration AddCategoryRefToProducts category:references
This assumes you have a Product model and Category model with these associations:
#product.rb
belongs_to :category
#category.rb
has_many :products
Run rake db:migrate to complete the process
When you look at your db/migrate directory you will see a file that contains an add_reference line within a def change block. Here's the reference for that method: Rails API. The syntax for the standalone generator is from the Rails Guides

Create a Users model where previous Users model existed then dropped

I am working on a Rails application where the previous developer had created a Users model, then later dropped it in lieu of another solution. The migration files are still in the repository, but obviously the table doesn't exist. I am now trying to create a User authentication system to integrate a blog, but I am running into the issue of the previous migration and getting the following error message when trying rails g model User:
"Another migration is already named create_users..."
Is it possible there a way to create Users again?
Just to be extra clear. There is a create_users and later a drop_users migration.
1. $ rails g model User --migration=false
2. $ rails g migration create_users_again
3. open create_users_again migration file (created in step 2), and define your table as:
def change
create_table :users do |t|
t.email :string
t.timestamps
end
add_index :email
end
You can look your old create_users migration file for help.
When the previous developer ran rails g model user, this created a migration class like so:
class CreateUsers < ActiveRecord::Migration
Now that you are running rails g model user, Rails is complaining that that class CreateUsers, already exits.
You can either:
Rename the previous migration to CreateUsersPrevious (don't forget to rename the migration file as well xxxxxxxxxxx_create_users_previous.rb) if you would like to keep it documented in your migration history
Remove the old migration file

Guidelines about using of migrate on Rails

I have already read the documentation of "migrate" on Rails 3 (Rails 3.0 Relese Notes Migrate) but I have some doubts.
e.g. I created two class:
rails generate scaffold User name:string age:integer height:float
rails generate scaffold Hat type:string width:float height:float
This create models, controllers, ... User and Hat and its migrate class: xxx_create_users.rb and xxx_create_hats.rb
Ok, now we guess we want modify User class and we delete height attribute, and we add the relationships between Users and Hats:
User
class User < ActiveRecord::Base
attr_accessible :name, :age
has_many :hats
end
Hat
class Hat < ActiveRecord::Base
attr_accessible :type, :width, height
belongs_to :user
end
Options that I guess:
I remove all files xxx_create_xxx.rb and then I will create again with: rails generate migration CreateUser (and the same for Hat)
I create a new migration file: rails generate migration MyNewMigration where I codify by hand all changes.
Is there another way to automate changes in my classes for passed it to the database? What is the correct way to proceed?
The idea of migrations is that you have a stringent storyline where you can start at any point, forward and backwards. This means that it should not ever be necessary to delete a migration.
Instead, you create a new migration that will change, remove or add database fields.
In your example, you would leave the old migration where it is and then create a new migration like so:
rails g migration change_user_fields
And inside def up you write
remove_column :table_name, :column_name
change_column :table_name, :column_name, :data_type
Add a def down - this will be run whenever the migration is reversed by rake db:rollback. Inside def down put:
add_column :table_name, :column_name # add the field that you removed (s.a.)
change_column :table_name, :column_name, :data_type # change back to old data type
Rails 3 gives you a nice shortcut for adding and removing fields from a table by doing:
rails g migration add_something_to_users name:string
which will automatically create a migration that adds a field called name with a data type of string to the users table. Or
rails g migration remove_something_from_users name
which will automatically create a migration to remove the name field from the users table. These shortcuts and the created migration files do not need a def down - rails will automatically be smart enough to figure that out when reversed.
In both cases, you can replace the word "something" with whatever you like.
However, I know of no way to use a shortcut to change data types, so you need to go in the migration file and do that manually.
Eventually, just run rake db:migrate and you'll be all set!
Scaffold only automate a fixed command, so if you create a model and its attributes with scaffold, your migration will only contain the fields you specify on the command line. There is no way to keep track of changes automatically.
If you add/remove/change something on your database, you have to manually set it. Migrations are useful because you can keep track of these changes on time.
So i recommend you to never delete a migration. In this particular case you described, you just have to create another one to reflect the new change on your database, keeping a total of 3 migrations, instead of deleting and creating another.
The answer to your question should be alternative 2. But you don't have to do it all by hand if you just want to add or remove attributes:
http://guides.rubyonrails.org/migrations.html#creating-a-standalone-migration

Ruby on Rails database: how to mention foreign key relation by changing app/model/table.rb file how to know they implemented

I am new to RoR. I used "rails generate model ServiceConfigs" command to generate a table.
so may commands are as below
rails generate model ServiceConfigs configs:string
rake db:migrate
-- can see app/db/service_config.rb created.
Now edited service_config.rb file to add 2 columns and which has a foreign key relation to service table. So here is code
class ServiceConfigs < ActiveRecord::Base
belongs_to :service, :dependent => :destroy
validates_presence_of :configs
end
Now when I login to underline database, and look at the table I don't see foreign key relation in table schema. Whats wrong/more I need to do?
highly appreciate your time and help
Krishna
So a few notes for you as you're getting started here: Firstly, I'd name your model in the singular form, as though you are describing a single instance of it: ServiceConfig and in the case where it belongs to a service, you may want to think of a different name all together.
Secondly validates_presence_of suggests that you have that field, so firstly, I'd remove the validation until you know that your DB has that column and that the migration worked. You can make sure by looking at your migration file and confirming that the column is being created.
You can define the relationship the "rails way" in your migration too:
http://guides.rubyonrails.org/association_basics.html
create_table :service_configs do |t|
t.string :configs
t.references :service
t.timestamps
end
Update
If you want to rerun a particular migration run:
rake db:migrate:redo VERSION=20100421175455
You can take a look in your schema to see what migration you are currently at as well. And you can also take a look at the schema to see what your DB is expected to look like as well.

Resources