[英]Extend model in Ruby on Rails for RESTful api app
作为项目的一部分,我们得到了一个 UML 图来实现。 现在我在 OOP 的部分,但我不确定如何在 Ruby 中实现它。每个任务都是杂务或家庭作业,据我了解它必须是多表继承(MTI)。 我不确定如何实现用户表之间的关系 -> chores/hw 的表,以及 tasks->chores/hw 的表。 另外,最好知道如何实现 CRUD 操作(创建\更新\销毁)希望有人能提供帮助。 谢谢。 这是图表:图表
models/person.rb
class Person < ApplicationRecord
has_many :tasks, as: :owner, class_name: "::Task"
end
models/task.rb
class Task < ApplicationRecord
belongs_to :owner, polymorphic: true
enum status: {
active: 0,
done: 1
}
scope :chores, -> { where(type: "Tasks::Chores")}
scope :homeworks, -> { where(type: "Tasks::Homework")}
end
models/tasks/chores.rb
class Tasks::Chores < Task
enum size: {
small: 0,
medium: 1,
large: 2
}
end
models/tasks/homework.rb
class Tasks::Homework
end
欢迎来到计算器!
我没有尝试过这段代码,但它应该是正确的。
Task
有一个多态的owner
,所以它可以是一个Person
,或者任何其他 model,这将添加 2 列owner_type
和owner_id
。
任务也有一个type
(STI),它可以是Tasks::Chores
或Tasks::Homework
(为清楚起见,我命名了它)
使用Task
model 上的范围,您应该能够调用person.tasks.chores
或person.tasks.homeworks
即使您的 UML 模式在 Rails 中实现时违反了依赖倒置原则并且违反了2NF
但你可以这样做:
您需要创建两个表people
和tasks
您可以通过添加这些迁移来做到这一点:
class CreatePeople < ActiveRecord::Migration[7.0]
def change
create_table :people do |t|
t.string :name
t.string :email
t.string :fav_prog_lang
t.timestamps
end
end
end
class CreateTasks < ActiveRecord::Migration[7.0]
def change
create_table :tasks do |t|
t.references :owner, null: false, foreign_key: { to_table: :people }
t.text :description
t.integer :size, default: 0
t.string :course
t.datetime :due_date
t.string :details
t.integer :status, default: 0
t.timestamps
end
end
end
之后你需要创建这些模型:
# app/models/person.rb
class Person < ApplicationRecord
has_many :tasks, foreign_key: :owner_id
end
# app/models/task.rb
class Task < ApplicationRecord
belongs_to :owner, class_name: 'Person', foreign_key: :owner_id
enum status: { active: 0, done: 1 }
end
# app/models/chore.rb
class Chore < Task
enum size: { small: 0, medium: 1, large: 2 }
end
# app/models/homework.rb
class Homework < Task
enum size: { small: 0, medium: 1, large: 2 }, _prefix: true
end
最后你可以创建你的任务:
person = Person.create(name: 'John Doe', email: 'john.doe@test.test', fav_prog_lang: 'Ruby')
Homework.create(owner: person, course: 'Some course', due_date: 10.days.since, details: 'Some details')
Chore.create(owner: person, size: :medium, description: 'Some description')
person.tasks
如果您需要能够知道什么任务是chore
,什么任务是homework
,您需要将type
字段添加到tasks
表中,以便能够确定子任务
更新:
为避免违反依赖倒置原则,您可以执行以下操作:
将Task
、 Chore
和Homework
分开到不同的表中,因为Chore
和Homework
的字段非常不同
class CreateTasks < ActiveRecord::Migration[7.0]
def change
create_table :tasks do |t|
t.references :owner, null: false, foreign_key: { to_table: :people }
t.integer :status, default: 0
t.timestamps
end
end
end
class CreateChores < ActiveRecord::Migration[7.0]
def change
create_table :chores do |t|
t.references :task, null: false, foreign_key: true
t.text :description
t.integer :size, default: 0
t.timestamps
end
end
end
class CreateHomeworks < ActiveRecord::Migration[7.0]
def change
create_table :homeworks do |t|
t.references :task, null: false, foreign_key: true
t.string :course
t.datetime :due_date
t.string :details
t.timestamps
end
end
end
而不是你的模型:
class Person < ApplicationRecord
has_many :tasks, foreign_key: :owner_id
has_many :chores, through: :tasks
has_many :homeworks, through: :tasks
end
class Task < ApplicationRecord
belongs_to :owner, class_name: 'Person', foreign_key: :owner_id
has_many :chores
has_many :homeworks
enum status: { active: 0, done: 1 }
accepts_nested_attributes_for :chores, :homeworks
end
class Chore < ApplicationRecord
belongs_to :task
enum size: { small: 0, medium: 1, large: 2 }
end
class Homework < ApplicationRecord
belongs_to :task
end
您可以像这样操作这些模型:
person = Person.create(name: 'John Doe', email: 'john.doe@test.test', fav_prog_lang: 'Ruby')
person.tasks.create(
status: :done, chores_attrubutes: [{ size: :medium, description: 'Some description' }]
)
person.tasks.create(homeworks_attrubutes: [{ course: 'Some course', due_date: 10.days.since, details: 'Some details' }])
person.chores
person.homeworks
# and you can have also all tasks
person.tasks
注意:但如果您需要添加更多不同的任务,则此方法不适用。 因为您总是会有新的任务类型,所以您将不得不添加新表。 这仅适用于您当前的示例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.