У меня есть модель Article, которая может принадлежать либо ServiceType, либо ServiceAddonType через полиморфную ассоциацию (необязательно):
Модель
Статья
class Article < ApplicationRecord
belongs_to :accountable, polymorphic: true, optional: true
end
ServiceType
class ServiceType < ApplicationRecord
has_many :articles, as: :accountable
end
ServiceAddonType
class ServiceAddonType < ApplicationRecord
has_many :articles, as: :accountable
end
Миграция статьи
class CreateArticles < ActiveRecord::Migration[5.1]
def change
create_table :articles, id: :uuid do |t|
t.references :accountable, polymorphic: true, index: true, type: :uuid
end
end
end
Проблема:
Когда добавляет Article к ServiceType, все работает как положено. Полиморфные поля получают следующие значения:
accountable_id: service_type.id
accountable_type: 'ServiceType'
После удаления Article из ServiceType, значения полей:
accountable_id: nil
accountable_type: 'ServiceType'
Почему? Как я могу исправить это так, чтобы accountable_type
также было nil
после удаления отношения?
Я сделал обратный вызов before_save
к модели Article, который очистил бы поле, если accountable_id
равен nil
, но на самом деле это, похоже, вообще не оказывает никакого влияния ('ServiceType'
все еще остается как значение _type). Я полагаю, это может быть связано с тем, что обновление статьи происходит не через ActiveRecord, а через необработанный SQL-запрос при удалении его из ServicType. Поэтому обратный вызов никогда не вызывается. Во всяком случае, я также считаю, что должны быть лучшие способы для достижения этой цели.
EDIT1:
Удаление статьи из service_type:
Форма ServiceType (тонкий синтаксис):
Это дает мне окно со списком статей и их флажками, которые уже присвоены типу сервиса. Сняв флажок и нажав «Отправить» в форме, я могу удалить отношение.
- if service_type.persisted?
.square-box.small-12.medium-5
- if service_type.articles.present?
h5= t('article.assigned')
= f.association :articles, collection: service_type.articles, as: :check_boxes, label: false
- else
= t('service_type.no_articles_assigned_yet')
Обновление ServiceTypeController # с помощью strong_params:
def update
if @service_type.update(service_type_params)
redirect_to service_types_path, notice: t(
'service_type.successful_update',
service_type_name: @service_type.name
)
else
redirect_to edit_service_type_path(@service_type), alert: @service_type.errors.full_messages.join(', ')
end
end
private
def service_type_params
params.require(:service_type).permit(:name, article_ids: [])
end
EDIT2:
Более полная версия моей статьи-модели с обратным вызовом, который я тестировал. Обратный вызов фактически вызывается, когда отношение добавлено , но не вызывается, когда отношение удалено .
class Article < ApplicationRecord
belongs_to :accountable, polymorphic: true, optional: true
default_scope { order(:name) }
before_save :arrange_polymorphic_fields
private
def arrange_polymorphic_fields
def arrange_polymorphic_fields
!accountable_id.present? && self.accountable_type = nil
end
end
end
Журнал Rails удаления статьи из сервисного типа:
Started PATCH "/service_types/acfe9618-69d4-4564-9ab5-65a50dc4b26a" for 127.0.0.1 at 2018-11-08 16:23:57 +0200
Processing by ServiceTypesController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"bbBWybKuXcwcYVZZqcL88VRY1U6puY9rz2TczyNEghlM+WIIf46lGtNYBk+sUITtLzhHWcNZl1FJL9s630rOgw==", "service_type"=>{"name"=>"Service-type 1", "article_ids"=>["", "8c2d53d8-9016-4e7b-85c8-d111797aa9d0", "84573dc7-c532-4055-a43d-ef5917cf1ec0", "0dc6da24-c221-4c24-9b22-c39b2f82a9d5", "f6a4dd0d-17bf-4bfd-9cc5-d871d23ad727", "25b25ed1-e4ae-43a6-87e7-f346def15aa5"]}, "id"=>"acfe9618-69d4-4564-9ab5-65a50dc4b26a"}
ServiceType Load (0.9ms) SELECT "service_types".* FROM "service_types" WHERE "service_types"."id" = $1 ORDER BY "service_types"."name" ASC LIMIT $2 [["id", "acfe9618-69d4-4564-9ab5-65a50dc4b26a"], ["LIMIT", 1]]
(0.5ms) BEGIN
Article Load (1.2ms) SELECT "articles".* FROM "articles" WHERE "articles"."id" IN ('8c2d53d8-9016-4e7b-85c8-d111797aa9d0', '84573dc7-c532-4055-a43d-ef5917cf1ec0', '0dc6da24-c221-4c24-9b22-c39b2f82a9d5', 'f6a4dd0d-17bf-4bfd-9cc5-d871d23ad727', '25b25ed1-e4ae-43a6-87e7-f346def15aa5') ORDER BY "articles"."name" ASC
Article Load (1.1ms) SELECT "articles".* FROM "articles" WHERE "articles"."accountable_id" = $1 AND "articles"."accountable_type" = $2 ORDER BY "articles"."name" ASC [["accountable_id", "acfe9618-69d4-4564-9ab5-65a50dc4b26a"], ["accountable_type", "ServiceType"]]
SQL (1.7ms) UPDATE "articles" SET "accountable_id" = NULL WHERE "articles"."id" IN (SELECT "articles"."id" FROM "articles" WHERE "articles"."accountable_id" = $1 AND "articles"."accountable_type" = $2 AND "articles"."id" = '542803bf-73ee-496f-a7e7-077858925245' ORDER BY "articles"."name" ASC) [["accountable_id", "acfe9618-69d4-4564-9ab5-65a50dc4b26a"], ["accountable_type", "ServiceType"]]
ServiceType Exists (1.2ms) SELECT 1 AS one FROM "service_types" WHERE "service_types"."name" = $1 AND ("service_types"."id" != $2) LIMIT $3 [["name", "Service-type 1"], ["id", "acfe9618-69d4-4564-9ab5-65a50dc4b26a"], ["LIMIT", 1]]
(2.4ms) COMMIT
Redirected to http://localhost:3000/service_types
Completed 302 Found in 31ms (ActiveRecord: 9.1ms)