我将应用程序中的代码命名为练习。通过“运动”,我的意思完全是为了好玩。假设示例角色Performer
和Manager
代表必须与帮助方法一起定义的20个角色中的2个。
class Role
module Performer
extend ActiveSupport::Concern
module InstanceMethods
def performer?(id = @current_user_id)
true unless self.roles.where(user_id: id, name: 'Performer').empty?
end
def make_performer(id = @current_user_id)
self.roles.new(user_id: id, name: 'Performer')
end
end
end
module Manager
extend ActiveSupport::Concern
module InstanceMethods
def manager?(id = @current_user_id)
true unless self.roles.where(user_id: id, name: 'Manager').empty?
end
def make_manager(id = @current_user_id)
self.roles.new(user_id: id, name: 'Manager')
end
end
end
end
根据需要将选择角色混合到其他模块中。每个模块都混合了一组不同的角色,
class Group
module Roles
extend ActiveSupport::Concern
included do
include Role::Manager
include Role::Performer
before_create :make_creator_manager
protected
def make_creator_manager
make_manager @current_user_id if @current_user_id
end
end
end
end
然后通过多态关联与个体模型相关联。
class Group < ActiveRecord::Base
include Group::Roles
attr_accessor :current_user_id
has_many :roles, as: :restrictable
end
我可以用闭包来干掉方法的内容,但由于方法的名称也遵循一种模式,metaprogramming会更有意义吗? ruby example
元编程在红宝石中是否足够普遍,无论谁(理论上)接管这个项目都能够毫无困难地维护它?
编辑1:角色迁移可能与此讨论相关
class CreateRoles < ActiveRecord::Migration
def change
create_table :roles do |t|
t.belongs_to :user
t.references :restrictable, polymorphic: true
t.string :name
t.timestamps
end
add_index :roles, :user_id
add_index :roles, [:restrictable_id, :restrictable_type]
end
end
答案 0 :(得分:1)
这很常见,但它是否可维护更多地与您提供的文档和开发人员的心态有关。
理想情况下,元编程会消失在应用程序中,很少需要触及。为此,它会做同样的事情 - 做出特定于角色的方法。元编程本身有多大可能需要维护?
只要有一条路径来自“嘿,那个功能来自哪里?”对于注入功能的代码,我认为这很好,特别是因为此功能的“元”范围非常有限。
我看到的唯一潜在问题是需要明确定义法律角色名称的样子,并确保它显然是什么方法名称,如果它不是简单的alpha字符,它将映射到哪个。
答案 1 :(得分:0)
看起来真的很复杂,你确定没有更简单的方法吗?
首先,看起来像STI(单表继承)或只是常规oo继承(如果你没有使用活动记录)会更合适:
user.type?(Manager)
代替manager?(user_id)
和
user.update_attributes(:type => 'Manager')
代替make_manager(user_id)
如果您要进行元编程,我现在会使用它来修改method_missing
以将上述方法转发到user.manager?
和user.make_manager!
。