From fb36e9bfce84c597db0d87cc029891899d303d13 Mon Sep 17 00:00:00 2001 From: Andrey Shlyapnikov <48034349+usernaimandrey@users.noreply.github.com> Date: Fri, 30 Aug 2024 09:15:17 +0300 Subject: [PATCH] add cancel process from vacancies (#760) * add cancel process from vacancies * add frontend process * move form in layout * add notification * add test to rout new_cancelation_reason * notification process * fix after reviw * fix after revew * remove resque from mutator * fix ruby version && logic mutator * add check create notification * fix and add new test case * fix --- .ruby-version | 2 +- .../web/admin/vacancies_controller.rb | 48 +++++++++++----- app/forms/web/admin/vacancy_form.rb | 3 +- app/lib/notifications_helper.rb | 13 +++++ app/models/notification.rb | 19 ++++++- app/models/vacancy.rb | 10 +++- app/mutators/admin/vacancy_mutator.rb | 30 ++++++++++ .../web/account/vacancies/index.html.slim | 3 + .../vacancies/_vacancies_table.html.slim | 3 + .../admin/vacancies/new_cancelation.html.slim | 7 +++ config/locales/admin/en.flash.yml | 5 +- config/locales/admin/en.yml | 1 + config/locales/admin/ru.flash.yml | 4 ++ config/locales/admin/ru.yml | 1 + config/locales/en.activerecord.yml | 3 + config/locales/en.enumerize.yml | 6 ++ config/locales/en.notification.yml | 2 + config/locales/en.views.yml | 1 + config/locales/ru.activerecord.yml | 3 + config/locales/ru.enumerize.yml | 6 ++ config/locales/ru.notifications.yml | 2 + config/locales/ru.views.yml | 1 + config/routes.rb | 2 + ...dd_column_cancelation_reason_to_vacancy.rb | 5 ++ db/schema.rb | 3 +- .../web/admin/vacancies_controller_test.rb | 55 ++++++++++++++++++- test/factories/vacancies.rb | 1 + test/fixtures/notifications.yml | 12 ++++ test/fixtures/vacancies.yml | 11 ++++ test/models/vacancy_test.rb | 1 + 30 files changed, 241 insertions(+), 22 deletions(-) create mode 100644 app/mutators/admin/vacancy_mutator.rb create mode 100644 app/views/web/admin/vacancies/new_cancelation.html.slim create mode 100644 db/migrate/20240707200834_add_column_cancelation_reason_to_vacancy.rb diff --git a/.ruby-version b/.ruby-version index 9e79f6c4a..a0891f563 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -ruby-3.2.2 +3.3.4 diff --git a/app/controllers/web/admin/vacancies_controller.rb b/app/controllers/web/admin/vacancies_controller.rb index 202b03c11..b8a859ee8 100644 --- a/app/controllers/web/admin/vacancies_controller.rb +++ b/app/controllers/web/admin/vacancies_controller.rb @@ -36,12 +36,16 @@ def new end def edit - vacancy = Vacancy.find params[:id] - @vacancy = vacancy.becomes(Web::Admin::VacancyForm) + @vacancy = resource_vacancy.becomes(Web::Admin::VacancyForm) + end + + def new_cancelation + @go_to = params[:go_to] + @vacancy = resource_vacancy.becomes(Web::Admin::VacancyForm) end def create - @vacancy = Web::Account::VacancyForm.new(params[:vacancy]) + @vacancy = Web::Admin::VacancyForm.new(params[:vacancy]) @vacancy.creator = current_user if @vacancy.save @@ -54,13 +58,15 @@ def create end def update - vacancy = Vacancy.find params[:id] - @vacancy = vacancy.becomes(Web::Admin::VacancyForm) - if @vacancy.update(params[:vacancy]) - f(:success) - redirect_to edit_admin_vacancy_path(@vacancy) - else + vacancy = resource_vacancy.becomes(Web::Admin::VacancyForm) + @vacancy = Admin::VacancyMutator.update(vacancy, params[:vacancy]) + + if @vacancy.invalid? + f(:error, now: true, values: { messages: @vacancy.errors.messages }) render :edit, status: :unprocessable_entity + else + f(:success) + redirect_to params[:go_to] || edit_admin_vacancy_path(@vacancy) end end @@ -72,22 +78,38 @@ def on_moderate end def archive - vacancy = Vacancy.find params[:id] - vacancy.archive! + resource_vacancy.archive! f(:success) redirect_to params[:go_to] || admin_vacancies_path(page: params[:page]) end def restore - vacancy = Vacancy.find params[:id] - vacancy.restore! + resource_vacancy.restore! f(:success) redirect_to params[:go_to] || admin_vacancies_path(page: params[:page]) end + def cancel + vacancy = resource_vacancy.becomes(Web::Admin::VacancyForm) + + @vacancy = Admin::VacancyMutator.cancel!(vacancy, params[:vacancy]) + + if @vacancy.canceled? + f(:success) + redirect_to params[:go_to] || new_cancelation_admin_vacancy_path(@vacancy) + else + f(:error, now: true, values: { messages: @vacancy.errors.messages }) + render :new_cancelation, status: :unprocessable_entity + end + end + private def query_params(default_params = {}) default_params.merge(params.permit![:q] || {}) end + + def resource_vacancy + @resource_vacancy ||= Vacancy.find params[:id] + end end diff --git a/app/forms/web/admin/vacancy_form.rb b/app/forms/web/admin/vacancy_form.rb index 6763792f0..71208bed9 100644 --- a/app/forms/web/admin/vacancy_form.rb +++ b/app/forms/web/admin/vacancy_form.rb @@ -35,7 +35,8 @@ class Web::Admin::VacancyForm < Vacancy :technology_list, :direction_list, :employment_type, - :state_event + :state_event, + :cancelation_reason enumerize :salary_amount_type, in: %w[gross net depends] diff --git a/app/lib/notifications_helper.rb b/app/lib/notifications_helper.rb index f6c689882..b52e8b531 100644 --- a/app/lib/notifications_helper.rb +++ b/app/lib/notifications_helper.rb @@ -85,5 +85,18 @@ def next_step_open_source_params(resource) career_path: career_member_path(career.slug, resource, locale: I18n.locale) } end + + def vacancy_publish_params(resource) + { + vacancy_path: vacancy_path(resource, locale: I18n.locale) + } + end + + def vacancy_cancel_params(resource) + { + vacancy_path: vacancy_path(resource, locale: I18n.locale), + cancelation_reason: resource.cancelation_reason_text + } + end end end diff --git a/app/models/notification.rb b/app/models/notification.rb index fe7b75661..5e0576c8c 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -24,10 +24,23 @@ # class Notification < ApplicationRecord include AASM + extend Enumerize + + KINDS_NOTIFICATION = %i[ + new_answer + new_comment + new_answer_like + new_answer_comment + answer_applied + new_career_member + career_member_finish + next_step_open_source + vacancy_publish + vacancy_cancel + ].freeze + + enumerize :kind, in: KINDS_NOTIFICATION - validates :kind, inclusion: { - in: %w[new_answer new_comment new_answer_like new_answer_comment answer_applied new_career_member career_member_finish next_step_open_source] - } validates :resource_type, presence: true belongs_to :user diff --git a/app/models/vacancy.rb b/app/models/vacancy.rb index d50890082..898effe9b 100644 --- a/app/models/vacancy.rb +++ b/app/models/vacancy.rb @@ -7,6 +7,7 @@ # id :integer not null, primary key # about_company :string # about_project :string +# cancelation_reason :string # city_name :string # company_name :string # conditions_description :text @@ -65,6 +66,7 @@ class Vacancy < ApplicationRecord enumerize :location_of_position, in: %w[remote onsite hybrid], default: 'onsite' enumerize :locale, in: %i[en ru], default: :ru enumerize :kind, in: %i[hr habr], predicates: true, scope: true + enumerize :cancelation_reason, in: %i[high_requirements stack_irrelevant low_wage vacancy_competitors education_required], predicates: true, scope: true # Ex:- scope :active, -> {where(:active => true)} # enumerize :programming_language, in: PROGRAMMING_LANGAUGES, default: 'full-time', predicates: true, scope: true # enumerize :country_name, in: COUNTRIES, default: :user, predicates: true, scope: true @@ -86,6 +88,7 @@ class Vacancy < ApplicationRecord unless: -> { salary_amount_type == :depends || salary_from&.positive? } validates :salary_currency, presence: true # validates :programming_language, presence: true + validates :cancelation_reason, presence: true, if: -> { canceled? || state_event == 'cancel' } belongs_to :creator, class_name: 'User' belongs_to :country, optional: true @@ -95,13 +98,14 @@ class Vacancy < ApplicationRecord state :on_moderate state :published state :archived + state :canceled event :publish do transitions to: :published end event :send_to_moderate do - transitions from: :idle, to: :on_moderate + transitions from: %i[idle canceled], to: :on_moderate end event :archive do @@ -111,6 +115,10 @@ class Vacancy < ApplicationRecord event :restore do transitions from: %i[archived], to: :on_moderate end + + event :cancel do + transitions from: %i[on_moderate], to: :canceled + end end def initialize(attribute = nil) diff --git a/app/mutators/admin/vacancy_mutator.rb b/app/mutators/admin/vacancy_mutator.rb new file mode 100644 index 000000000..222acada4 --- /dev/null +++ b/app/mutators/admin/vacancy_mutator.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +class Admin::VacancyMutator + class << self + def cancel!(vacancy, params = {}) + return vacancy if vacancy.canceled? + + user = vacancy.creator + cancelation_reason = params[:cancelation_reason] + vacancy.assign_attributes(cancelation_reason:) + + if vacancy.cancel! + user.notifications.create!(kind: :vacancy_cancel, resource: vacancy) + end + + vacancy + end + + def update(vacancy, params = {}) + user = vacancy.creator + change_to_published = params[:state_event] == 'publish' && !vacancy.published? + + if vacancy.update(params) && change_to_published + user.notifications.create!(kind: :vacancy_publish, resource: vacancy) + end + + vacancy + end + end +end diff --git a/app/views/web/account/vacancies/index.html.slim b/app/views/web/account/vacancies/index.html.slim index c61c40307..f9f3a4fa6 100644 --- a/app/views/web/account/vacancies/index.html.slim +++ b/app/views/web/account/vacancies/index.html.slim @@ -11,6 +11,9 @@ - if policy(vacancy).update? = link_to edit_account_vacancy_path(vacancy) do span.bi.bi-pencil-square.text-muted + - if vacancy.canceled? + span.ms-3 + = t('.cancelation_reason', reason: vacancy.cancelation_reason_text) .card-body h5.card-title = link_to vacancy, vacancy_path(vacancy) diff --git a/app/views/web/admin/vacancies/_vacancies_table.html.slim b/app/views/web/admin/vacancies/_vacancies_table.html.slim index 1172c5d1a..044023d52 100644 --- a/app/views/web/admin/vacancies/_vacancies_table.html.slim +++ b/app/views/web/admin/vacancies/_vacancies_table.html.slim @@ -26,6 +26,9 @@ table.table span.bi.bi-eye-fill = link_to edit_admin_vacancy_path(vacancy), class: 'btn btn-outline-primary btn-sm', title: t('.edit') do span.bi.bi-gear-fill + - if vacancy.may_cancel? + = link_to new_cancelation_admin_vacancy_path(vacancy, go_to: @go_to), class: 'btn btn-outline-warning btn-sm', title: t('.cancel') do + span.bi.bi-x-circle - if vacancy.may_restore? = link_to restore_admin_vacancy_path(vacancy, go_to: @go_to), method: :patch, class: 'btn btn-outline-success btn-sm', data: { confirm: t('.confirm_restore') }, title: t('.restore') do span.bi.bi-arrow-counterclockwise diff --git a/app/views/web/admin/vacancies/new_cancelation.html.slim b/app/views/web/admin/vacancies/new_cancelation.html.slim new file mode 100644 index 000000000..5ab206468 --- /dev/null +++ b/app/views/web/admin/vacancies/new_cancelation.html.slim @@ -0,0 +1,7 @@ += simple_form_for @vacancy, as: :vacancy, url: cancel_admin_vacancy_path(go_to: @go_to), wrapper: 'horizontal_form' do |f| + .mb-3 + .mb-3 + = f.input :cancelation_reason, include_blank: false + .row.mt-5 + .col-sm.d-flex.mb-3 + .me-3 = f.button :submit, class: 'btn-primary' diff --git a/config/locales/admin/en.flash.yml b/config/locales/admin/en.flash.yml index f726e4e27..6fc435adc 100644 --- a/config/locales/admin/en.flash.yml +++ b/config/locales/admin/en.flash.yml @@ -39,8 +39,11 @@ en: success: Resume published successfully update: success: Resume updated successfully - error: Failed to save changes. Please check form fields and try again. + error: "Failed to update job vacancy. Please correct errors in the form: %{messages}" vacancies: + cancel: + success: Vacancy canceled successfull + error: "Failed to decline the job. Please correct errors in the form: %{messages}" archive: success: Vacancy archived successfully restore: diff --git a/config/locales/admin/en.yml b/config/locales/admin/en.yml index 8790b4bf3..a770ec0d1 100644 --- a/config/locales/admin/en.yml +++ b/config/locales/admin/en.yml @@ -99,6 +99,7 @@ en: confirm_restore: Are you sure you want to post your selected vacancy? vacancies_table: edit: Editing Job + cancel: Cancel home: index: admins: Administrators diff --git a/config/locales/admin/ru.flash.yml b/config/locales/admin/ru.flash.yml index 0fafcba18..6b2fc6f8b 100644 --- a/config/locales/admin/ru.flash.yml +++ b/config/locales/admin/ru.flash.yml @@ -47,8 +47,12 @@ ru: success: Вакансия успешно возвращена на модерацию update: success: Вакансия успешно обновлена + error: "Не удалось обновить вакансию. Исправьте ошибки в форме: %{messages}" create: success: Вакансия созданна + cancel: + success: Вакансия отклонена + error: "Не удалось отклонить вакансию. Исправьте ошибки в форме: %{messages}" users: update: success: Данные пользователя успешно обновлены diff --git a/config/locales/admin/ru.yml b/config/locales/admin/ru.yml index 2a8a01d34..a7409ed09 100644 --- a/config/locales/admin/ru.yml +++ b/config/locales/admin/ru.yml @@ -98,6 +98,7 @@ ru: restore: Вернуть на модерацию confirm_archive: Вы уверенны что хотите отправить вакансию в архив confirm_restore: Вы уверенны что хотите вернуть вакансию на модерацию + cancel: Отклонить home: menu: list: Список diff --git a/config/locales/en.activerecord.yml b/config/locales/en.activerecord.yml index 53e970165..76263c53f 100644 --- a/config/locales/en.activerecord.yml +++ b/config/locales/en.activerecord.yml @@ -23,6 +23,7 @@ en: archive: To archive restore: Restore from archive send_to_moderate: Send to moderate + cancel: Cancel attributes: resume/answer: content: Answer @@ -87,6 +88,8 @@ en: state/on_moderate: On moderate state/published: Published state/archived: Archived + state/canceled: Canceled + cancelation_reason: Cancelation reason name: Name company: Company notification: diff --git a/config/locales/en.enumerize.yml b/config/locales/en.enumerize.yml index 35e753268..4e97714ff 100644 --- a/config/locales/en.enumerize.yml +++ b/config/locales/en.enumerize.yml @@ -38,3 +38,9 @@ en: fluent: Speak fluently notification_kind: next_step_open_source: Open source + cancelation_reason: + high_requirements: high requirements for work experience + stack_irrelevant: non-revenant technology stack + low_wage: wages too low + vacancy_competitors: competitors' vacancy + education_required: requires compulsory higher education or to be a university student diff --git a/config/locales/en.notification.yml b/config/locales/en.notification.yml index 66f4450d2..98db87b2e 100644 --- a/config/locales/en.notification.yml +++ b/config/locales/en.notification.yml @@ -10,4 +10,6 @@ en: next_step_open_source_html: | The first half of the Career Track is over! A very important step lies ahead - Participation in Open Source projects
How to choose your first open source project + vacancy_publish_html: Your vacancy has been published + vacancy_cancel_html: Your vacancy was rejected due to %{cancelation_reason} diff --git a/config/locales/en.views.yml b/config/locales/en.views.yml index e4c11df6b..59db2e1ab 100644 --- a/config/locales/en.views.yml +++ b/config/locales/en.views.yml @@ -235,6 +235,7 @@ en: index: resume: Look for candidates in the Resume section header: My vacancies + cancelation_reason: "Reason: %{reason}" resumes: new: info_for_user: Please note that if you plan to look for a job abroad, create a resume in the English version of the site diff --git a/config/locales/ru.activerecord.yml b/config/locales/ru.activerecord.yml index f5a14d99f..b31c2c29e 100644 --- a/config/locales/ru.activerecord.yml +++ b/config/locales/ru.activerecord.yml @@ -15,6 +15,7 @@ ru: archive: Архивировать restore: Восстановить из архива send_to_moderate: Отправить на модерацию + cancel: Отклонить models: career: Карьерный трек @@ -110,8 +111,10 @@ ru: state/published: Опубликована state/archived: В архиве state/on_moderate: На модерации + state/canceled: Отклонена name: Имя company: компания + cancelation_reason: Причина отклонения resume: name: Позиция summary: Описание diff --git a/config/locales/ru.enumerize.yml b/config/locales/ru.enumerize.yml index ffbc054a9..4c0a4508a 100644 --- a/config/locales/ru.enumerize.yml +++ b/config/locales/ru.enumerize.yml @@ -47,3 +47,9 @@ ru: kind: habr: Хабр hr: Консультант + cancelation_reason: + high_requirements: высокие требования к опыту работы + stack_irrelevant: нерелевантный стек технологий + low_wage: слишком низкая заработная плата + vacancy_competitors: вакансия конкурентов + education_required: требуется обязательное высшее образование или быть студентом ВУЗа diff --git a/config/locales/ru.notifications.yml b/config/locales/ru.notifications.yml index 211460964..ef4f34a81 100644 --- a/config/locales/ru.notifications.yml +++ b/config/locales/ru.notifications.yml @@ -10,3 +10,5 @@ ru: next_step_open_source_html: | Первая половина Карьерного трека позади! Впереди очень важный шаг - Участие в Open Source проектах
Как выбрать свой первый опенсорс проект + vacancy_publish_html: Ваша вакансия опубликована + vacancy_cancel_html: Ваша вакансия отклонена по причине - %{cancelation_reason} diff --git a/config/locales/ru.views.yml b/config/locales/ru.views.yml index 4e2d81a48..f76b47ad0 100644 --- a/config/locales/ru.views.yml +++ b/config/locales/ru.views.yml @@ -333,6 +333,7 @@ ru: index: resume: Ищите кандидатов в разделе Резюме header: Мои вакансии + cancelation_reason: "Причина: %{reason}" resumes: new: info_for_user: Обращаем ваше внимание если вы планируете искать работу в России и СНГ, создавайте резюме в русскоязычной версии сайта diff --git a/config/routes.rb b/config/routes.rb index 9e724d16b..b67fd374d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -110,8 +110,10 @@ get :on_moderate end member do + get :new_cancelation patch :archive patch :restore + patch :cancel end end resources :careers, only: [] do diff --git a/db/migrate/20240707200834_add_column_cancelation_reason_to_vacancy.rb b/db/migrate/20240707200834_add_column_cancelation_reason_to_vacancy.rb new file mode 100644 index 000000000..4c9565062 --- /dev/null +++ b/db/migrate/20240707200834_add_column_cancelation_reason_to_vacancy.rb @@ -0,0 +1,5 @@ +class AddColumnCancelationReasonToVacancy < ActiveRecord::Migration[7.1] + def change + add_column :vacancies, :cancelation_reason, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 117783305..870a13ef0 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_01_19_100332) do +ActiveRecord::Schema[7.1].define(version: 2024_07_07_200834) do create_table "career_items", force: :cascade do |t| t.integer "order" t.integer "career_id", null: false @@ -338,6 +338,7 @@ t.datetime "published_at", precision: nil t.integer "external_id" t.string "kind", null: false + t.string "cancelation_reason" t.index ["country_id"], name: "index_vacancies_on_country_id" t.index ["creator_id"], name: "index_vacancies_on_creator_id" t.index ["external_id"], name: "index_vacancies_on_external_id" diff --git a/test/controllers/web/admin/vacancies_controller_test.rb b/test/controllers/web/admin/vacancies_controller_test.rb index a44ddb688..59c395b65 100644 --- a/test/controllers/web/admin/vacancies_controller_test.rb +++ b/test/controllers/web/admin/vacancies_controller_test.rb @@ -55,13 +55,16 @@ class Web::Admin::VacanciesControllerTest < ActionDispatch::IntegrationTest test '#publish' do vacancy = vacancies(:archived) - attrs = vacancy.attributes.merge state_event: :publish + state_event = :publish + attrs = vacancy.attributes.merge(state_event:) previous_published_at = vacancy.published_at patch admin_vacancy_path(vacancy), params: { vacancy: attrs } assert_response :redirect vacancy.reload + notification = Notification.find_by(resource: vacancy, kind: "vacancy_#{state_event}") + assert { notification } assert { vacancy.published_at? } assert { vacancy.published_at != previous_published_at } end @@ -97,4 +100,54 @@ class Web::Admin::VacanciesControllerTest < ActionDispatch::IntegrationTest assert { vacancy.on_moderate? } end + + test '#cancele' do + vacancy = vacancies(:on_moderate) + go_to = on_moderate_admin_vacancies_path + attrs = vacancy.attributes.merge(cancelation_reason: :high_requirements) + + patch cancel_admin_vacancy_path(vacancy), params: { vacancy: attrs, go_to: } + + assert_redirected_to go_to + vacancy.reload + notification = Notification.find_by(resource: vacancy, kind: :vacancy_cancel) + + assert { notification } + assert { vacancy.canceled? } + end + + test '#cancele with invalid params' do + vacancy = vacancies(:on_moderate) + attrs = vacancy.attributes + + patch cancel_admin_vacancy_path(vacancy), params: { vacancy: attrs } + + assert_response :unprocessable_entity + vacancy.reload + notification = Notification.find_by(resource: vacancy, kind: :vacancy_cancel) + + assert { !notification } + assert { vacancy.on_moderate? } + end + + test '#new_cancelation_reason' do + vacancy = vacancies(:on_moderate) + + get new_cancelation_admin_vacancy_path(vacancy) + + assert_response :success + end + + test '#cancel already canceled' do + vacancy = vacancies(:canceled) + attrs = vacancy.attributes.merge(cancelation_reason: :high_requirements) + + assert_no_difference -> { Notification.count } do + patch cancel_admin_vacancy_path(vacancy), params: { vacancy: attrs } + end + assert_redirected_to new_cancelation_admin_vacancy_path(vacancy) + vacancy.reload + + assert { !vacancy.high_requirements? } + end end diff --git a/test/factories/vacancies.rb b/test/factories/vacancies.rb index d941c0900..821da8200 100644 --- a/test/factories/vacancies.rb +++ b/test/factories/vacancies.rb @@ -7,6 +7,7 @@ # id :integer not null, primary key # about_company :string # about_project :string +# cancelation_reason :string # city_name :string # company_name :string # conditions_description :text diff --git a/test/fixtures/notifications.yml b/test/fixtures/notifications.yml index 698aee55f..f9e3f0857 100644 --- a/test/fixtures/notifications.yml +++ b/test/fixtures/notifications.yml @@ -61,4 +61,16 @@ career_member_full_by_full: state: unread kind: new_career_member +vacancy_publish_one: + user: full + resource: one (Vacancy) + state: unread + kind: vacancy_publish + +vacancy_cancel_one: + user: one + resource: canceled (Vacancy) + state: unread + kind: vacancy_cancel + # FIXME: add likes to resume and answers diff --git a/test/fixtures/vacancies.yml b/test/fixtures/vacancies.yml index 14e3e3fdd..2f965e02e 100644 --- a/test/fixtures/vacancies.yml +++ b/test/fixtures/vacancies.yml @@ -5,6 +5,7 @@ # id :integer not null, primary key # about_company :string # about_project :string +# cancelation_reason :string # city_name :string # company_name :string # conditions_description :text @@ -135,6 +136,16 @@ on_moderate: salary_to: 2000 salary_currency: rub +canceled: + <<: *DEFAULTS + title: Canceled + state: canceled + creator: one + salary_from: 1000 + salary_to: 2000 + salary_currency: rub + cancelation_reason: stack_irrelevant + over_month_old: <<: *DEFAULTS title: Фронтендер diff --git a/test/models/vacancy_test.rb b/test/models/vacancy_test.rb index f03c18f6f..2e1ccc624 100644 --- a/test/models/vacancy_test.rb +++ b/test/models/vacancy_test.rb @@ -7,6 +7,7 @@ # id :integer not null, primary key # about_company :string # about_project :string +# cancelation_reason :string # city_name :string # company_name :string # conditions_description :text