diff --git a/app/controllers/job_applications_controller.rb b/app/controllers/job_applications_controller.rb index 3e162bb..96ca3d9 100644 --- a/app/controllers/job_applications_controller.rb +++ b/app/controllers/job_applications_controller.rb @@ -96,18 +96,19 @@ def set_job_application end def job_application_params - params.require(:job_application).permit(:date_applied, :company_name, :method_of_contact, :email_address, :point_of_contact, :website_link, :position_type, :position_title, :claimed_for_unemployment, :status) + params.require(:job_application).permit(:date_applied, :company_name, :method_of_contact, :email_address, :point_of_contact, :website_link, :position_type, :position_title, :claimed_for_unemployment, :status, :location) end def filter_and_sort_job_applications job_applications = JobApplication.all job_applications = job_applications.search(params[:search]) if params[:search].present? + job_applications = job_applications.by_location(params[:location]) if params[:location].present? job_applications = job_applications.by_method_of_contact(params[:method_of_contact]) if params[:method_of_contact].present? job_applications = job_applications.by_position_type(params[:position_type]) if params[:position_type].present? + job_applications = job_applications.by_status(params[:status]) if params[:status].present? job_applications = job_applications.claimed_for_unemployment if params[:claimed_for_unemployment] == "true" job_applications = job_applications.not_claimed_for_unemployment if params[:claimed_for_unemployment] == "false" - job_applications = job_applications.by_status(params[:status]) if params[:status].present? sort_column = sort_column(params[:sort]) sort_direction = sort_direction(params[:direction]) @@ -122,7 +123,7 @@ def filter_and_sort_job_applications end def sort_column(column) - %w[date_applied company_name position_title created_at claimed_for_unemployment status].include?(column) ? column : "created_at" + %w[date_applied company_name position_title created_at claimed_for_unemployment location status].include?(column) ? column : "created_at" end def sort_direction(direction) diff --git a/app/models/job_application.rb b/app/models/job_application.rb index 3cefb91..a605515 100644 --- a/app/models/job_application.rb +++ b/app/models/job_application.rb @@ -1,5 +1,6 @@ class JobApplication < ApplicationRecord attribute :status, :string + attribute :location, :string validates :date_applied, :company_name, :method_of_contact, :position_type, :position_title, presence: true validates :email_address, presence: true, if: -> { method_of_contact == "email" } @@ -13,6 +14,7 @@ class JobApplication < ApplicationRecord } validates :claimed_for_unemployment, inclusion: {in: [true, false]} validates :status, inclusion: {in: %w[hired interviewing job_offer no_response not_hired]} + validates :location, inclusion: {in: %w[hybrid in_office remote]} enum method_of_contact: { email: "email", @@ -33,7 +35,13 @@ class JobApplication < ApplicationRecord no_response: "no response", not_hired: "not hired" } + enum location: { + hybrid: "hybrid", + in_office: "in office", + remote: "remote" + } + scope :by_location, ->(location) { where(location: location) } scope :by_method_of_contact, ->(method) { where(method_of_contact: method) } scope :by_position_type, ->(type) { where(position_type: type) } scope :by_status, ->(status) { where(status: status) } @@ -45,6 +53,7 @@ class JobApplication < ApplicationRecord email_address ILIKE :query OR point_of_contact ILIKE :query OR website_link ILIKE :query OR + location ILIKE :query OR status ILIKE :query", query: "%#{query}%") } end diff --git a/app/views/job_applications/_form.html.erb b/app/views/job_applications/_form.html.erb index 6ad9f4f..d6e120a 100644 --- a/app/views/job_applications/_form.html.erb +++ b/app/views/job_applications/_form.html.erb @@ -52,13 +52,17 @@
<%= form.label :status, class: 'block text-sm font-medium text-gray-700 mb-2' %> - <%= form.select :status, JobApplication.statuses.keys.map { |k| [k.humanize, k] }, { include_blank: 'Select a status' }, class: 'shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline' %> -
- <%= form.label :claimed_for_unemployment, class: 'flex items-center' do %> - <%= form.check_box :claimed_for_unemployment, class: 'h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded mr-2' %> - Claimed for Unemployment - <% end %> -
+ <%= form.select :status, JobApplication.statuses.keys.map { |k| [k.humanize, k] }, { include_blank: false }, class: 'shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline' %> +
+
+ <%= form.label :location, class: 'block text-sm font-medium text-gray-700 mb-2' %> + <%= form.select :location, JobApplication.locations.keys.map { |k| [k.humanize, k] }, { include_blank: false }, class: 'shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline' %> +
+
+ <%= form.label :claimed_for_unemployment, class: 'flex items-center' do %> + <%= form.check_box :claimed_for_unemployment, class: 'h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded mr-2' %> + Claimed for Unemployment + <% end %>
diff --git a/app/views/job_applications/_job_application.html.erb b/app/views/job_applications/_job_application.html.erb index 5d868c6..0c39849 100644 --- a/app/views/job_applications/_job_application.html.erb +++ b/app/views/job_applications/_job_application.html.erb @@ -26,6 +26,9 @@ <%= job_application.status.humanize %> + + <%= job_application.location.humanize %> + <% if job_application.website_link.present? %> <%= link_to 'Visit', diff --git a/app/views/job_applications/_job_applications_table.html.erb b/app/views/job_applications/_job_applications_table.html.erb index 8369af1..293f1ef 100644 --- a/app/views/job_applications/_job_applications_table.html.erb +++ b/app/views/job_applications/_job_applications_table.html.erb @@ -31,6 +31,9 @@ <%= sort_link_to 'Status', 'status' %> + + <%= sort_link_to 'Location', 'location' %> + Website diff --git a/db/migrate/20240718143013_add_location_to_job_applications.rb b/db/migrate/20240718143013_add_location_to_job_applications.rb new file mode 100644 index 0000000..c9918da --- /dev/null +++ b/db/migrate/20240718143013_add_location_to_job_applications.rb @@ -0,0 +1,6 @@ +class AddLocationToJobApplications < ActiveRecord::Migration[7.1] + def change + add_column :job_applications, :location, :string, null: false, default: "remote" + add_check_constraint :job_applications, "location IN ('remote', 'in office', 'hybrid')", name: "check_valid_location" + end +end diff --git a/db/schema.rb b/db/schema.rb index 8d1df02..b8dc100 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.1].define(version: 2024_07_17_175130) do +ActiveRecord::Schema[7.1].define(version: 2024_07_18_143013) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -28,6 +28,8 @@ t.datetime "updated_at", null: false t.boolean "claimed_for_unemployment", default: false, null: false t.string "status", default: "no response", null: false + t.string "location", default: "remote", null: false + t.check_constraint "location::text = ANY (ARRAY['remote'::character varying, 'in office'::character varying, 'hybrid'::character varying]::text[])", name: "check_valid_location" t.check_constraint "status::text = ANY (ARRAY['interviewing'::character varying, 'no response'::character varying, 'hired'::character varying, 'not hired'::character varying, 'job offer'::character varying]::text[])", name: "check_valid_status" end diff --git a/db/seeds.rb b/db/seeds.rb index 728f7af..e02cdb9 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,7 +1,7 @@ require "faker" JobApplication.destroy_all -50.times do +20.times do method_of_contact = %w[email internet_job_application recruiter].sample email_address = (method_of_contact == "email") ? Faker::Internet.email : nil website_link = (method_of_contact == "internet_job_application") ? "https://example.com/" : nil @@ -16,6 +16,7 @@ position_title: Faker::Job.title, website_link: website_link, claimed_for_unemployment: [true, false].sample, - status: %w[interviewing no_response not_hired job_offer].sample + status: %w[interviewing no_response not_hired job_offer].sample, + location: %w[remote in_office hybrid].sample ) end diff --git a/test/factories/job_applications_factory.rb b/test/factories/job_applications_factory.rb index c08ad97..2bca962 100644 --- a/test/factories/job_applications_factory.rb +++ b/test/factories/job_applications_factory.rb @@ -1,14 +1,15 @@ FactoryBot.define do factory :job_application do - date_applied { Date.new(2023, 1, 1) } + claimed_for_unemployment { false } company_name { "Example Company" } + date_applied { Date.new(2023, 1, 1) } + email_address { "example@example.com" } + location { "remote" } method_of_contact { "email" } - position_type { "full_time" } + point_of_contact { "John Doe" } position_title { "Software Engineer" } - claimed_for_unemployment { false } + position_type { "full_time" } status { "interviewing" } - email_address { "example@example.com" } - point_of_contact { "John Doe" } trait :with_website do method_of_contact { "internet_job_application" } diff --git a/test/models/job_application_test.rb b/test/models/job_application_test.rb index ab59240..4f7e6a5 100644 --- a/test/models/job_application_test.rb +++ b/test/models/job_application_test.rb @@ -60,6 +60,12 @@ def setup assert_not_nil @job_application.errors[:website_link] end + test "job application validates location inclusion" do + assert_raises(ArgumentError) do + build(:job_application, location: "invalid_location") + end + end + test "job application validates status inclusion" do assert_raises(ArgumentError) do build(:job_application, status: "invalid_status") @@ -84,6 +90,15 @@ def setup assert_equal 1, JobApplication.by_method_of_contact("internet_job_application").count end + test "by_location scope finds job applications by location" do + JobApplication.destroy_all + create(:job_application, location: "remote") + create(:job_application, location: "in_office") + + assert_equal 1, JobApplication.by_location("remote").count + assert_equal 1, JobApplication.by_location("in_office").count + end + test "by_position_type scope finds job applications by position_type" do JobApplication.destroy_all create(:job_application, position_type: "full_time")