Andrius Andrius -3 years ago 150
MySQL Question

ActiveRecord::StatementInvalid: Mysql2::Error: Cannot delete or update a parent row - Rails 4.2.6

Error that need to be solved:


ActiveRecord::StatementInvalid: Mysql2::Error: Cannot delete or update
a parent row: a foreign key constraint fails
(
slap_chat_development
.
chatrooms
, CONSTRAINT
fk_rails_496733c195

FOREIGN KEY (
group_id
) REFERENCES
groups
(
id
)): DELETE FROM
groups
WHERE
groups
.
id
= 1


QUESTION IS:


  • can someone guide me where from should this error be fixed.



As I see problem persists in relation between
groups
and
chatrooms
tables.

Further details:

schema.rb

ActiveRecord::Schema.define(version: 20160606100750) do

create_table "chatrooms", force: :cascade do |t|
t.integer "group_id", limit: 4
t.string "name", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

add_index "chatrooms", ["group_id"], name: "index_chatrooms_on_group_id", using: :btree

create_table "chatrooms_users", force: :cascade do |t|
t.integer "chatroom_id", limit: 4
t.integer "user_id", limit: 4
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

add_index "chatrooms_users", ["chatroom_id"], name: "index_chatrooms_users_on_chatroom_id", using: :btree
add_index "chatrooms_users", ["user_id"], name: "index_chatrooms_users_on_user_id", using: :btree

create_table "groups", force: :cascade do |t|
t.string "name", limit: 255
t.integer "user_id", limit: 4
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

add_index "groups", ["user_id"], name: "index_groups_on_user_id", using: :btree

create_table "groups_users", force: :cascade do |t|
t.integer "group_id", limit: 4
t.integer "user_id", limit: 4
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

add_index "groups_users", ["group_id"], name: "index_groups_users_on_group_id", using: :btree
add_index "groups_users", ["user_id"], name: "index_groups_users_on_user_id", using: :btree

create_table "posts", force: :cascade do |t|
t.integer "user_id", limit: 4
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "content", limit: 255
end

add_index "posts", ["user_id"], name: "index_posts_on_user_id", using: :btree

create_table "users", force: :cascade do |t|
t.string "email", limit: 255, default: "", null: false
t.string "encrypted_password", limit: 255, default: "", null: false
t.string "reset_password_token", limit: 255
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", limit: 4, default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip", limit: 255
t.string "last_sign_in_ip", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "first_name", limit: 255
t.string "nick_name", limit: 255
t.string "last_name", limit: 255
end

add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree

add_foreign_key "chatrooms", "groups"
add_foreign_key "chatrooms_users", "chatrooms"
add_foreign_key "chatrooms_users", "users"
add_foreign_key "groups", "users"
add_foreign_key "groups_users", "groups"
add_foreign_key "groups_users", "users"
add_foreign_key "posts", "users"
end


Group model:

class Group < ActiveRecord::Base
has_many :chatrooms
belongs_to :group_admin, class_name: "User", foreign_key: :user_id
has_and_belongs_to_many :members, class_name: "User", association_foreign_key: :user_id

validates :user_id, presence: true
validates :name, presence: true, length: { minimum: 3 }

before_create { self.name = self.name.capitalize }
after_create :assign_creator
around_destroy :destroy_all_associates

def general_room
self.chatrooms.where("name = ?", "general").take
end

def except_general_room
self.chatrooms.select { |room| room != self.general_room }
end

def assign_creator
member = self.group_admin
self.members << member
self.general_room.members << member
end

def destroy_all_associates
rooms = self.chatrooms
yield
rooms.each do |room|
room.destroy
end
end
end


Chatroom model:

class Chatroom < ActiveRecord::Base
belongs_to :group
has_and_belongs_to_many :members, class_name: "User", association_foreign_key: :user_id

validates :name, presence: true, length: { minimum: 3 }

before_save { self.name = self.name.downcase }
around_create :ensure_group_presence
around_destroy :destroy_all_associates

def feed
ids = Array.new
self.members.each do |member|
ids += member.post_ids
end
Post.where("id IN (?)", ids)
end

def ensure_group_presence
yield
self.group_id.present?
end

def destroy_all_associates
feed = self.feed
yield
feed.destroy_all
end
end

Answer Source

You can try using this in your group model.

class Group < ActiveRecord::Base
  has_many :chatrooms , dependent: :destroy
end

Now when you execute, Group.last.destroy, it should delete the dependent associated chatrooms before and no hanging data would be left

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download