【问题标题】:Rails Namespaced Model Not Triggering CallbacksRails 命名空间模型不触发回调
【发布时间】:2013-08-12 12:54:47
【问题描述】:

基本组模型:

class Group < ActiveRecord::Base
  @@ItemType = 'GroupItem' # Base ItemType
  after_initialize :default_item_type

  has_many :group_assignments
  has_many :items, through: :group_assignments, source: :groupable, source_type: @@ItemType, dependent: :destroy

  accepts_nested_attributes_for :items, allow_destroy: true

  private
  def default_item_type
    self.item_type = @@ItemType if self.new_record?
  end
end

命名空间模型:

class Gradation::Group < Group
  @@ItemType = 'Gradation' # Base ItemType
  after_initialize :default_item_type

  has_many :group_assignments
  has_many :items, through: :group_assignments, source: :groupable, source_type: @@ItemType, dependent: :destroy

  accepts_nested_attributes_for :items, allow_destroy: true
  private
  def default_item_type
    self.item_type = @@ItemType if self.new_record?
  end
end

我试图在 *after_initialize* 回调上设置一个字段 *item_type*,但无论我做什么,回调只会在常规组模型上触发,而不是在命名空间模型上触发。

我很难理解为什么这是预期的行为,以及如何让回调为命名空间Group工作。

【问题讨论】:

  • 试试这个可能有点奇怪,但是你能把private改成protected吗?如果我没记错的话,私有方法只能由模型使用,而受保护的方法可以由模型及其继承的类使用。此外,回调after_initialize 会被调用很多次!每次检索记录时都会调用它。如果要在记录的创建步骤上设置默认值,请改用before_create ;)

标签: ruby-on-rails callback rails-activerecord polymorphic-associations


【解决方案1】:

在这里使用类变量@@ItemType = 'Gradation' 不太可能帮助您。在这个问题的初始建模中,@@ItemType 互相踩踏,总是给你“渐变”

以下将起作用。您会注意到不同之处:

  1. 移动到类的常量而不是类变量
  2. 更改了周围的命名空间

app/models/group.rb

class Group < ActiveRecord::Base
  ITEM_TYPE = 'GroupItem' # Base ItemType
  after_initialize :default_item_type

  private
  def default_item_type
    self.item_type = ITEM_TYPE if self.new_record?
  end
end

app/models/group/gradation.rb

class Group::Gradation < Group
  ITEM_TYPE = 'Gradation' # Base ItemType

  private
  def default_item_type
    self.item_type = ITEM_TYPE if self.new_record?
  end
end

注意事项:

  1. 你不能在这里使用 SingleTableInheritance -- Rails 期望有一个渐变表
  2. 您必须在每个子类上定义default_item_type,以便它可以提取正确的ITEM_TYPE

要摆脱上面的#2,你可以这样做:

class Group < ActiveRecord::Base
  ITEM_TYPE = 'GroupItem' # Base ItemType
  after_initialize :default_item_type

  private
  def default_item_type
    self.item_type = "#{self.class}::ITEM_TYPE".constantize if self.new_record?
  end
end

那么,每个子类可以是:

class Group::Graduation < Group
  ITEM_TYPE = 'Graduation' # Base ItemType  
end

【讨论】:

    【解决方案2】:

    我的问题的整体解决方案是这样的……

    基组模型:

    class Group < ActiveRecord::Base
      @@ItemType = 'GroupItem' # Base ItemType
      after_initialize :default_item_type
    
      has_many :group_assignments
      has_many :items, through: :group_assignments, source: :groupable, source_type: @@ItemType, dependent: :destroy
    
      accepts_nested_attributes_for :items, allow_destroy: true
    
      private
      def default_item_type
        self.item_type = @@ItemType if self.new_record?
      end
    end
    

    ItemType 设置为另一个任意模型的子类 Group 模型(在 app/models/groups/gradation_group.rb 中):

    class Groups::GradationGroup < Group
      @@ItemType = 'Gradation'
      has_many :items, through: :group_assignments, source: :groupable, source_type: @@ItemType, dependent: :destroy
    end
    

    我的理解是我必须将命名空间更改为非类名。我还必须将组名更改为 items 关联将由其他内容组成的名称(在本例中为 Gradation)。

    【讨论】:

      猜你喜欢
      • 2012-09-10
      • 2017-03-21
      • 2011-05-23
      • 2012-07-08
      • 2012-04-18
      • 2013-05-28
      • 2014-01-29
      • 2020-09-13
      • 2012-02-16
      相关资源
      最近更新 更多