舞台:

假设我的模型定义如下:

class Client < AR:Base
  has_one :driver_profile, class_name: 'Driver'
  has_many :races
end

class Driver
  # attribute :dob

  belongs_to :client
  has_and_belongs_to_many :teams
end

class Race
  # attribute :date

  belongs_to :client
  has_and_belongs_to_many :drivers
end

这样做的逻辑是:页面上注册的每个客户都可以注册许多不同的种族,每个团队可以有多个驱动程序。但是,每个客户也都是驱动程序,默认情况下,将其分配给他的每个团队。为了实现这一点,我重写了Team drivers阅读器(我正在使用andand gem):
def drivers
  association = super
  driver_profile = client.andand.driver_profile
  if !driver_profile || driver_profile.new_record? || association.include? driver_profile
    association << client.driver_profile
  end
  association
end

这工作得很好,但是却不如我希望的那样好(并且每次我调用此方法时,都会进行一次额外的db调用)。

问题

对于所有模型,我都有一个非常庞大的多步骤表单。在前两个步骤中,用户可以编辑他的个人信息(在客户模型上),driver_profile和他的初始比赛。在随后的步骤中,他可以添加任意数量的车手参加比赛,但是,车手的出生日期需要与比赛日期进行核对(必须至少为21)。

问题在于,此验证不会落在驾驶员模型上,因为驾驶员可能对一场比赛有效,而对第二场比赛无效。因此,这是种族问题,而不是车手问题。我写了这样的验证(在Race模型上):
validate :drivers_at_least_21

def drivers_at_least_21
  error = false
  drivers.each do |driver|
    if driver.age_at(start) < 21
      driver.errors.add(:dob, :too_young)
      error = true
    end
  end
  errors.add(:driver, :invalid) if error
end

这在大多数情况下都有效,但是由于client.driver_profiledrivers是完全不同的关联,因此添加到drivers中的驱动程序的错误不会添加到client.driver_profile中,也不会显示在driver_profile的嵌套字段中(第一页)。我设法使用以下方法克服了它:
(drivers + Array.wrap(client.andand.driver_profile)).uniq(&:object_id).each do |driver|

但是,此操作非常笨拙,丑陋且通常很糟糕,因此这是假设模型设计错误的理想时机。

问题

您将如何为此重新设计数据库模型和关联?到目前为止,我已经想到了许多解决方案:
  • 使用联合定义种族上的驱动程序。如果仅联合方法返回了可查询的AR关系,那么这绝对是最好的选择。
  • 创建类似于other_drivers的关联,并定义方法drivers以对驱动程序和driver_profile求和。这样,我将无法查询驱动程序结果。
  • 'Hack'驱动程序关联的目标方法,向其添加driver_profile-但是,此方法不会在结果范围中持久存在。
  • 最佳答案

    我想知道,如何将您的驱动程序关联转换为多态关联?

    我正在考虑这样的事情(注意:我使用 racers 以避免与 Driver 实例混淆):

    移民:

    # RaceRacer migration
    class CreateRaceRacers < ActiveRecord::Migration
      def change
        create_table :race_racers do |t|
          t.references :race, index: true
          t.integer :racer_id
          t.string :racer_type
    
          t.timestamps
        end
      end
    end
    

    楷模:
    # RaceRacer model
    class RaceRacer < ActiveRecord::Base
      belongs_to :race
      belongs_to :racer, polymorphic: true
    end
    
    # Race model
    class Race < ActiveRecord::Base
      has_many :race_racers
      has_many :driver_racers, through: :race_racers, source: :racer,
               source_type: :Driver
      has_many :customer_racers, through: :race_racers, source: :racer,
               source_type: :Customer
    
      # Unfortunately ActiveRecord doesn't support has_many on a polymorphic
      # association without :source_type, so we need to define a method
      def racers
        race_racers.map(&:racer)
      end
    end
    
    # Driver model
    class Driver < ActiveRecord::Base
      has_many :race_racers, as: :racer
      has_many :races, through: :race_racers
    end
    
    # Customer model
    class Customer < ActiveRecord::Base
      has_many :race_racers, as: :racer
      has_many :races, through: :race_racers
    end
    
    Race.first.racersmap 上的 race_racers ,所以 DriverCustomer 实例上的错误应该没问题

    关于ruby-on-rails - Rails中的相关协会,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22783645/

    10-10 16:53