我正在开发一个引擎,其中任何模型都可以与Permit允许具有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:permit和person has_many:permit。我想要做的是在User上动态创建关联,使用许可关联作为源,并通过执行相同操作将其他模型上的链关联下载到User。这可以通过以下方式手动完成(在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
然而,在实践中,允许将包含在许多模型中,所以我试图在User上编写一个类方法(实际上在另一个模块中,但不需要混淆更多),可以遍历User.reflect_on_all_associations并创建一系列新的关联,每个关联可能有很多关联。
在rails 3.2.8中寻找关于如何干净地完成此操作的输入。
答案 0 :(得分:0)
以下是我的做法(实施代码与问题中给出的细节略有不同):
模块可授权 def self.included(base) base.class_eval做 base.extend ClassMethods 结束 端
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添加了我之后的链,并将它们的符号存储在类实例变量中。
我很乐意听到有关如何改进它的建议。