Rails has_many:through,null belongs_to,multiple belongs_to和belongs_to的删除?

我想知道我是否在正确的轨道上,如果rails允许这种事情。

UserNetwork具有一个Role 。 即“吉姆”是“学校”的“历史老师”。

Role具有位置(权力)和名称(标签)。 “吉姆”是“历史老师”(标签),但拥有会员或管理员,主管或其他(权力)的权力。

根据该RoleUser可以查看Network所有Events ,无论他/她是否创建了这些事件。 即如果“吉姆”是“校长”(管理员),“吉姆”可以看到“南希”的“rest计划”,但如果“吉姆”是“历史老师”(成员)则不能。

UserEvent创建为NetworkRole 。 即“吉姆”在“学校”创建“课程计划”作为“历史老师”。

Event永远连接到该特定Network并且当前连接到该Role

如果User替换该Role其他User ,并且新User可以访问该Event ,我希望该Event持续存在。 即“汤姆”取代“吉姆”作为“历史老师”,并可以修改“课程计划”,因为他是“历史老师”。 “吉姆”无法再访问“课程计划”。

但是如果没有User附加到Role我也希望Event持续存在。 即“汤姆”被解雇并且没有当前替换,管理员仍然可以看到“课程计划”。

最后,如果删除了该Role ,则Event仍然存在,因为它连接到没有Role Network

模型如下,我使用CanCan进行授权,这些是我的问题:

  1. 角色可以缺少User ,还是需要创建一些通用的“无” User或“所有人” UserEvent可以错过Role吗? (可以belongs_to为null吗?)
  2. Event连接到RoleNetwork是好/坏设计? 有一个更好的方法吗?
  3. 如果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 )。 另一种方法是为每个网络提供一个无法销毁的默认角色。 但它可能并不简单。