PostsControllerTest Error with Simple Ruby on Rails Program - ruby-on-rails

Full Code on GitHub, https://github.com/Marium36/blog
I am taking online Ruby on Rails course that guides us to create simple blog application.
Running this on Ubuntu 18.04
Following commands work
> rails new blog
> cd blog
> rails generate scaffold Post title:string body:text
> rails generate scaffold Comment post:references body:text
> rake db:migrate
> rake routes
> rails server
As soon as I run this (per the course)
> rake db:test:load
> rake test
I get error
Run options: --seed 62159
# Running:
.E
Error:
PostsControllerTest#test_should_destroy_post:
ActiveRecord::InvalidForeignKey: SQLite3::ConstraintException: FOREIGN KEY constraint failed
app/controllers/posts_controller.rb:57:in `destroy'
test/controllers/posts_controller_test.rb:43:in `block (2 levels) in <class:PostsControllerTest>'
test/controllers/posts_controller_test.rb:42:in `block in <class:PostsControllerTest>'
rails test test/controllers/posts_controller_test.rb:41
............
Finished in 7.151961s, 1.9575 runs/s, 2.2371 assertions/s.
14 runs, 16 assertions, 0 failures, 1 errors, 0 skips

The error you're experiencing (Foreign Key constraint failed) is telling you that you have a foreign key constraint in your database that is not met when some particular piece of code is run.
What is a foreign key?*
In relational databases—like MySQL, PostgreSQL, or SQLite—you typically have tables of data that relate to one another in some way. It's very common for rows in those tables to reference one another using an ID, which is referred to as the “key”. You might have, as you do here, a comments table with a post_id column that references the id column of the posts table. In this case, the post_id is referencing the foreign key posts.id.
What is a constraint?
In relational databases, constraints provide a way to ensure the integrity of your data. A constraint can do things like ensure a price column is never negative (i.e. verify based on the data itself), ensure one value is lower than another in the same row, or verify that the data matches another record in another table entirely.
Putting it together: what is a foreign key constraint?
A foreign key constraint, if you haven't already put it together, is just a special type of constraint that ensures that the “foreign record”—the row in the table you're referencing—actually exists. In this case, comments.post_id has a foreign key constraint on posts.id, which ensures that a row can't be added to the comments table with a post_id that doesn't exist in the posts.id column.
So why did you get this error?
This is your migration creating the comments table:
class CreateComments < ActiveRecord::Migration[6.0]
def change
create_table :comments do |t|
t.references :post, null: false, foreign_key: true
t.text :body
t.timestamps
end
end
end
Note the foreign_key: true part! That's telling Rails to add a foreign key constraint between comments and posts on the foreign key.
This is the test that is failing:
test "should destroy post" do
assert_difference('Post.count', -1) do
delete post_url(#post)
end
assert_redirected_to posts_url
end
It's deleting a Post record, which tells us that there is a row in the comments table with a post_id column referencing the Post we're trying to remove in this test, hence the failure.
What can I do to fix it?
First, you probably want to add an inverse relationship to your Post model, like this:
class Post < ApplicationRecord
has_many :comments
Then you'll want to tell Rails how to handle associated records when you're removing a Post. You can do that with the dependent option, which takes a handful of options. I'll use :delete_all here, which tells Rails to use a single SQL query to delete all “dependent” comments (that is, comments that reference this Post) without loading them first:
class Post < ApplicationRecord
has_many :comments, dependent: :delete_all
end
With that change your test should succeed because it will have removed the comments as well as the post in the same transaction, preventing the foreign key constraint from failing.

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

edit page with form that uses select

I have a blog like set up were there are things called events (which are essentially posts) but they have different types ("kinds") which will help me categorize where to put them in my layout. Anyway when I go to the events/edit page I get this error:
Mysql2::Error: Unknown column 'event_kinds.event_id' in 'where clause': SELECT event_kinds.* FROM event_kinds WHERE event_kinds.event_id = 1 LIMIT 1
I thought it might be an association issue, so is this right?
EventKind has_many :events
Event has_one :event_kind
?
EDIT:
I've renamed event_kinds to kinds. Right now I don't have a table called event_kinds that links together events and kinds models since each event can only be of one kind I just put the kind id inside the events table. Is there a way so that I can skip the events_kind...
You need to add event_id column to the event_kinds table.
Just create a migration
rails g migration add_event_id_to_envent_kind
Edit he file and add the below content.
def change
add_column :envent_kinds, :event_id, :integer
end
Run migration
rake db:migrate
This should solve the error.

Rails migration assumes a relationship where there is none

I have a Rails 3.1 app with a User model and a Venue model. These two models have a HABTM relationship - A user may manage many venues and a venue may be managed by many users.
I'd like users to be able to select a default venue so I'm trying to add a default_venue_id attribute to User with the following migration:
class AddDefaultVenueIdToUser < ActiveRecord::Migration
def self.up
add_column :users, :default_venue_id, :integer
end
def self.down
remove_column :users, :default_venue_id
end
end
The problem is that when I run that migration against my PostgreSQL database, it's assuming that default_venue_id is the foreign key for a relationship with the non-existent default_venues table and throws the following error:
PGError: ERROR: relation "default_venues" does not exist
: ALTER TABLE "users" ADD FOREIGN KEY ("default_venue_id") REFERENCES "default_venues" ("id")
Should I be doing something to tell the database that I'm not trying to create a relationship or am I going about this the wrong way?
Edit: I've just realised that another developer who worked on the project added the schema_plus gem which automatically defines constraints for columns ending in _id
That explains why I've never run into this behaviour before!
It would be helpful to see the Models as well to diagnose this problem.
However with that being said, I think that if you are using HABTM associations here it might be a good idea to take a look at a has many through relationship. example: VenueManagement which would have your user_id and venue_id. That way you could handle extra attributes on the association where it makes sense, like a default flag.
Hope that helps.
Since Rails seems to pick up on the _id part of the tag and tries linking it to a table, the easy solution to this is to try name it differently as convention says a field with _id links to a table.
An example of which could be
:default_id_for_venue, or just :defualt_venue

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