Rails has_many:through,null belongs_to,multiple belongs_to和belongs_to的删除?
我想知道我是否在正确的轨道上,如果rails允许这种事情。
User
在Network
具有一个Role
。 即“吉姆”是“学校”的“历史老师”。
Role
具有位置(权力)和名称(标签)。 “吉姆”是“历史老师”(标签),但拥有会员或管理员,主管或其他(权力)的权力。
根据该Role
, User
可以查看Network
所有Events
,无论他/她是否创建了这些事件。 即如果“吉姆”是“校长”(管理员),“吉姆”可以看到“南希”的“rest计划”,但如果“吉姆”是“历史老师”(成员)则不能。
User
将Event
创建为Network
的Role
。 即“吉姆”在“学校”创建“课程计划”作为“历史老师”。
Event
永远连接到该特定Network
并且当前连接到该Role
。
如果User
替换该Role
其他User
,并且新User
可以访问该Event
,我希望该Event
持续存在。 即“汤姆”取代“吉姆”作为“历史老师”,并可以修改“课程计划”,因为他是“历史老师”。 “吉姆”无法再访问“课程计划”。
但是如果没有User
附加到Role
我也希望Event
持续存在。 即“汤姆”被解雇并且没有当前替换,管理员仍然可以看到“课程计划”。
最后,如果删除了该Role
,则Event
仍然存在,因为它连接到没有Role
Network
。
模型如下,我使用CanCan进行授权,这些是我的问题:
- 角色可以缺少
User
,还是需要创建一些通用的“无”User
或“所有人”User
?Event
可以错过Role
吗? (可以belongs_to为null吗?) - 将
Event
连接到Role
和Network
是好/坏设计? 有一个更好的方法吗? - 如果
User
可以根据他/她的Role
看到更多事件,他们通过Network
或他们的Role
有很多Events
吗? 我在思考Network
,而Ability.rb会限制它。
User.rb
class User :roles has_many :events, :through => :network # I would use CanCan to determine the authorization of # what network events they can see based on their role? end
Network.rb
class Network :roles has_many :events # it shouldn't have this through roles right? # because a role can be deleted end
Role.rb
class Role < ActiveRecord::Base belongs_to :user #CAN THIS BE NULL? belongs_to :network end
Event.rb
class Event :roles # Is this necessary if I am using CanCan # to determine if a User can reach the event? end
Ability.rb
if user user.roles.each do |role| can :manage, Event, :role_id => role.id if role.position == "admin" || role.position == "manager" can :manage, Event, :network_id => role.network_id elseif role.position == "supervisor" can :read, Event, :network_id => role.network_id end end end
你的关联很好,你可以拥有null belongs_to
字段。 默认情况下,Rails不会在数据库上创建外键约束。 就CanCan设置而言,我会做类似的事情:
class Ability include CanCan::Ability def initialize(user) #Adding can rules do not override prior rules, but instead are logically or'ed. #See: https://github.com/ryanb/cancan/wiki/Ability-Precedence #Anything that you can pass to a hash of conditions in Active Record will work here. #The only exception is working with model ids. #You can't pass in the model objects directly, you must pass in the ids. #can :manage, Project, :group => { :id => user.group_ids } #See https://github.com/ryanb/cancan/wiki/Defining-Abilities can :read, Event, network: {id: user.supervises_network_ids} can :manage, Event, role: {id: user.role_ids} can :manage, Event, network: {id: user.manages_network_ids + user.admins_network_ids} end end
你在哪里:
class User < ActiveRecord::Base #... def manages_network_ids @manages_network_ids ||= roles.manager.collect &:network_id end def admins_network_ids @admins_network_ids ||= roles.admin.collect &:network_id end def supervises_network_ids @supervises_network_ids ||= roles.supervisor.collect &:network_id end #... end
在角色上你有:
class Role < ActiveRecord::Base #... scope :manager, where(position: "manager") scope :admin, where(position: "admin") scope :supervisor, where(position: "supervisor") #... end
这允许您的Event具有null role_id
,因为您将允许网络上的任何管理员(或管理员)管理受network_id
约束的所有事件。 此外,如果您将角色重新分配给新用户,则旧用户将无法再管理该事件,而新用户将无法管理该事件。
要回答你的第一个问题, belongs_to
在技术上可以是nil
。 您必须进行validation( validates_presence_of
)以避免这种情况。
我不知道CanCan但是,从概念层面来说,我不会为了能够访问数据而写出这么多关联。 Rails协会不仅仅是一个数据阅读器,我不确定你在这里每个案例都需要它。
例如,User#events可以替换为:
def events roles.includes(:events).map(&:events).flatten end
要么
def events Event.where(:role_id => roles.map(&:id)) end
要么
def events Event.joins(:role).where(:role => {:user_id => id}) end
如果多次调用此方法,可以添加一些memoization。 事实上,如果你只召唤一次,你几乎不需要一种方法。
关于将事件关联到角色和网络,我会小心,因为您可能存在一致性问题(您必须确保event.role.network == event.network
)。 另一种方法是为每个网络提供一个无法销毁的默认角色。 但它可能并不简单。