diff --git a/Gemfile b/Gemfile index a42bb24..4596178 100644 --- a/Gemfile +++ b/Gemfile @@ -44,6 +44,11 @@ end group :development do gem "annotate", "~> 3.2" gem "rails-erd", "~> 1.7" - gem "web-console" end + +group :test do + gem "shoulda-matchers", "~> 5.1" +end + +gem "faker", "~> 2.21" diff --git a/Gemfile.lock b/Gemfile.lock index fba12c6..4183bb1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -110,6 +110,8 @@ GEM factory_bot_rails (6.2.0) factory_bot (~> 6.2.0) railties (>= 5.0.0) + faker (2.21.0) + i18n (>= 1.8.11, < 2) faraday (2.3.0) faraday-net_http (~> 2.0) ruby2_keywords (>= 0.0.4) @@ -282,6 +284,8 @@ GEM sprockets (> 3.0) sprockets-rails tilt + shoulda-matchers (5.1.0) + activesupport (>= 5.2.0) sprockets (4.1.1) concurrent-ruby (~> 1.0) rack (> 1, < 3) @@ -324,6 +328,7 @@ DEPENDENCIES devise (~> 4.8) dotenv-rails (~> 2.7) factory_bot_rails (~> 6.2) + faker (~> 2.21) importmap-rails jbuilder omniauth (~> 1.9.1) @@ -335,6 +340,7 @@ DEPENDENCIES redis (~> 4.0) rspec-rails (~> 5.1) sassc-rails + shoulda-matchers (~> 5.1) sprockets-rails stimulus-rails turbo-rails diff --git a/app/models/axis.rb b/app/models/axis.rb new file mode 100644 index 0000000..9749e89 --- /dev/null +++ b/app/models/axis.rb @@ -0,0 +1,18 @@ +# == Schema Information +# +# Table name: axes +# +# id :bigint not null, primary key +# name :string +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_axes_on_name (name) UNIQUE +# +class Axis < ApplicationRecord + has_many :subjects + + validates :name, presence: true, uniqueness: true +end diff --git a/app/models/category.rb b/app/models/category.rb new file mode 100644 index 0000000..6afd088 --- /dev/null +++ b/app/models/category.rb @@ -0,0 +1,18 @@ +# == Schema Information +# +# Table name: categories +# +# id :bigint not null, primary key +# name :string +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_categories_on_name (name) UNIQUE +# +class Category < ApplicationRecord + has_many :subjects + + validates :name, presence: true, uniqueness: true +end diff --git a/app/models/subject.rb b/app/models/subject.rb new file mode 100644 index 0000000..4d5e7d4 --- /dev/null +++ b/app/models/subject.rb @@ -0,0 +1,28 @@ +# == Schema Information +# +# Table name: subjects +# +# id :bigint not null, primary key +# name :string +# created_at :datetime not null +# updated_at :datetime not null +# axis_id :bigint not null +# category_id :bigint not null +# +# Indexes +# +# index_subjects_on_axis_id (axis_id) +# index_subjects_on_category_id (category_id) +# index_subjects_on_name (name) UNIQUE +# +# Foreign Keys +# +# fk_rails_... (axis_id => axes.id) +# fk_rails_... (category_id => categories.id) +# +class Subject < ApplicationRecord + belongs_to :category + belongs_to :axis + + validates :name, presence: true, uniqueness: true +end diff --git a/db/migrate/20220721123241_create_categories.rb b/db/migrate/20220721123241_create_categories.rb new file mode 100644 index 0000000..a4b9eca --- /dev/null +++ b/db/migrate/20220721123241_create_categories.rb @@ -0,0 +1,11 @@ +class CreateCategories < ActiveRecord::Migration[7.0] + def change + create_table :categories do |t| + t.string :name + + t.timestamps + end + + add_index(:categories, :name, unique: true) + end +end diff --git a/db/migrate/20220721123254_create_axes.rb b/db/migrate/20220721123254_create_axes.rb new file mode 100644 index 0000000..5ad078a --- /dev/null +++ b/db/migrate/20220721123254_create_axes.rb @@ -0,0 +1,11 @@ +class CreateAxes < ActiveRecord::Migration[7.0] + def change + create_table :axes do |t| + t.string :name + + t.timestamps + end + + add_index(:axes, :name, unique: true) + end +end diff --git a/db/migrate/20220721123327_create_subjects.rb b/db/migrate/20220721123327_create_subjects.rb new file mode 100644 index 0000000..f4714bb --- /dev/null +++ b/db/migrate/20220721123327_create_subjects.rb @@ -0,0 +1,13 @@ +class CreateSubjects < ActiveRecord::Migration[7.0] + def change + create_table :subjects do |t| + t.string :name + t.references :category, null: false, foreign_key: true + t.references :axis, null: false, foreign_key: true + + t.timestamps + end + + add_index(:subjects, :name, unique: true) + end +end diff --git a/db/schema.rb b/db/schema.rb index faf2c2b..c645db4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2022_07_21_015136) do +ActiveRecord::Schema[7.0].define(version: 2022_07_21_123327) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -28,6 +28,31 @@ ActiveRecord::Schema[7.0].define(version: 2022_07_21_015136) do t.index ["resource_type", "resource_id"], name: "index_active_admin_comments_on_resource" end + create_table "axes", force: :cascade do |t| + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["name"], name: "index_axes_on_name", unique: true + end + + create_table "categories", force: :cascade do |t| + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["name"], name: "index_categories_on_name", unique: true + end + + create_table "subjects", force: :cascade do |t| + t.string "name" + t.bigint "category_id", null: false + t.bigint "axis_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["axis_id"], name: "index_subjects_on_axis_id" + t.index ["category_id"], name: "index_subjects_on_category_id" + t.index ["name"], name: "index_subjects_on_name", unique: true + end + create_table "users", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false @@ -41,4 +66,6 @@ ActiveRecord::Schema[7.0].define(version: 2022_07_21_015136) do t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true end + add_foreign_key "subjects", "axes" + add_foreign_key "subjects", "categories" end diff --git a/spec/factories/axes.rb b/spec/factories/axes.rb new file mode 100644 index 0000000..9645ede --- /dev/null +++ b/spec/factories/axes.rb @@ -0,0 +1,18 @@ +# == Schema Information +# +# Table name: axes +# +# id :bigint not null, primary key +# name :string +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_axes_on_name (name) UNIQUE +# +FactoryBot.define do + factory :axis do + name { Faker::Superhero.name } + end +end diff --git a/spec/factories/categories.rb b/spec/factories/categories.rb new file mode 100644 index 0000000..3abf370 --- /dev/null +++ b/spec/factories/categories.rb @@ -0,0 +1,18 @@ +# == Schema Information +# +# Table name: categories +# +# id :bigint not null, primary key +# name :string +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_categories_on_name (name) UNIQUE +# +FactoryBot.define do + factory :category do + name { Faker::Superhero.name } + end +end diff --git a/spec/factories/subjects.rb b/spec/factories/subjects.rb new file mode 100644 index 0000000..114c5d5 --- /dev/null +++ b/spec/factories/subjects.rb @@ -0,0 +1,29 @@ +# == Schema Information +# +# Table name: subjects +# +# id :bigint not null, primary key +# name :string +# created_at :datetime not null +# updated_at :datetime not null +# axis_id :bigint not null +# category_id :bigint not null +# +# Indexes +# +# index_subjects_on_axis_id (axis_id) +# index_subjects_on_category_id (category_id) +# index_subjects_on_name (name) UNIQUE +# +# Foreign Keys +# +# fk_rails_... (axis_id => axes.id) +# fk_rails_... (category_id => categories.id) +# +FactoryBot.define do + factory :subject do + name { Faker::Superhero.name } + axis + category + end +end diff --git a/spec/models/axis_spec.rb b/spec/models/axis_spec.rb new file mode 100644 index 0000000..ce046ea --- /dev/null +++ b/spec/models/axis_spec.rb @@ -0,0 +1,27 @@ +# == Schema Information +# +# Table name: axes +# +# id :bigint not null, primary key +# name :string +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_axes_on_name (name) UNIQUE +# +require 'rails_helper' + +RSpec.describe(Axis, type: :model) do + describe "associations" do + it { is_expected.to(have_many(:subjects)) } + end + + describe "validations" do + subject { create :axis } + + it { is_expected.to(validate_presence_of(:name)) } + it { is_expected.to(validate_uniqueness_of(:name)) } + end +end diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb new file mode 100644 index 0000000..ca77eae --- /dev/null +++ b/spec/models/category_spec.rb @@ -0,0 +1,25 @@ +# == Schema Information +# +# Table name: categories +# +# id :bigint not null, primary key +# name :string +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_categories_on_name (name) UNIQUE +# +require 'rails_helper' + +RSpec.describe(Category, type: :model) do + describe "associations" do + it { is_expected.to(have_many(:subjects)) } + end + + describe "validations" do + it { is_expected.to(validate_presence_of(:name)) } + it { is_expected.to(validate_uniqueness_of(:name)) } + end +end diff --git a/spec/models/subject_spec.rb b/spec/models/subject_spec.rb new file mode 100644 index 0000000..91fffd1 --- /dev/null +++ b/spec/models/subject_spec.rb @@ -0,0 +1,38 @@ +# == Schema Information +# +# Table name: subjects +# +# id :bigint not null, primary key +# name :string +# created_at :datetime not null +# updated_at :datetime not null +# axis_id :bigint not null +# category_id :bigint not null +# +# Indexes +# +# index_subjects_on_axis_id (axis_id) +# index_subjects_on_category_id (category_id) +# index_subjects_on_name (name) UNIQUE +# +# Foreign Keys +# +# fk_rails_... (axis_id => axes.id) +# fk_rails_... (category_id => categories.id) +# +require 'rails_helper' + +RSpec.describe(Subject, type: :model) do + describe "associations" do + it { is_expected.to(belong_to(:axis)) } + it { is_expected.to(belong_to(:category)) } + # it { is_expected.to(have_many(:questions)) } + end + + describe "validations" do + subject { create :subject } + + it { is_expected.to(validate_presence_of(:name)) } + it { is_expected.to(validate_uniqueness_of(:name)) } + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index b6317b5..e5a49fa 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -39,26 +39,14 @@ RSpec.configure do |config| # instead of true. config.use_transactional_fixtures = true - # You can uncomment this line to turn off ActiveRecord support entirely. - # config.use_active_record = false - - # RSpec Rails can automatically mix in different behaviours to your tests - # based on their file location, for example enabling you to call `get` and - # `post` in specs under `spec/controllers`. - # - # You can disable this behaviour by removing the line below, and instead - # explicitly tag your specs with their type, e.g.: - # - # RSpec.describe UsersController, type: :controller do - # # ... - # end - # - # The different available types are documented in the features, such as in - # https://relishapp.com/rspec/rspec-rails/docs config.infer_spec_type_from_file_location! - - # Filter lines from Rails gems in backtraces. config.filter_rails_from_backtrace! - # arbitrary gems may also be filtered via: - # config.filter_gems_from_backtrace("gem name") + config.include(FactoryBot::Syntax::Methods) +end + +Shoulda::Matchers.configure do |config| + config.integrate do |with| + with.test_framework(:rspec) + with.library(:rails) + end end