RESTful API アプリ用に Ruby on Rails でモデルを拡張する
概要
プロジェクトの一環として、実装する UML 図を入手しました。今私は OOP の部分にいますが、Ruby でそれを実装する方法がわかりません。 マルチテーブル継承(MTI)でなければならないと理解しているので、すべてのタスクは雑用または宿題です。 ユーザーテーブル -> chores/hw のテーブル、タスク -> chores/hw のテーブル間の関係を実装する方法がわかりません。 また、CRUD アクション (create) の実装方法を知っておくとよいでしょう。 誰かが助けてくれることを願っています。 ありがとう。 図は次のとおりです。 ダイアグラム
解決策
UML スキーマが Rails で実装する際に依存性逆転の原則に違反し、2NF に違反している場合でも、
しかし、次のようにすることもできます。
人とタスクの 2 つのテーブルを作成する必要があります
これを行うには、次の移行を追加します。
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: '[email protected]', 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
どのタスクが雑用で、どのタスクが宿題であるかを知る必要がある場合は、タスク テーブルにタイプ フィールドを追加して、サブタスクを判断できるようにする必要があります。
アップデート:
依存関係の逆転の原則に違反しないようにするには、次のことを実行できます。
家事と宿題はフィールドが大きく異なるため、タスク、家事、宿題を別のテーブルに分離します。
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: '[email protected]', 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
注: ただし、このアプローチは、さらにさまざまなタスクを追加する必要がある場合には適していません。新しいタスク タイプが常に存在するため、新しいテーブルを追加する必要があります。これは現在の例でのみ機能します。