【问题标题】:Rails employer and employee deviseRails 雇主和雇员设计
【发布时间】:2012-06-25 20:42:32
【问题描述】:

我正在尝试弄清楚如何构建它,请帮助: 我需要用户能够注册为雇主或雇员。雇主基本上是公司,雇员是从事该工作的人。我想知道如何记录员工何时/是否被雇用和终止工作。 has_many:through 协会会为此工作还是更好,但有没有我忽略的宝石可以帮助我解决这个问题?

【问题讨论】:

  • 您研究过 STI(单表继承)吗?
  • STI 表示单独表中可能无法使用的重复字段
  • Yasky,“可能无法使用”是怎么回事?这是一个家庭作业问题吗?如果是就好了;大多数人仍然会给你解决问题的建议,但你不妨把所有的牌都摆在桌面上。否则,您可能会不断得到无法使用的答案。

标签: ruby-on-rails ruby ruby-on-rails-3.1 devise sti


【解决方案1】:

这是分层对象模型的经典案例,因此您必须根据所涉及的对象以及它们之间的关系来考虑这个问题。想想企业在现实生活中的运作方式:

雇主 -> 雇员不是雇主 -> 经理等 -> 雇员

这种系统模型的一个很好的例子是 GitHub。在 GitHub 上,用户可以属于组织。他们还可以创建并管理它们,管理成员等(在您的情况下雇用和解雇)。因此,对这个系统进行建模的更好方法是以用户为中心,而不是拆分两个不同的用户类别。

如之前的回答中所述,雇主(或本文中的企业) 感觉)不应被视为系统的用户,因为他们不会 用户会根据程序的状态进行操作。因此,我个人认为 STI 是 这个系统模型有点矫枉过正。

所以...

所有受雇于企业的人都是员工,但并非所有员工都拥有相同级别的权限(例如,经理将比初级员工拥有更多权限)。因此,您应该为Business 建模,它有很多 Employees。那些Employees 将根据他们的职位拥有不同级别的权限:

  • can_hire?
  • can_fire?

您还可以创建一个方法来告诉您此 Employee 何时被雇用/解雇。如果他们被雇用/解雇,这些可能会返回日期/时间,如果不是,则返回 nilnil 在这个意义上显然意味着他们还没有被雇用/解雇。

在管理不同用户的能力时,他们的权限级别由他们可以做什么和不能做什么来定义。您当然可以通过检查上述方法的简单方法将预设角色应用于这种情况。例如:

def manager?
  self.can_hire? and self.can_fire?
end

然后,您还可以定义允许创建业务的能力:

def can_create_business?
  self.manager?
end

注意:您可以使用范围来优雅地实现这一点。

您还可以为您的角色创建一个基本用户模型的子类,或者创建一个角色类来定义上述方法并作用于给定的用户模型。然后,您可以创建单个角色和角色子集。

可以说,在某些情况下,允许将雇主/企业和雇员创建为可以对计划状态采取行动的独立实体是有用的。如果Business 可以执行的不仅仅是简单的管理功能,那么这可能是值得的。在这种情况下,我仍然不会将业务视为用户模型。我需要创建一个特殊的用户帐户以及 Business,它的角色为 Business Administrator 或类似的东西。

此模型总体上遵循编程和计算机科学中的一些最基本原则,因此我希望它对您的问题有所帮助。当然,有许多可用的 gem 内置了这个功能,即 DeviseCanCan/CanTango,尽管我会亲自构建这个系统。

【讨论】:

    【解决方案2】:

    我想我会将 STI 与有很多直通关系结合起来。

    我将首先创建一个 Employers 和 Employees 的单表继承。

    class User < ActiveRecord::Base
      ...
    end
    
    class Employer < User
    end
    
    class Employee < User
    end
    

    雇主雇用雇员。一个雇主可以有很多员工,并且随着就业而来的是其他相关属性,例如date_of_hiredesignationstatusmanager_iddepartment 等。因此我会将其建模为一个单独的对象,因此将此信息存储在一个单独的表。我们叫它Employment,好吗?

    rails g model employment employer_id:integer, employee_id:integer, date_of_hire:date, designation:string, status:string, manager_id:integer
    

    让我们现在建立关系。

    class Employment < ActiveRecord::Base
      belongs_to :employer # Foreign key options should not required because of User STI
      belongs_to :employee
      belongs_to :manager,  :foreign_key => :manager_id,  :class_name => "User"
    end
    
    class Employee < User
      has_many :employments
      has_many :employers
      has_one  :manager,      :through     => :employments, :foreign_key => :manager_id
    end
    
    class Employer < User
      has_many :employments, :foreign_key => :employer_id
      has_many :employees,   :through     => :employments
    end
    

    基于业务规则,我们可以实现优雅的作用域。

    class Employee < User
      ...
      scope :fired, :where => {:status => 'fired'}
      scope :recently_joined, :where => {:date_of_hire => 3.months.ago...Date.today}
      scope :developers, :where => {:designation => 'developer'}
      ... 
    end
    

    还有……

    Employee.recently_joined
    Employee.recently_joined.developers
    Employee.fired
    

    请理解,这显然不是经过测试的代码,可能存在一些故障。

    但是!

    我强烈建议您重新考虑将雇主建模为用户的需求。从我个人的经验来看,后来证明是灾难(可能是我当时没有经验,但我不会再走那条路了)。我真的会为 Employer 和 Employee 建立单独的模型,并建立如上所述的关系,但使用 foreign_key 和 class_name 属性。主要原因是 STI 要在您的域中工作,雇主和雇员应该与用户具有“IS A”关系。您可能会认为这是一个“IS A”关系,但也认为它是否与“IS A”关系的“TYPE”相同。在我处理的应用程序中,它没有任何意义,但我们还是选择了 STI。雇主在申请中的特征、身份和待遇与雇员完全不同。尽管两者都有一些相同的数据,但它们的存在目的不同,用途也不同。这足以(单一职责)对它们进行单独建模。 STI 是一个可以解决问题的棘手工具。但是如果使用不当,会产生比它所能解决的问题更多的问题。

    【讨论】:

    • 我发现在几乎所有情况下,STI 都有点老套,最终被拉出来重构。
    • 我们非常有效地使用 STI 在我们的应用程序中区分不同类型的公司。没有不是 Company 子类的 Company 行,例如 AwesomeCompany 或 NotSoGreatCompany。每种类型的公司还有一个相关的配置文件,例如 AwesomeCompanyProfile,用于存储该类型公司独有的信息。它对我们来说效果很好。
    • @CalebThompson 您提到的案例听起来像是何时使用 STI 的一个很好的例子。您拥有的所有 STI 子类都与公司共享同一种“IS A”关系。我想我在上面的回答中也说了同样的话。但是将雇主(通常是公司)和雇员建模为用户似乎并不正确,因为雇主与雇员与用户之间的“IS A”关系不同。但是,它始终取决于您的业务规则。但从我个人的经验来看,这样做几乎总是错误的。
    • Chirantan,我同意你的观点,员工/雇主可能有很大的不同,他们不应该使用 STI。我将我的评论指向@KevinBedell,他的评论听起来像是从来没有有性传播感染的案例。
    • 我同意你的看法@CalebThompson,在某些情况下它是有道理的,但它们非常罕见。我很高兴我决定在我用过的 5 次中只使用一次 STI。并不是说完全没用。
    【解决方案3】:

    只需使用 has_many, :through。它会完成工作。假设您需要为一家可以做到的公司招募所有在职员工

    class Employers   
      has_many  :hired_employees, :through => :employments, 
                :class_name => "Employees", 
                :source => :employee, 
                :conditions => ['employment.status= ?',"hired"] 
    end
    

    那你就可以Employers.first.hired_employees了。您可以添加更多并使用不同的条件,以便您可以得到“终止”、“解雇”等。

    当然,这假设您有第三个模型,称为就业,它属于雇员和雇主。您的 Employee 和 Employment 类可能如下所示:

    class Employee
      has_many :employments
    end
    
    class Employment
      belongs_to :employee
      belongs_to :employer
    end
    

    【讨论】:

      【解决方案4】:

      根据您所说,您可能需要以下模型:User、Job、Assignment、Role

      class User
          ... some devise declarations here ...
          ... some role here. rolify gem is my suggestion ...
          scope :employee, :where => {user.has_role? :employee}
          scope :employer, :where => {user.has_role? :employer}
          has_many :jobs, :through => :assignments 
          has_many :assignments 
      end
      
      class Job
          belongs_to :user # employer
          has_many :assignments
          has_many :users, :through => :assignments # employee
      end
      
      class Assignment
         belongs_to :job
         belongs_to :user # employee
         def fired?
             ... stuff to check if the employee is fired
         end
         def hired?
             ... stuff to check if the employee is hired
         end
      end
      

      优点:

      • 您可以轻松添加更多角色,例如经理、管理员……。使用 rolify gem 或者您可以为自己创建角色模型
      • 作业类将存储您需要存储的任何内容,例如解雇、雇用的员工
      • 由于角色已明确预定义,因此可以使用 cancan 等授权 gem 轻松添加访问控制。

      缺点:

      • 使用此模型,用户必须在执行任何其他操作之前检查您正在处理的当前用户是雇主还是雇员。但是,可以使用角色轻松检查这一点

      为简单起见,您可以使用 rails_app_composer gem 生成安装了 devise、cancan 和 rolify 的初始应用程序。

      注意:此答案基于许多类似的问题,例如: Polymorphism or STI

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-24
        • 2015-02-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-24
        相关资源
        最近更新 更多