这是多态性的有效使用吗?如果是,我应该如何声明这种关系?

发布于 2024-12-11 14:48:20 字数 249 浏览 1 评论 0原文

我有一个预约模型,可以由导师或学生初始化。一旦一侧初始化,另一侧就可以接受或拒绝。

我将模型设计为:约会和参与者。参与者有两个属性:participant_id 和participant_type(“导师”/“学生”)。我想使用多态声明 Appointment has_one Tutor, has_many Students。

我的问题是:这是多态性的有效使用吗?如果是,那么我应该如何声明这种关系和外键?如果不是,那为什么?

谢谢。

I have an Appointment model, which can be initialized by Tutor or Student. Once initialized by one side, the other side can accept or decline.

I design my models as: Appointment, and Participant. Participant has two attributes: participant_id and participant_type ("Tutor"/"Student"). I would like to declare Appointment has_one Tutor, has_many Students using polymorphic.

My questions are: Is this a valid use of polymorphism? If yes, then how should I declare this relationship and the foreign keys? If no, then why?

Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

半葬歌 2024-12-18 14:48:20

当您具有在不同实体(例如学生和导师)之间共享的公共属性(例如参与约会的能力)时,请使用多态性。我认为您的情况需要参与者的多态性,而不是约会。

问问自己:是否有不同类型的约会或不同类型的参与者?从您提供的信息来看,您似乎有一种约会和不同类型的参与者。

多态参与者的示例

约会

class Appointment < ActiveRecord::Base
  has_many :participants
  has_one  :tutor,    :through => participants
  has_many :students, :through => participants
end

学生

class Student < ActiveRecord::Base
  has_many :appointments, :as => appointable
end

导师

class Tutor < ActiveRecord::Base
  has_many :appointments, :as => :appointable
end

参与者

# This model joins your appointable entities (Tutors and Students)
# to Appointments
class Participant < ActiveRecord::Base
  belongs_to :appointment
  belongs_to :appointable, :polymorphic => true
end

至于声明你的外键,Rails 会负责给你的。

参与者迁移

class CreateParticipants < ActiveRecord::Migration
  def up
    create_table :partipants do |t| 
      t.references :appointment
      t.references :appointable, :polymorphic => true
    end
  end

  def down
    drop_table :participants
  end
end

要更好地了解 Rails 如何将 polymorphic 等关键字转换为 SQL 关联,请参阅指南:http://guides.rubyonrails.org/association_basics.html#polymorphic-associations

我认为状态机是一个有趣的选择 - 我没有任何 Ruby/Rails 状态机项目的经验,所以我不能给你这方面的建议。

调度

这是如何设置调度的不完整图景。希望这足以让您开始。

将这些方法添加到约会:

class Appointment < ActiveRecord::Base

  # Anybody may request a new appointment,
  # specifying the initiator, and other participants
  # they would like to attend.
  def self.request requester, requested_participants=nil
    a = self.new
    a.status = "requested"
    a.requester = requester
    a.request_participation_of requested_participants
    a.save!
  end

  # Anybody may call this method
  # to request that the appointment be 
  # rescheduled, specifying the requester
  def reschedule requester
    self.status = "reschedule_requested"
    requester.participation_in(self).update_attribute :status=> "requester_of_reschedule"
    self.participants.where("appointable_id != ?", requester.id)
      .update_all :status => "reschedule_requested"
    self.save!
  end

  protected

  def requester= requester
    requester.participation_in(self).update_attribute :status => "requester"
  end

  def request_participation_of participants
    if participants.is_a? Array
      participants.each do |participant|
        participant.request_participation_in self
      end
    else
      request_participation_of [participants]
    end
  end
end

安排模块包含针对导师和学生的方法,因此您可以执行诸如 student_3.request_appointment coach_1tutor_1.reschedule_appointment Appointment_4 之类的操作。

lib/appointments/scheduling.rb

module Appointments::Scheduling
  # When a Student or Tutor's participation
  # in an Appointment has been requested,
  # he/she indicates acceptance of the request
  # with this method
  def accept_participation_in appointment
    self.participation_in(appointment).update_attribute :status => "accepted"
  end

  # Same as above, to decline the request
  def decline_participation_in appointment
    self.participation_in(appointment).update_attribute :status => "declined"
  end

  # This method finds the Student or Tutor's
  # Participant object for a particular Appointment
  def participation_in appointment
    Participant.where(:appointment_id => appointment.id)
      .find_by_appointable_id self.id
  end

  # A student or tutor can request a new
  # Appointment with a participant or
  # group of participants with this method
  def request_appointment participants
    Appointment.request self, participants
  end

  # This Student or Tutor's participation
  # in an appointment can be requested with
  # this method
  def request_participation_in appointment
    Participant.find_or_create_by_appointment_id_and_appointable_id(
      :appointment_id => appointment.id,
      :appointable_id => self.id
    )
  end

  # This Student or Tutor's confirmation of
  # a scheduled Appointment may be requested
  # with this method
  def request_reschedule_of appointment
    new_status = "reschedule_requested"
    if participant.id.eql? requester.id
      new_status = "requester_of_reschedule"
    end
    self.participation_in(appointment).update_attribute :status => new_status
  end

  # A Student or Tutor may reschedule a
  # particular Appointment with this method
  def reschedule_appointment appointment
    appointment.reschedule self
  end
end

这些模块就位后,您可以将它们包含在适当的实体中:

class Appointment < ActiveRecord::Base
  include Appointments::Schedulable
end

class Student < ActiveRecord::Base
  include Appointments::Scheduling
end

class Tutor < ActiveRecord::Base
  include Appointments::Scheduling
end

我的示例还要求您向两个模块添加一个 status 字段任命和参与者。我最终会创建一个 AppointmentStatus 和一个 ParticipantStatus - 首先我会让系统在没有它们的情况下工作。

以下是有关创建模型中使用的模块的有用资源:http:// henrik.nyh.se/2008/02/rails-model-extensions

Use polymorphism when you have a common property (such as the ability to participate in appointments) shared among different entities (such as Students and Tutors). I think your situation calls for polymorphism for Participants, rather than Appointments.

Ask yourself: are there different types of Appointments, or different types of Participants? From the information you've provided, it seems like you have one kind of Appointment, and different kinds of Participants.

An example of polymorphic Participant

Appointment

class Appointment < ActiveRecord::Base
  has_many :participants
  has_one  :tutor,    :through => participants
  has_many :students, :through => participants
end

Student

class Student < ActiveRecord::Base
  has_many :appointments, :as => appointable
end

Tutor

class Tutor < ActiveRecord::Base
  has_many :appointments, :as => :appointable
end

Participant

# This model joins your appointable entities (Tutors and Students)
# to Appointments
class Participant < ActiveRecord::Base
  belongs_to :appointment
  belongs_to :appointable, :polymorphic => true
end

As far as declaring your foreign keys goes, Rails takes care of that for you.

Migration for Participant

class CreateParticipants < ActiveRecord::Migration
  def up
    create_table :partipants do |t| 
      t.references :appointment
      t.references :appointable, :polymorphic => true
    end
  end

  def down
    drop_table :participants
  end
end

For a better understanding of how Rails translates keywords such as polymorphic into SQL associations, see the guide: http://guides.rubyonrails.org/association_basics.html#polymorphic-associations

I think state machines are an interesting option - I don't have experience with any of the Ruby/Rails state machine projects, so I can't give you advice on that.

Scheduling

This is an incomplete picture of how to set up scheduling. Hopefully, it should be enough to get you started.

Add these methods to Appointment:

class Appointment < ActiveRecord::Base

  # Anybody may request a new appointment,
  # specifying the initiator, and other participants
  # they would like to attend.
  def self.request requester, requested_participants=nil
    a = self.new
    a.status = "requested"
    a.requester = requester
    a.request_participation_of requested_participants
    a.save!
  end

  # Anybody may call this method
  # to request that the appointment be 
  # rescheduled, specifying the requester
  def reschedule requester
    self.status = "reschedule_requested"
    requester.participation_in(self).update_attribute :status=> "requester_of_reschedule"
    self.participants.where("appointable_id != ?", requester.id)
      .update_all :status => "reschedule_requested"
    self.save!
  end

  protected

  def requester= requester
    requester.participation_in(self).update_attribute :status => "requester"
  end

  def request_participation_of participants
    if participants.is_a? Array
      participants.each do |participant|
        participant.request_participation_in self
      end
    else
      request_participation_of [participants]
    end
  end
end

The Scheduling module contains methods for Tutors and Students, so you can do things like student_3.request_appointment tutor_1 or tutor_1.reschedule_appointment appointment_4.

lib/appointments/scheduling.rb:

module Appointments::Scheduling
  # When a Student or Tutor's participation
  # in an Appointment has been requested,
  # he/she indicates acceptance of the request
  # with this method
  def accept_participation_in appointment
    self.participation_in(appointment).update_attribute :status => "accepted"
  end

  # Same as above, to decline the request
  def decline_participation_in appointment
    self.participation_in(appointment).update_attribute :status => "declined"
  end

  # This method finds the Student or Tutor's
  # Participant object for a particular Appointment
  def participation_in appointment
    Participant.where(:appointment_id => appointment.id)
      .find_by_appointable_id self.id
  end

  # A student or tutor can request a new
  # Appointment with a participant or
  # group of participants with this method
  def request_appointment participants
    Appointment.request self, participants
  end

  # This Student or Tutor's participation
  # in an appointment can be requested with
  # this method
  def request_participation_in appointment
    Participant.find_or_create_by_appointment_id_and_appointable_id(
      :appointment_id => appointment.id,
      :appointable_id => self.id
    )
  end

  # This Student or Tutor's confirmation of
  # a scheduled Appointment may be requested
  # with this method
  def request_reschedule_of appointment
    new_status = "reschedule_requested"
    if participant.id.eql? requester.id
      new_status = "requester_of_reschedule"
    end
    self.participation_in(appointment).update_attribute :status => new_status
  end

  # A Student or Tutor may reschedule a
  # particular Appointment with this method
  def reschedule_appointment appointment
    appointment.reschedule self
  end
end

Once these modules are in place, you can include them in the appropriate entities:

class Appointment < ActiveRecord::Base
  include Appointments::Schedulable
end

class Student < ActiveRecord::Base
  include Appointments::Scheduling
end

class Tutor < ActiveRecord::Base
  include Appointments::Scheduling
end

My example also requires that you add a status field to both Appointment and Participant. I would eventually create an AppointmentStatus and a ParticipantStatus - first I would get the system working without that, however.

Here is a helpful resource on creating modules for use in your models: http://henrik.nyh.se/2008/02/rails-model-extensions

人间不值得 2024-12-18 14:48:20

我意识到就我而言,我不需要多态性。相反,我需要条件主动关系:

Appointment.rb

 has_one :tutor, :class_name => "Participant", :foreign_key => :appointment_id, :conditions => {:invitable_type => "Tutor"},  :dependent => :destroy 

I realized that in my case I don't need polymorphism. Instead, I need conditional active relation:

Appointment.rb

 has_one :tutor, :class_name => "Participant", :foreign_key => :appointment_id, :conditions => {:invitable_type => "Tutor"},  :dependent => :destroy 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文