Rails не очищает полиморфное поле _type после удаления отношения - PullRequest
0 голосов
/ 08 ноября 2018

У меня есть модель Article, которая может принадлежать либо ServiceType, либо ServiceAddonType через полиморфную ассоциацию (необязательно):

enter image description here

Модель

Статья

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)

Ответы [ 2 ]

0 голосов
/ 14 ноября 2018

Это не тот ответ, который я ищу, но он решает мою проблему до сих пор.

Я предполагаю, что это более широкая проблема Rails из-за этого старого поста и этой проблемы с github . Я попробовал dependent: :nullify), и для моего Rails 5.1.6 это не сработало.

Поэтому я придумал создать ArticleConcern и включил его в модели ServiceType и ServiceAddonType. Работает по мере необходимости:

# frozen_string_literal: true

require 'active_support/concern'

module ArticleConcern
  extend ActiveSupport::Concern

  included do
    after_save -> { arrange_polymorphic_fields }
  end

  def arrange_polymorphic_fields
    Article.where(accountable_id: nil).where.not(accountable_type: nil).each do |a|
      a.update(accountable_type: nil)
    end
  end
end
0 голосов
/ 08 ноября 2018

Странно, это не вызывается, когда связь удаляется. В любом случае, ваш обратный вызов в данный момент ничего не делает.

Может быть, вы можете попробовать изменить следующее:

def arrange_polymorphic_fields
    def arrange_polymorphic_fields
      !accountable_id.present? && self.accountable_type = nil
    end
  end

до

def arrange_polymorphic_fields
   unless self.accountable_id.present?
      self.accountable_type = nil
   end
end

И снова пытаюсь удалить связь.

(На самом деле я вижу, что вы пытаетесь сделать с !accountable_id.present? && self.accountable_type = nil, но я не большой поклонник смешивания условного оператора с фактическим присваиванием. Я предпочитаю писать простой простой код, если не очень сжатый. И тогда мы можем пойти дальше не в чем проблема ..)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...