【问题标题】:ActiveRecord::StatementInvalid: Mysql2::Error: Cannot delete or update a parent row - Rails 4.2.6ActiveRecord::StatementInvalid: Mysql2::Error: 无法删除或更新父行 - Rails 4.2.6
【发布时间】:2016-06-06 18:06:26
【问题描述】:

需要解决的错误:

ActiveRecord::StatementInvalid: Mysql2::Error: 无法删除或更新 父行:外键约束失败 (slap_chat_development.chatrooms, 约束fk_rails_496733c195 外键 (group_id) 引用 groups (id)):删除 groups 在哪里 groups.id = 1

问题是:

  • 谁能指导我从哪里修复这个错误。

正如我所见,groupschatrooms 表之间的关系仍然存在问题。

更多详情:

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

组模型:

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

聊天室模型:

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

【问题讨论】:

标签: mysql ruby-on-rails ruby activerecord


【解决方案1】:

您可以尝试在您的组模型中使用它。

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

现在当你执行Group.last.destroy时,它应该删除之前依赖的关联聊天室,不会留下任何挂起的数据

【讨论】:

    【解决方案2】:

    您似乎正在尝试删除具有一个或多个聊天室的群组。

    但是因为你添加了外键约束(add_foreign_key "chatrooms", "groups"),所以在还有分配的聊天室的情况下是不允许删除组的。

    要解决此问题,您必须销毁群组本身之前销毁所有关联的聊天室。

    【讨论】:

    • 这个答案也帮助我理解了我的错误。非常感谢!
    【解决方案3】:

    我认为这取决于您是否需要删除关联的表。 如果你需要删除关联的表,你应该

    has_many :chatrooms , dependent: :destroy
    

    但是,如果你不想删除关联的表,你应该

    has_many :chatrooms , dependent: :nullify
    

    rails API中有详细说明

    :dependent
      Controls what happens to the associated objects when their owner is 
      destroyed. Note that these are implemented as callbacks, and Rails 
      executes callbacks in order. Therefore, other similar callbacks may 
      affect the :dependent behavior, and the :dependent behavior may 
      affect other callbacks.
    
        :destroy causes all the associated objects to also be destroyed.
    
        :delete_all causes all the associated objects to be deleted directly 
        from the database (so callbacks will not be executed).
    
        :nullify causes the foreign keys to be set to NULL. Callbacks are not executed.
    
        :restrict_with_exception causes an exception to be raised if there are any associated records.
    
        :restrict_with_error causes an error to be added to the owner if there are any associated objects.
    
        If using with the :through option, the association on the join model must be a belongs_to, and the records which get deleted are the join records, rather than the associated records.
    
        If using dependent: :destroy on a scoped association, only the scoped objects are destroyed. For example, if a Post model defines has_many 
        :comments, -> { where published: true }, dependent: :destroy and destroy is called on a post, only published comments are destroyed. 
        This means that any unpublished comments in the database would still contain a foreign key pointing to the now deleted post.
    

    RailsApi

    【讨论】:

      【解决方案4】:

      错误:Mysql2::Error:无法删除或更新父行:外键约束失败

      解决方案:

      我认为您使用过 .delete 或 delete_all,

      使用 .destroy

      代替 .delete 或 delete_all

      .destroy 将删除与该模型相关的所有值

      现在它可以工作了!

      【讨论】:

        猜你喜欢
        • 2022-01-09
        • 2021-12-09
        • 2018-03-15
        • 2016-09-13
        • 1970-01-01
        • 2018-08-05
        • 2014-07-10
        • 1970-01-01
        • 2015-12-26
        相关资源
        最近更新 更多