代码之家  ›  专栏  ›  技术社区  ›  Andres

移除关系后,Rails不会清除多态类型字段

  •  0
  • Andres  · 技术社区  · 7 年前

    我有通过多态关联(可选)属于ServiceType或ServiceAddonType的项目模型:

    enter image description here

    模型

    条款

    class Article < ApplicationRecord
      belongs_to :accountable, polymorphic: true, optional: true
    end
    

    服务类型

    class ServiceType < ApplicationRecord
      has_many :articles, as: :accountable
    end
    

    服务添加类型

    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
    

    问题:

    什么时候? 添加 从文章到服务类型,一切按预期工作。多态字段获得以下值:

    accountable_id: service_type.id
    accountable_type: 'ServiceType'
    

    之后 移除 文章来自ServiceType,字段的值为:

    accountable_id: nil
    accountable_type: 'ServiceType'
    

    为什么?我怎样才能把它修好 accountable_type 也会是 nil 在解除关系之后? 我做了一个 before_save 回调到项目模型,如果 accountable_id ,但事实上,这似乎一点效果都没有( 'ServiceType' 仍然保留为'u type值)。我想这可能是因为文章更新不是通过ActiveRecord,而是在我从ServicType中删除它时通过原始SQL查询。因此回调永远不会被调用。无论如何,我也觉得应该有更好的方法来实现这一点。


    编辑1:

    正在从服务类型中删除项目:

    ServiceType表单(slim语法): 这给了我一个框,其中包含已分配给服务类型的文章列表及其复选框。通过取消选中它们并单击表单上的提交,我可以删除关系。

    - 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用强参数更新:

    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
    

    编辑2:

    我的文章模型的更完整版本和我测试的回调。当关系为 补充 但当关系是 远离的 .

    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 回复  |  直到 7 年前
        1
  •  0
  •   Maxence    7 年前

    奇怪的是,当关系被移除时,它没有被调用。不管怎样,你的回拨现在似乎什么也做不了。

    也许你可以尝试更改以下内容:

    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 但我不是把条件语句和实际任务混合起来的大粉丝。如果不是很简洁的话,我更喜欢编写非常简单的代码。。然后我们可以更进一步,这不是问题的根源

        2
  •  0
  •   Andres    7 年前

    这不是我想要的答案,但它解决了我的问题。

    我认为这是一个更广泛的铁路问题,因为 this old post this github issue . 我试过了 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