2012-12-05 93 views
1

我想知道我是否在正確的軌道上,如果軌道允許這種事情。Rails has_many:通過,歸屬belongs_to,多個belongs_to並刪除belongs_to?

User有一個RoleNetwork。即「吉姆」是「學校」中的「歷史教師」。

A Role同時具有位置(功率)和名稱(標籤)。 「吉姆」是一名「歷史教師」(標籤),但具有成員或管理員,主管或任何權力的權力。

根據Role的不同,User可以在Network中看到全部Events,無論他/她是否創建了它們。即如果「Jim」是「Principal」(管理員),而「Jim」是「歷史教師」(成員),則「Jim」可以看到「Nancy的」「Recess Plan」。

A UserNetwork內創建Event作爲Role。即「吉姆」在「學校」創建「課程計劃」作爲「歷史教師」。

Event永遠連接到那個特定的Network,並且目前是那個Role

我想這Event堅持如果User取代另一個UserRole,新User可以訪問Event。即「湯姆」代替「吉姆」作爲「歷史教師」,並可以修改「教案」,因爲他是「歷史教師」。 「Jim」無法再訪問「課程計劃」。

但是,如果沒有User附加到Role,我也希望Event持續。即「湯姆」被解僱,並且目前沒有替換,管理員仍然可以看到「課程計劃」。

最後,如果該Role被刪除,Event仍然存在連接到Network沒有Role

型號有以下,我使用慘慘的授權,而這些是我的問題:

  1. 能作用缺少一個User,或者我需要創建一些通用的「無」 User或者「每個人「User?並且Event可能會丟失Role? (可否屬於空?)
  2. Event連接到RoleNetwork是好還是不好設計?有一個更好的方法嗎?
  3. 如果一個User可以看到更多的事件,具體取決於他/她的Role他們有很多EventsNetwork或他們的Role?我想通過Network和Ability.rb會限制它。

User.rb

class User < ActiveRecord::Base 
    has_many :roles 
    has_many :networks, :through => :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 

網絡。RB

class Network < ActiveRecord::Base 
    has_many :roles 
    has_many :users, :through => :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 < ActiveRecord::Base 
    belongs_to :role  #Can this be null? 

    belongs to :network 
    # Does it belong to the network through the role, 
    # or can it belong on its own, in case the role is deleted? 

    # belongs_to :user, :through => :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 
+0

你的問題真的很重 - 你可以通過將問題分解成更容易解釋的小問題來得到更好的迴應 – aguynamedloren

+0

謝謝,將會做到。我一直在想如何做到這一點,並不確定,但生病嘗試。 – dewyze

回答

3

你的關聯是好的,你可以有空的belongs_to字段。 Rails默認情況下不會在數據庫上創建外鍵約束。至於康康舞設置得好,我會做這樣的事情:

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 

這使你的活動,有空role_id,因爲您將允許網絡上的任何管理員(或管理員)管理所有事件,受到network_id的限制。另外,如果您將角色重新分配給新用戶,則舊用戶將不能再管理該事件,而新用戶將會無法管理該事件。

+1

這真棒!謝謝! – dewyze

0

要回答你的第一個問題belongs_to技術上可以nil。你必須進行驗證(validates_presence_of)以避免這種情況。

我不知道CanCan但在概念層面上,我不會爲了能夠訪問數據而編寫如此多的關聯。 Rails協會不僅僅是一個數據讀取器,我不確定你在這裏需要每個案例。

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 

你可以添加一些記憶化,如果你調用這個方法不止:

例如,用戶#事件可以被替代一旦。事實上,如果你只需要調用一次,那麼你幾乎不需要一種方法。

關於將事件同時關聯到角色和網絡,我會很小心,因爲您可能有一致性問題(您必須確保event.role.network == event.network)。另一種方法是爲每個網絡設置一個無法銷燬的默認角色。但它可能並不簡單。

+0

爲什麼你不使用內置的關聯?使用'has_many through:'不僅僅是一個訪問器。 –

+0

是的,我不確定用戶和事件之間實際上是否存在關聯。關鍵在於用戶可以訪問事件,因爲他們的角色直接與事件相關,或者因爲他們在網絡中的訪問權限足夠高,可以讓他們看到網絡的所有事件。這是否會改變我將使用該方法的方式? Can Can基本上只能用來檢查是否顯示所有事件,或者只顯示個人事件。它會阻止訪問。這是一個非常有用的寶石,但它在關於聯想方面讓我感到困惑。 – dewyze

+0

@SeanHill我不是一個Rails專家,但是讓模型架構更加複雜,只是爲了避免單行查詢對我來說似乎有點矯枉過正。請求的功能聽起來像是一個範圍,而不是一個真正的關聯。至少,我會將這些關聯特別記錄爲便捷的訪問者。除此之外,如果CanCan要求這樣做,或者如果我們需要的不僅僅是閱讀數據,那是另一回事。 –