0

私は、任意のモデルがPermitasPermissibleと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

したがって、Group 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.reflect_on_all_associationsをトラバースして、新しいアソシエーション。それぞれが深いアソシエーションである可能性があります。

Rails3.2.8でこれをきれいに行う方法についての入力を探しています。

4

1 に答える 1

0

これが私が行った方法です(実装コードは、質問で指定された詳細とはわずかに異なります):

module Authorisable def self.include(base) base.class_eval do base.extend ClassMethods end end

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 で追加し、それらのシンボルをクラス インスタンス変数に格納します。

それを改善する方法についての提案を聞いてうれしいです。

于 2012-11-12T10:51:08.083 に答える