首页 > 解决方案 > Rails has_many 相同的模型,但不同的实例

问题描述

我正在构建一个锻炼跟踪应用程序。目前,我的模型设置如下......

这一切都很好。

但是现在我正在添加一个新的关系,我不确定如何设置。我想要一个用户 has_many "completed_workouts" 的新模型,它包含锻炼模型的所有属性。

我的第一个想法是添加一个 user_workout 模型;为用户和锻炼提供外键。但这意味着每当我对锻炼进行更改时,它也会反映在 user.workouts 中;这不是我想要的。

架构.rb

    create_table "circuits", force: :cascade do |t|
        t.integer "weight"
        t.integer "reps"
        t.integer "rest"
        t.integer "exercise_id"
      end
    
      create_table "exercises", force: :cascade do |t|
        t.string "name"
      end
    
      create_table "schedules", force: :cascade do |t|
        t.string "name"
      end
    
      create_table "user_schedules", force: :cascade do |t|
        t.integer "user_id"
        t.integer "schedule_id"
      end
    
    
      create_table "users", force: :cascade do |t|
        t.string "name"
        t.string "username"
    
      end
    
      create_table "workout_exercises", force: :cascade do |t|
        t.integer "workout_id"
        t.integer "exercise_id"
      end
    
      create_table "workout_schedules", force: :cascade do |t|
        t.integer "workout_id"
        t.integer "schedule_id"
      end
    
      create_table "workouts", force: :cascade do |t|
        t.string "name"
      end

用户.rb

class User < ApplicationRecord
  has_many :user_schedules
  has_many :schedules, through: :user_schedules
end

日程安排.rb

class Schedule < ApplicationRecord
  has_many :user_schedules
  has_many :users, through: :user_schedules

  has_many :workout_schedules
  has_many :workouts,through: :workout_schedules

  accepts_nested_attributes_for :workouts

end

锻炼.rb

class Workout < ApplicationRecord
  has_many :workout_exercises
  has_many :exercises,through: :workout_exercises
  has_many :workout_schedules
  has_many :schedules,through: :workout_schedules

end

标签: ruby-on-railsforeign-keysrelational-database

解决方案


我可以想到两种可能的解决方案,两者都需要一定程度的数据冗余。

解决方案 1:添加 user_workout 模型,该模型存储锻炼表的时间点副本

在这种方法中,您可以按计划添加模型,但您可以将所需的属性复制到user_workout模型中,而不是只保留对 的引用。这意味着当您的值稍后发生变化时,您将继续反映用户进行的锻炼的价值。workoutuser_workoutworkoutuser_workout

表结构:

  1. user_id:整数
  2. 锻炼id:整数(供参考)
  3. 锻炼的所有其他列

优点:

  1. 即使锻炼发生变化,用户锻炼值也不会改变

缺点:

  1. 数据重复(在这种情况下在一定程度上是必需的)
  2. 每当将新列添加到 时workout,它们也需要添加到user_workout

但是,如果您只是出于显示目的而存储值并且不打算对它们执行任何计算操作,您可以简单地调用一个哈希字段worker_snapshotuser_workout不是所有列。这将克服第二个缺点。

解决方案 2:在锻炼表中创建一个新条目,无论何时对其进行编辑

这种方法假定锻炼只能具有固定值,如果锻炼中有任何变化,则意味着正在创建新的锻炼。这意味着没有锻炼的“更新”之类的东西,而只是在需要更新时使用修改过的旧锻炼值来创建新的锻炼。然后该user_workout表可以直接指向workout_id而不用担心锻炼数据的变化。

优点:

  1. 不需要user_workout担心表的变化workouts

缺点:

  1. 可能会使锻炼表膨胀

这两种方法都可能有助于处理您描述的场景。我个人更喜欢使用workout_snapshot哈希的第一种方法。

注意:我建议对数据库结构进行非规范化。您的几个表只有name列,并以多对多关系链接到其他表。我建议改变一些事情:

  1. 您可以自己拥有一个name字段user_schedules,然后删除该schedules表。user_schedule本身可以有各种练习。
  2. 一个练习可以有一个名字和一个workout_id,并且workout_exercises表格可以被删除。

这些只是我认为可能有助于降低数据库结构复杂性的建议。我知道我对您正在构建的内容的了解非常有限,并且此建议可能毫无用处,在这种情况下您可以忽略它!


推荐阅读