How to add reference column migration in Rails 6 with SQLite - ruby-on-rails

What is the correct way to add reference column migration in Rails 6 without getting SQLite3::SQLException: Cannot add a NOT NULL column with default value NULL?
I can hack it to get it working; but, I am preparing a tutorial for a grad class, so I want to make sure I'm doing it "by the book".
The starting point is a Post class (think "blog post"). I want to add an Author class and set up an 1-to-many relationship between authors and posts. After adding the author class and running the corresponding migration, I then create a migration to add an Author reference to Post:
rails g migration AddAuthorToPost author:references
This command generates:
class AddAuthorToPost < ActiveRecord::Migration[6.0]
def change
add_reference :posts, :author, null: false, foreign_key: true
end
end
The problem is, of course, that SQLite complains because it won't tolerate the potential for a null foreign key --- even if the Post table is empty: (How to solve "Cannot add a NOT NULL column with default value NULL" in SQLite3?)
I looked back at the previous year's tutorial (prepared by a different instructor) and the generator did not add null: false to the migration. (See also Add a reference column migration in Rails 5)
Removing null: false from the migration allows the migration to run; but, "disabling safety features" doesn't seem appropriate in a classroom setting :)
Is there a better way to do this?

By default, a foreign_key is required (on app level, not on database).
To disable, in config/application.rb add
config.active_record.belongs_to_required_by_default = false
Or
class YourModel < ApplicationRecord
belongs_to :another_model, optional: true
end

Related

Adding 2 references to a rails model from same model

I have a model called WalksSection and another called WalkSectionButton. I have created the WalksSection model (and done migration).
Now I want to create WalkSectionButton but want to create two references between the two tables:
walk_sections.id = walk_section_buttons.section_button_id
walk_sections.id = walk_section_buttons.next_section_button_id
The first is the standard one but the other (I think) I need to tell the migration and the model the column name.
So the standard one in the model is
belongs_to :WalkSection
and in the migration is
t.references :WalkSection, foreign_key: true
So I guess I need to have a second line in model and migration which specifies the foreign (and primary) key name but not sure of the syntax.
The other way to do this maybe is to run the migration to create the first reference then do another migration that adds the column and key for the second foregn key.
add_column :walk_section_buttons, :next_section_button_id, :integer
add_foreign_key :walk_section_buttons, :walk_sections, column: :next_section_button_id, primary_key: :id
But not sure what to do to the model. Maybe I don't need to but in the WalksSections model I think I should add a has_many, but again would need to specify a column name for the second one.

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

Add nullable foreign key in Rails

Referencing to Rails 4.2 add_foreign_key support:
# add a foreign key to `articles.author_id` referencing `authors.id`
add_foreign_key :articles, :authors
How to create a nullable foreign key constraint, to allow the situation, where articles.author_id can be sometimes null?
Note that in Rails 5 and in Rails 6 you may need to mark the corresponding association as optional if it's 1:n (belongs_to), as the default was changed:
belongs_to :author, optional: true
This is the corresponding Changeset.
To use the old behavior across your application, you can also set:
Rails.application.config.active_record.belongs_to_required_by_default = false
in config/initializers/new_framework_defaults.rb
The error you will usually see is:
ActiveRecord::RecordInvalid: Validation failed: Class must exist
from /usr/local/lib/ruby/gems/2.3.0/gems/activerecord-5.0.0.1/lib/active_record/validations.rb:78:in `raise_validation_error'
You may also need to update any migration: change null: false to true and run rake db:redo if it had already run.
Adding optional: true along with belongs_to :author in article model will do the job.
There is nothing in the guide that implies add_foreign_key would make the corresponding foreign field "NOT NULL" or required. add_foreign_key simply adds a foreign key constraint whether the field is required or not (in your case author_id in articles).
Did you get an error when you tried this in your migration?
Here's the SQL that it would generate:
ALTER TABLE "articles" ADD CONSTRAINT articles_author_id_fk FOREIGN KEY ("author_id") REFERENCES "authors" ("id")
SO, if in your original migration of articles, author_id is null, then you can have foreign key that's nullable.

Add a foreign key to an existing rails model

I have a rails 4 app.
I have two tables, one for 'scope' and one for 'data'. Data belongs to scope. I forgot to add a foreign key when I set up data and I'm trying to write a migration to add one now.
I have created a change table, but the migration I've written isn't working.
I can't follow the rails guides example because it isn't consistent with the experience I'm having in my setup (not sure why).
The migration I have is:
class AddFKeyToData < ActiveRecord::Migration
def change
add_foreign_key :data, :scopes
end
end
Please can you help me identify the problem.
Thank you
Rollback this migration by:
rake db:rollback
Then go into your migration and edit add_foreign....
to:
add_column :data, :scope_id, :integer
Should work!

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