2012-12-05 5 views
1

나는 올바른 길을 가고 있는지 그리고 레일이 이런 종류의 것을 허용하는지 알고 싶습니다.레일 has_many : through, null belongs_to, 다수 belongs_to 및 belongs_to 삭제?

UserNetwork에서 하나의 Role을 갖는다. 즉 "짐"은 "학교"에서 "역사 교사"입니다.

Role에는 위치 (전원)와 이름 (레이블)이 모두 있습니다. "짐"은 "역사 교사"(레이블)이지만 회원, 관리자 또는 감독자 또는 기타 (권력)의 권한을가집니다.

RoleUser에 따라 그/그녀가 그들을 생성 여부 Network의 모든 Events을 볼 수 있습니다. Jim이 "Principal"(관리자)이지만 "Jim"이 "History Teacher"(회원) 인 경우 "Jim"은 "Nancy 's" "Recess Plan"을 볼 수 있습니다.

User은 을 내에 Role으로 생성합니다. 즉 "Jim"은 "School"에서 "History Teacher"로 "Lesson Plan"을 만듭니다.

Event 영원히 특정 Network와 현재 해당 Role에 연결되어 있습니다.

은 내가 UserRole 다른 User을 대체하는 경우 Event가 지속하고, 새로운 UserEvent에 액세스 할 수 있도록합니다. 즉 "Tom"은 "Jim"을 "History Teacher"로, "History Teacher"이기 때문에 "Lesson Plan"을 수정할 수 있습니다. "Jim"은 더 이상 "수업 계획"에 액세스 할 수 없습니다.

은 그러나 나는 또한 Role에 첨부 된 User가없는 경우 Event가 계속하고자합니다. 즉 "Tom"이 (가) 해고되고 현재 교체가 없으면 관리자는 여전히 "수업 계획"을 볼 수 있습니다. 그 Role이 삭제 된 경우 Role없이 그 Network에 연결로

마지막의 Event는 여전히 존재합니다.

모델은 내가 허가 캉캉를 사용하고, 다음과 같습니다, 이들은 나의 질문은 다음과 같습니다

  1. 것은 역할은 User 누락 수 있습니다, 또는 좀 일반적인 "없음"User 또는 "을 만들 수 없습니다해야 모두 "User? 그리고 EventRole가 누락 될 수 있습니까? (속할 수 있을까?)
  2. EventRoleNetwork에 모두 연결하는 것이 좋은가요? 이 작업을 수행하는 더 좋은 방법이 있습니까? User하면
  3. 가에 따라 더 많은 이벤트를 볼 수있는 그/그녀의 Role 그들이 가지고있는 않는 Network 또는 Role을 통해 많은 Events? 나는 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 

네트워크.기술적으로 nil 될 수 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

귀하의 협회는 괜찮으며, 당신은 null belongs_to 필드를 가질 수 있습니다. Rails는 기본적으로 데이터베이스에 외래 키 제약 조건을 작성하지 않습니다.

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 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 Role < ActiveRecord::Base 
    #... 
    scope :manager, where(position: "manager") 
    scope :admin, where(position: "admin") 
    scope :supervisor, where(position: "supervisor") 
    #... 
end 

이가 이벤트를 할 수 있습니다 마찬가지로 지금까지 캉캉 설정이가는대로, 내가 좋아하는 뭔가를 할 것입니다 네트워크에있는 모든 관리자 (또는 관리자)가 network_id으로 제한된 모든 이벤트를 관리 할 수 ​​있으므로 null role_id을 갖습니다. 또한 역할을 새 사용자에게 재 할당하면 이전 사용자는 더 이상 이벤트를 관리 할 수 ​​없으며 새 사용자가 이벤트를 관리하게됩니다.

+1

이것은 굉장합니다! 감사! – dewyze

0

첫 번째 질문 belongs_to 대답합니다. 이를 방지하려면 유효성 검사 (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이이를 요청하거나 단순히 데이터를 읽는 것 이상을 필요로한다면 다른 이야기입니다. –

관련 문제