我知道在Rails 5中before_destroy
回调不会考虑false
返回值,而是考虑throw(:abort)
。您可以在here和there中找到有关Rails API docs和Rails Guides的更多信息。
但prepend
选项在以下情况下仍不起作用。
我需要阻止删除以下模型中的最后一条记录:
class ShopLanguage < ApplicationRecord
belongs_to :shop
belongs_to :language
has_many :descriptions, inverse_of: :shop_language, dependent: :destroy
validates :language, :shop, presence: true
validates :language, uniqueness: { scope: :shop, message: "already defined for this shop"}
before_destroy :check_last_language, prepend: true
private
def check_last_language
if shop.languages.count < 2
errors[:base] << "You can't delete the last language"
false
end
end
end
这是Shop模型:
class Shop < ApplicationRecord
has_many :users
has_many :links, inverse_of: :shop
has_many :shop_languages, inverse_of: :shop, dependent: :destroy
has_many :languages, through: :shop_languages
...
即使我在声明关系之前移动回调上限:
class ShopLanguage < ApplicationRecord
before_destroy :check_last_language, prepend: true
...
它也不起作用。这是我在rails控制台中尝试的内容:
shop = Shop.first
#<Shop id: 2, category: "Sport", fax: nil, identifier: 1, leader: "XXXXX", modified_by: "batch.update.shops", name: "ENGLOS", opening_date: "1976-07-27", phone: "0320001700", status: "open", created_at: "2018-03-22 16:39:35", updated_at: "2018-03-22 16:39:35">
2.4.0 :002 > lang = Language.find(245)
Language Load (0.4ms) SELECT "languages".* FROM "languages" WHERE "languages"."id" = $1 LIMIT $2 [["id", 245], ["LIMIT", 1]]
=> #<Language id: 245, tag: "fr-FR", created_at: "2018-03-22 16:25:59", updated_at: "2018-03-22 16:25:59">
shop.languages
Language Load (1.0ms) SELECT "languages".* FROM "languages" INNER JOIN "shop_languages" ON "languages"."id" = "shop_languages"."language_id" WHERE "shop_languages"."shop_id" = $1 LIMIT $2 [["shop_id", 2], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Language id: 245, tag: "fr-FR", created_at: "2018-03-22 16:25:59", updated_at: "2018-03-22 16:25:59">]>
shop.languages.delete(lang)
(0.4ms) SAVEPOINT active_record_1
SQL (0.5ms) DELETE FROM "shop_languages" WHERE "shop_languages"."shop_id" = $1 AND "shop_languages"."language_id" = 245 [["shop_id", 2]]
(0.2ms) RELEASE SAVEPOINT active_record_1
=> [#<Language id: 245, tag: "fr-FR", created_at: "2018-03-22 16:25:59", updated_at: "2018-03-22 16:25:59">]
2.4.0 :007 > shop.languages.size
(3.5ms) SELECT COUNT(*) FROM "languages" INNER JOIN "shop_languages" ON "languages"."id" = "shop_languages"."language_id" WHERE "shop_languages"."shop_id" = $1 [["shop_id", 2]]
=> 0
所以,回调还没有被调用。 问题在于,如https://docs.microsoft.com/en-us/sql/t-sql/functions/try-cast-transact-sql中所述,
5跳过回调与验证一样,也可以 使用以下方法跳过回调:
递减decrement_counter delete delete_all
所以,如果我做对了,当我在我的收藏中调用delete
时:
shop.languages.delete(lang)
永远不会调用我的回调方法。 更多的是,Active Record或Active Model回调在返回false时不再停止,因此唯一的解决方案是使用:
throw(:abort) if shop.languages.count < 2
问题是如何正确删除表shop_languages
中的记录而不删除表languages
中的相应语言记录?运用
throw(:abort) if ...
似乎没有足够的可读性和便捷的API响应方式。
答案 0 :(得分:0)
我不确定这是否可以解决您的问题,但是您可以覆盖#destroy
:
def destroy
if ...
super
else
# no-op
end
end