2016-03-23 8 views
0

Ich habe in diesem SO question untersucht, aber ich habe immer noch Probleme, meinen Kopf um das Konzept zu wickeln.ActiveRecord has_many und gehört_to auf dem gleichen Modell

Ich habe eine ähnliche Einrichtung mit der verknüpften SO Frage, in der ich eine User Klasse, die sowohl Mitarbeiter und Manager enthält. Ich habe auch ein anderes Modell für Role (mit den Rollennamen) und UserRole (mit welchem ​​Benutzer welche Rolle).

angeben Meine Anforderungen, dass ein Mitarbeiter (a User deren Role ist User) kann nur einen Geschäftsführer haben (a User deren Role ist Manager). Jetzt ist dieses Managering-Konzept eine Ergänzung zum aktuellen System, und ich sollte die users Tabelle nicht ändern, also mache ich eine neue Tabelle mit ihrer eigenen MVC.

Aber jetzt finde ich es schwierig, has_many und belongs_to wie die verknüpfte Frage zu verwenden. Wie verwende ich das neue Modell? Ich habe versucht mit :through, aber es funktioniert nicht (aus irgendeinem Grund).

Mache ich es falsch? Soll ich einfach eine manager_id Spalte zu users hinzufügen und die Lösung in der verknüpften Frage in mein Problem einbauen? Wie stelle ich außerdem sicher, dass nur ein User, dessen RoleManager ist, als Manager festgelegt werden kann?

Hinweis: Ich muss sagen, dass ich relativ neu zu Rails und ActiveRecord und sogar Ruby im Allgemeinen bin.

Hinweis 2: Ich verwende Rails 4.2.0, wenn es relevant ist.

Antwort

0

eine viele zu viele System mit Rollen ist ziemlich geradlinig einrichten:

class User 
    has_many :user_roles 
    has_many :roles, through: :user_roles 

    def has_role?(role) 
    roles.where(name: role).any? 
    end 
end 

class Role 
    has_many :user_roles 
    has_many :users, through: :user_roles 
end 

class UserRole 
    belongs_to :role 
    belongs_to :user 
    validates_uniqueness_of :role, :user 
end 

So stellen Sie sicher, dass Sie einen eindeutigen Index für die Rolle auf Userrole erstellen und Benutzer :

add_index :user_roles, [:role_id, :user_id], unique: true 

Die einfachste und performante Art und Weise der Manager Anforderung umzusetzen wäre eine mananger_id Spalte users und Setup hinzuzufügen eine sich selbst verweis one to many Beziehung:

class User 
    has_many :user_roles 
    has_many :roles, through: :user_roles 

    belongs_to :manager, class_name: 'User' 
    has_many :subordinates, foreign_key: :manager_id, class_name: 'User' 

    validate :authorize_manager! 

    def has_role?(role) 
    roles.where(name: role).any? 
    end 

    private 
    def authorize_manager! 
    if manager.present? 
    errors.add(:manager, "does not have manager role") unless manager.has_role?("manager") 
    end 
    end 
end 

Ein anderer Weg, dies zu tun wäre, um Ressourcen Rollen scoped zu verwenden. Der beste Teil ist, dass Sie es nicht selbst gebaut haben. Es gibt ein ausgezeichnetes Juwel, das von der Community erstellt wurde, die Sie mit einem solchen System einrichtet.

Es ist auch ein bisschen flexibler als das ehemalige System, sobald Sie einen Hang davon bekommen, können Sie Rollen zu jeder Art von Ressource in Ihrer Domäne hinzufügen.

class User < ActiveRecord::Base 
    rolify 
    resourcify 
end 

--- 

the_boss = User.find(1) 
bob = User.find_by(name: 'Bob') 

# creating roles 
the_boss.add_role(:manager) # add a global role 
the_boss.add_role(:manager, bob) # add a role scoped to a user instance 

# querying roles 
bob.has_role?(:manager) # => false 
the_boss.has_role?(:manager) # => true 
the_boss.has_role?(:manager, bob) # => true 
the_boss.has_role?(:manager, User.create) # => false 

Wenn Sie mit Rolify gehen Kompliment es mit einer Genehmigung Bibliothek wie Pundit oder CanCanCan die Regeln zu erzwingen.

+0

Ich sollte nicht die 'users' Tabelle bearbeiten, aber wenn die andere Option noch ein weiteres Juwel hinzufügt, ist vielleicht eine neue Spalte nicht so eine schlechte Idee. – StorymasterQ

+0

Ich denke, ich gehe mit der Spalte 'manager_id'. Wie bekomme ich den neu eingefügten Manager-Namen für die Fehlermeldung? EDIT: Nevermind, habe ich herausgefunden 'manager.name'. – StorymasterQ

+0

"Ein weiteres Juwel hinzuzufügen" ist nicht immer schlecht. Erfinden Sie das Rad nicht aus Angst vor der technischen Schuld oder dem hier nicht erfundenen Syndrom. – max

0
class User < ActiveRecord::Base 
    belongs_to :manager, class_name: 'User' 
    has_many :employees, foreign_key: :manager_id, class_name: 'User' 
end 

Hilft es?

Update:

class User < ActiveRecord::Base 
    has_one :role, through: :user_role 
    belongs_to :manager, -> { where(role: {name: 'manager'}), class_name: 'User' 
    has_many :employees, -> { where(role: {name: 'employee'}), foreign_key: :manager_id, class_name: 'User' 
end 
+0

Das ist die verknüpfte Frage Lösung, aber ich kann es nicht funktionieren. Wie bringe ich den neuen Tisch in den Verein? – StorymasterQ

+0

Was ist mit diesem Update? Nicht sicher, das ist es, was Sie erreichen wollen, aber Sie sollten vielleicht einen Blick auf diese Art von Struktur werfen. –

+0

Hm, also sollte/muss ich eine 'manager_id' Spalte zur' users' Tabelle hinzufügen? – StorymasterQ

Verwandte Themen