繁体   English   中英

在 Ruby on Rails 中扩展 model 用于 RESTful api 应用程序

[英]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_typeowner_id

任务也有一个type (STI),它可以是Tasks::ChoresTasks::Homework (为清楚起见,我命名了它)

使用Task model 上的范围,您应该能够调用person.tasks.choresperson.tasks.homeworks

即使您的 UML 模式在 Rails 中实现时违反了依赖倒置原则并且违反了2NF

但你可以这样做:

您需要创建两个表peopletasks

您可以通过添加这些迁移来做到这一点:

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表中,以便能够确定子任务

更新:

为避免违反依赖倒置原则,您可以执行以下操作:

TaskChoreHomework分开到不同的表中,因为ChoreHomework的字段非常不同

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM