これを構造化する方法を見つけようとしています。助けてください: ユーザーが雇用主または従業員としてサインアップできるようにする必要があります。雇用者は基本的に会社であり、従業員はその仕事で雇用されている人々です。従業員がいつ採用され、いつ解雇されたかを記録する方法を知りたいです。アソシエーションはこれに対して機能しますか、has_many:through
それともそれ以上に機能しますか?
4 に答える
これは階層オブジェクト モデルの典型的なケースであるため、関係するオブジェクトとそれらの相互関係の観点からこの問題を考える必要があります。ビジネスが実際にどのように機能するかを考えてみましょう。
雇用主 -> 従業員 雇用主 -> マネージャーなどではありません -> 従業員
このシステム モデルの良い例は、GitHub のシステム モデルです。GitHub では、ユーザーは組織に所属できます。また、それらを作成して管理し、メンバーを管理することもできます(あなたの場合は雇用と解雇)。したがって、このシステムをモデル化するためのはるかに優れた方法は、ユーザーの 2 つの異なるクラスに分割するのではなく、ユーザー中心にすることです。
以前の回答で述べたように、雇用主 (またはこの意味での企業) は、プログラムの状態に基づいて行動しないため、システムのユーザーと見なされるべきではありません。したがって、個人的には、このシステム モデルに対して STI は少しやり過ぎだと思います。
そう...
ビジネスで雇用されているすべての人は従業員ですが、すべての従業員が同じレベルの権限を持っているわけではありません (たとえば、管理職は下級従業員よりも権限が大きくなります)。Business
したがって、多く の をもつ a をモデル化する必要がありますEmployee
。これらEmployee
の s は、その地位に基づいてさまざまなレベルの権限を持ちます。
- 雇えますか?
- can_fire?
- 等
Employee
これがいつ採用/解雇されたかを知らせるメソッドを作成することもできます。これらは、雇用/解雇されたかnil
どうかにかかわらず、日付/時刻を返すことができます。nil
この意味では、彼らがまだ雇用/解雇されていないことを明らかに意味します。
さまざまなユーザーの能力を管理する場合、権限のレベルは、ユーザーができることとできないことによって定義されます。もちろん、上記の方法を確認する簡単な方法で、この状況に事前設定された役割を適用できます。例えば:
def manager?
self.can_hire? and self.can_fire?
end
次に、ビジネスの作成を可能にする機能も定義します。
def can_create_business?
self.manager?
end
注: これをエレガントに実現するためにスコープを使用できます。
ロールの基本的な User モデルをサブクラス化するか、上記のメソッドを定義して特定の User モデルで動作する Role クラスを作成することもできます。その後、個々の役割と役割のサブセットを作成できます。
おそらく、雇用主/企業と従業員の両方をプログラムの状態に基づいて行動できる別個のエンティティとして作成できるようにすることが役立つ場合があります。Business
単純な管理機能以上の機能を実行できる場合、これは価値があるかもしれません。その場合、私はまだビジネスをユーザー モデルとは見なしません。Business
または同様の役割を持つ特別なユーザーアカウントを作成する必要がありますBusiness Administrator
。
このモデルは、プログラミングとコンピューター サイエンス全体の最も基本的な原則のいくつかに従っているので、問題を少しでも解明できれば幸いです。もちろん、DeviseやCanCan/CanTangoなど、この機能が組み込まれている gem が多数ありますが、私は個人的にこのシステムを自分で構築します。
私は STI を多くの関係を通じて結合すると思います。
まず、Employers と Employees の 1 つのテーブル継承を作成することから始めます。
class User < ActiveRecord::Base
...
end
class Employer < User
end
class Employee < User
end
雇用主は従業員を雇用します。1 人の雇用主は多くの従業員を持つことができ、雇用とともに 、 、 、 などの他の関連プロパティが発生しますdate_of_hire
。designation
したがってstatus
、これを別のオブジェクトとしてモデル化し、この情報を別のテーブルに保存しますmanager_id
。department
と呼びましょう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 は、問題を解決できるトリッキーなツールです。しかし、使い方を誤ると、解決できる問題よりも多くの問題が発生します。
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
。さらに追加してさまざまな条件を使用することで、「終了」、「却下」などを行うことができます。
もちろん、これは、従業員と雇用者に属する雇用と呼ばれる3番目のモデルがあることを前提としています。従業員クラスと雇用クラスは次のようになります。
class Employee
has_many :employments
end
class Employment
belongs_to :employee
belongs_to :employer
end
あなたが言ったことから、次のモデルが必要になるかもしれません: 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
長所:
- マネージャー、管理者などの役割を簡単に追加できます。roify gemを使用するか、自分でロールモデルを作成できます
- 割り当てクラスには、従業員について解雇、雇用など、保存する必要があるものはすべて保存されます
- 役割が明確に定義されているため、cancan などの認可 gem を使用してアクセス制御を簡単に追加できます。
短所:
- このモデルを使用すると、他の操作を行う前に、現在作業しているユーザーが雇用者か従業員かを確認する必要があります。ただし、これはロールを使用して簡単に確認できます
簡単にするために、rails_app_composer gem を使用して、devise、cancan、および rolify がインストールされた初期アプリを生成できます。
注: この回答は、 ポリモーフィズムまたは STIなどの多くの同様の質問に基づいています。