Rails has_many 型号相同,实例不同
Rails has_many of same model, but different instance
我正在构建一个锻炼跟踪应用程序。目前,我的模型设置为......
一个用户 has_many 安排
时间表 has_many 锻炼
一个锻炼有很多练习
一个练习 has_many 电路(包括 reps/sets/weights)。
一切正常。
但现在我要添加一个新关系,但我不确定如何设置。
我想要一个新模型 a user has_many "completed_workouts" 它包含锻炼模型的所有属性。
我的第一个想法是添加一个 user_workout 模型;带有用户和锻炼的外键。但这意味着每当我对锻炼进行更改时,它也会反映在 user.workouts 中;这不是我想要的。
schema.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
user.rb
class User < ApplicationRecord
has_many :user_schedules
has_many :schedules, through: :user_schedules
end
schedule.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
workout.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
我能想到两种可能的解决方案,都需要一定程度的数据冗余。
解决方案 1:添加 user_workout 模型,用于存储锻炼的时间点副本 table
在这种方法中,您可以按照计划添加 user_workout
模型,但不是只保留对 workout
的引用,您可以将需要的属性复制到 user_workout
模型。这意味着当您的 workout
值稍后发生变化时,您的 user_workout
将继续反映用户进行的锻炼的价值。
Table结构:
- user_id: 整数
- workout_id:整数(供参考)
- 锻炼的所有其他列
优点:
- 即使锻炼发生变化,用户锻炼值也不会改变
缺点:
- 数据重复(在这种情况下需要一定程度)
- 每当向
workout
添加新列时,它们也需要添加到 user_workout
。
但是,如果您只是为了显示目的而存储这些值并且不打算对它们执行任何计算操作,您可以简单地在 user_workout
中有一个名为 worker_snapshot
的哈希字段而不是所有的列。这将克服第二个缺点。
解决方案 2:每当对其进行编辑时,为锻炼创建一个新条目table
此方法假定锻炼只能具有固定值,并且如果锻炼中有任何变化,则意味着正在创建新的锻炼。这意味着锻炼没有 "updates" 之类的东西,如果需要更新,只需创建具有旧值修改值的新锻炼。然后 user_workout
table 可以直接指向 workout_id
而不必担心锻炼数据发生变化。
优点:
- 不需要
user_workout
table 担心对 workouts
的更改
缺点:
- 可能会使锻炼膨胀 table
这两种方法都可能有助于处理您描述的情况。我个人更喜欢使用 workout_snapshot
散列的第一种方法。
注意: 我建议对数据库结构进行反规范化。您的几个 table 仅具有 name
列,并以多对多关系链接到其他 table。我建议更改的一些内容:
- 您可以在
user_schedules
本身中有一个 name
字段,并删除 schedules
table。 user_schedule
本身可以有各种练习。
- 一个练习可以有一个名字和一个
workout_id
,workout_exercises
table 可以被删除。
这些只是我认为可能有助于降低数据库结构复杂性的建议。据我了解,我对您正在构建的内容的了解非常有限,而且此建议可能毫无用处,在这种情况下您可以忽略它!
我正在构建一个锻炼跟踪应用程序。目前,我的模型设置为...... 一个用户 has_many 安排 时间表 has_many 锻炼 一个锻炼有很多练习 一个练习 has_many 电路(包括 reps/sets/weights)。
一切正常。
但现在我要添加一个新关系,但我不确定如何设置。 我想要一个新模型 a user has_many "completed_workouts" 它包含锻炼模型的所有属性。
我的第一个想法是添加一个 user_workout 模型;带有用户和锻炼的外键。但这意味着每当我对锻炼进行更改时,它也会反映在 user.workouts 中;这不是我想要的。
schema.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
user.rb
class User < ApplicationRecord
has_many :user_schedules
has_many :schedules, through: :user_schedules
end
schedule.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
workout.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
我能想到两种可能的解决方案,都需要一定程度的数据冗余。
解决方案 1:添加 user_workout 模型,用于存储锻炼的时间点副本 table
在这种方法中,您可以按照计划添加 user_workout
模型,但不是只保留对 workout
的引用,您可以将需要的属性复制到 user_workout
模型。这意味着当您的 workout
值稍后发生变化时,您的 user_workout
将继续反映用户进行的锻炼的价值。
Table结构:
- user_id: 整数
- workout_id:整数(供参考)
- 锻炼的所有其他列
优点:
- 即使锻炼发生变化,用户锻炼值也不会改变
缺点:
- 数据重复(在这种情况下需要一定程度)
- 每当向
workout
添加新列时,它们也需要添加到user_workout
。
但是,如果您只是为了显示目的而存储这些值并且不打算对它们执行任何计算操作,您可以简单地在 user_workout
中有一个名为 worker_snapshot
的哈希字段而不是所有的列。这将克服第二个缺点。
解决方案 2:每当对其进行编辑时,为锻炼创建一个新条目table
此方法假定锻炼只能具有固定值,并且如果锻炼中有任何变化,则意味着正在创建新的锻炼。这意味着锻炼没有 "updates" 之类的东西,如果需要更新,只需创建具有旧值修改值的新锻炼。然后 user_workout
table 可以直接指向 workout_id
而不必担心锻炼数据发生变化。
优点:
- 不需要
user_workout
table 担心对workouts
的更改
缺点:
- 可能会使锻炼膨胀 table
这两种方法都可能有助于处理您描述的情况。我个人更喜欢使用 workout_snapshot
散列的第一种方法。
注意: 我建议对数据库结构进行反规范化。您的几个 table 仅具有 name
列,并以多对多关系链接到其他 table。我建议更改的一些内容:
- 您可以在
user_schedules
本身中有一个name
字段,并删除schedules
table。user_schedule
本身可以有各种练习。 - 一个练习可以有一个名字和一个
workout_id
,workout_exercises
table 可以被删除。
这些只是我认为可能有助于降低数据库结构复杂性的建议。据我了解,我对您正在构建的内容的了解非常有限,而且此建议可能毫无用处,在这种情况下您可以忽略它!