【问题标题】:Automatically create associations through many existing associations通过许多现有关联自动创建关联
【发布时间】:2012-10-25 23:23:30
【问题描述】:

我正在开发一个引擎,其中任何模型都可以与 Permit as Permissible 建立 has_many 关联:

class Permit < ActiveRecord::Base
  belongs_to :permissible, polymorphic: true
end

module Permissible
  def self.included(base)
    base.class_eval do
    has_many :permits, as: :permissible
  end
end

class Group < ActiveRecord::Base
  include Permissible
end

class GroupAllocation < ActiveRecord::Base
  belongs_to :person
  belongs_to :group
end

class Person < ActiveRecord::Base
  include Permissible
  has_many :group_allocations
  has_many :groups, through: :group_allocations
end

class User < ActiveRecord::Base
  belongs_to :person
end

所以,组 has_many :permits 和 Person has_many :permits。我正在尝试做的是在使用许可关联作为源的用户上动态创建关联,并通过执行相同操作将其他模型上的关联链接到用户。这可以通过以下方式手动完成(在 rails 3.1+ 中):

class Person
  has_many :group_permits, through: :person, source: :permits
end

class User
  has_many :person_permits, through: :person, source: :permits, class_name: Permit
  has_many :person_group_permits, through: :person, source: :group_permits, class_name: Permit
end

然而,在实践中,Permissible 将包含在许多模型中,所以我试图在 User 上编写一个类方法(实际上是在另一个模块中,但不需要更多混淆),它可以遍历 User.reflect_on_all_associations 并创建一组新关联,每个关联可能有很多深度。

寻找有关如何在 rails 3.2.8 中干净利落地执行此操作的意见。

【问题讨论】:

    标签: ruby-on-rails dynamic associations ruby-on-rails-3.2 has-many-through


    【解决方案1】:

    我是这样做的(实现代码与问题中给出的细节略有不同):

    模块可授权 def self.included(base) base.class_eval 做 base.extend 类方法 结尾 结束

    module ClassMethods
      class PermissionAssociationBuilder
        def build_permissions_associations(klass)
          chains = build_chains_from(klass)
          chains.select! {|c| c.last.klass.included_modules.include? DistributedAuthorisation::Permissible}
          permissions_associations = []
          chains.each do |chain|
            source_name = :permissions
            chain.reverse.each do |r|
              assoc_name = :"#{r.name}_#{source_name}"
              r.active_record.has_many assoc_name, through: r.name.to_sym, source: source_name, class_name: DistributedAuthorisation::Permission
              source_name = assoc_name
            end
            permissions_associations << source_name
          end
          return permissions_associations
        end
    
        private
    
        def build_chains_from(klass)
          chains = reflections_to_follow(klass).map {|r| [r]}
          chains.each do |chain|
            models = chain.map {|r| r.klass}.unshift klass
            reflections_to_follow(models.last).each do |r|
              chains << (chain.clone << r) unless models.include? r.klass
            end
          end
        end
    
        def reflections_to_follow(klass)
          refs = klass.reflect_on_all_associations
          refs.reject {|r| r.options[:polymorphic] or r.is_a? ActiveRecord::Reflection::ThroughReflection}
        end
      end
    
      def permissions_associations
        @permissions_associations ||= PermissionAssociationBuilder.new.build_permissions_associations(self)
      end
    end
    

    可能不是最有效的方法,但它使用 Klass.permissions_associations 添加了我想要的链,并将它们的符号存储在类实例变量中。

    我很高兴听到有关如何改进它的建议。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-01-12
      • 1970-01-01
      • 1970-01-01
      • 2017-07-21
      • 1970-01-01
      • 1970-01-01
      • 2017-11-12
      相关资源
      最近更新 更多