1

Я использую Active Admin, поэтому adminuser может создавать/удалять категории, ярлыки и продукты.PG :: ForeignKeyViolation При удалении категорий/ярлыков в Active Admin

Я могу создать Labels, Categories и Products без каких-либо проблем, но когда я хочу, чтобы удалить ярлыки или категории Я всегда получаю эту ошибку:

PG::ForeignKeyViolation at /admin/labels/2

ERROR: update or delete on table "labels" violates foreign key constraint "fk_rails_5a55c39b94" on table "products" 
DETAIL: Key (id)=(2) is still referenced from table "products". 

И если я пытаюсь уничтожить продукт Я получаю это сообщение со вспышкой Product could not be destroyed.

Мне кажется, что я получаю эту ошибку при удалении labels или categories, которые относятся к продукту.

Я не уверен, что нужно сделать, чтобы исправить это

Ниже приведен соответствующий код

app/admin/product.rb

ActiveAdmin.register Product do 

permit_params :title, :description, :image, :price_usd, :price_isl, :category_id, :label_id 

index do 
    column :title 
    column :category 
    column :label 
    column :created_at 

    column :price_isk, :sortable => :price_isl do |product| 
     number_to_currency(product.price_isl, :unit => "ISK " , :precision => 0) 
    end 
    column :price_euro, :sortable => :price_usd do |product| 
     number_to_currency(product.price_usd, :unit => "€ " , :precision => 0) 
    end 

    actions 
end 
end 

app/admin/label.rb

ActiveAdmin.register Label do 
permit_params :name 
end 

app/admin/category.rb

ActiveAdmin.register Category do 
permit_params :name 
end 

И в app/models/product.rb

class Product < ActiveRecord::Base 
belongs_to :category 
belongs_to :label 

has_many :product_item 

before_destroy :ensure_not_product_item 

    validates :title, :description, presence: true 
    validates :price_usd, :price_isl, numericality: {greater_than_or_equal_to: 0.01} 
    validates :title, uniqueness: true 

has_attached_file :image, styles: { medium: "500x500#", thumb: "100x100#" } 
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/ 

def ensure_not_product_item 
    if product_item.empty? 
     return true 
    else 
     errors.add(:base, 'You have Product Items') 
     return false 
    end 

end 
end 

и app/models/label.rb

class Label < ActiveRecord::Base 
    has_many :products 
    has_many :pages 
end 

и app/models/category.rb

class Category < ActiveRecord::Base 
    has_many :products 
end 

и app/models/product_items.rb

class ProductItem < ActiveRecord::Base 
belongs_to :product 
belongs_to :cart 
belongs_to :order 


def total_price_usd 
    product.price_usd * quantity 
end 

def total_price_isl 
    product.price_isl * quantity 
end 

end 

ответ

2

Вы хотите обновить свои ассоциации has_many, чтобы сообщить ActiveRecord, что делать, когда вы уничтожаете Label или Category.Похоже, вы хотите, чтобы просто свести на нет label_id или category_id в соответствующем Product S так:

class Label < ActiveRecord::Base 
    has_many :products, :dependent => :nullify 
    has_many :pages 
end 
class Category < ActiveRecord::Base 
    has_many :products, :dependent => :nullify 
end 

Не уверен, что вы хотите сделать около Page сек, когда вы уничтожите Label, если вы хотите обновить их, чтобы не label_id затем:

has_many :pages, :dependent => :nullify 

, если вы хотите, чтобы уничтожить Page сек, то:

has_many :pages, :dependent => :destroy 

Аналогично для has_many :product_item в Product. Если вы хотите уничтожить предметы, уничтожая продукт затем:

  1. Отбросьте before_destroy :ensure_not_product_item и метод ensure_not_product_item.
  2. Обновление ассоциации до has_many :product_items, :dependent => :destroy.

Если вы хотите, чтобы они вручную уничтожали предметы перед продуктом, оставите то, что у вас есть.


Основная проблема заключается в том, что у вас есть ограничения внешнего ключа внутри базы данных, чтобы гарантировать, что products.label_id и products.category_id столбцы всегда ссылаться на действительные categories.id значения. Если вы удаляете строку из categories (т. Е. Уничтожаете экземпляр Category), но есть строки в products, которые по-прежнему ссылаются на эту категорию, тогда база данных жалуется, потому что вы пытаетесь нарушить ограничение внешнего ключа и оставляете сломанные данные внутри вашей базы данных.

FK внутри базы данных - хорошая идея, потому что она не позволяет вам нарушать ссылки в вашей базе данных, но вам нужно правильно очистить ее.

+0

Это замечательно .... но как насчет того, что «Продукт не может быть уничтожен?», Когда я пытаюсь уничтожить продукты, а не ярлыки или каноны? – Slowboy

+1

Да, я его отвечу, если это сработает, я думаю, что это лучший способ сделать это ... – Eric

+1

Возможно, вы захотите отказаться от 'before_destroy: обеспечить_not_product_item' и сказать' has_many: product_item,: dependent =>: destroy'. Это уничтожит предметы при уничтожении продукта. Это только предположение, но реальное решение зависит от ваших бизнес-требований. –

1

Вы можете установить для label_id или category_id в таблице продуктов значение nil при удалении категории. С верхней части моей головы, но, возможно, что-то вроде:

Категория Модель:

before_destroy :remove_category_from_products 

private 

def remove_category_from_products 
    Product.where(category_id: id).update_all(category_id: nil) 
end 

Я имею в виду, у меня нет большого контекста на бизнес-логики в вашем приложении, но это должно сделать так, вы больше не видите эту ошибку ...

+0

Я получаю его, но не ... если я добавлю это в модель, я получаю эту ошибку сейчас: 'uninitialized constant Category :: Products' в этой строке' Products.where (category_id: id) .update_all (category_id: nil) ' – Slowboy

+0

И' before_delete' должен быть 'before_destroy' :) – Slowboy

+0

crap, это должен быть продукт, а не продукт' Product.where (category_id: id) .update_all (category_id: nil) ' – Eric