Created
December 1, 2012 15:15
-
-
Save tanraya/4182837 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # encoding: utf-8 | |
| require 'valid_email' | |
| class Vacancy < ActiveRecord::Base | |
| include Workflow | |
| # Сколько рубрик разрешено иметь | |
| RUBRICS = 1..3 | |
| # Разрешенные периоды публикации | |
| PUBLICATION_PERIODS = { | |
| :one_week => 1.week, | |
| :two_weeks => 2.weeks, | |
| :three_weeks => 3.weeks, | |
| :one_month => 1.month | |
| } | |
| # Состояния вакансии, в которых ей разрешено показываться на сайте | |
| DISPLAYES_STATES = [:approved, :pending, :archived] | |
| # Предупреждать об истечении срока публикации вакансии за 1 и 3 дня до истечения срока | |
| WARN_EXPIRING_FOR = [1.day, 3.days] | |
| # see https://github.com/rsl/stringex | |
| acts_as_url :post, :url_attribute => :slug, | |
| :sync_url => true, | |
| :allow_duplicates => true | |
| belongs_to :city | |
| belongs_to :company, :counter_cache => true | |
| # TODO Креатором может быть и манагер, сменить на User? | |
| belongs_to :creator, class_name: 'User::Employer' | |
| belongs_to :company_activity, class_name: 'Rubric' | |
| belongs_to :experience, class_name: 'Rubric' | |
| belongs_to :education, class_name: 'Rubric' | |
| belongs_to :gender, class_name: 'Rubric' | |
| belongs_to :work_scheldule, class_name: 'Rubric' | |
| has_many :vacancy_rubrics | |
| has_many :rubrics, :through => :vacancy_rubrics | |
| has_one :favorite, :as => :favoriteable, :dependent => :destroy | |
| # Соблюдаем Law Of Demeter | |
| delegate :subdomain, :to => :city, :prefix => true | |
| accepts_nested_attributes_for :company | |
| # Аттрибуты, которые может менять Работодатель | |
| attr_accessible :age_from, :age_to, :city_id, :company_activity_id, | |
| :conditions, :contact_person, :description, :education_id, :email, :experience_id, | |
| :gender_id, :phones, :post, :publication_period, :requirements, :responsibilities, | |
| :salary, :salary_by_interview, :work_scheldule_id, :workplace_address, :company_attributes, | |
| :rubric_ids, :as => [:user, :admin] | |
| # Аттрибуты, которые может менять Администратор или Менеджер | |
| attr_accessible :state, :company_id, :created_at, :as => :admin | |
| validates :post, :city_id, :gender_id, :age_from, :age_to, :education_id, | |
| :experience_id, :work_scheldule_id, :company_activity_id, :contact_person, | |
| :phones, :presence => true | |
| validates :city_id, :gender_id, :age_from, :age_to, :education_id, | |
| :experience_id, :work_scheldule_id, :company_activity_id, | |
| :numericality => true | |
| validates :publication_period, :inclusion => { :in => PUBLICATION_PERIODS.keys.map(&:to_s) } | |
| validates :salary, :presence => true, :numericality => true#, :unless => :salary_by_interview? | |
| validates :email, :email => true, :allow_blank => true | |
| validates :rubric_ids, :length => { | |
| :minimum => RUBRICS.min, | |
| :maximum => RUBRICS.max | |
| } | |
| # Описываем состояния | |
| workflow_column :state | |
| workflow do | |
| # На рассмотрении | |
| state :pending do | |
| event :approve, :transitions_to => :approved | |
| event :archive, :transitions_to => :archived | |
| event :remove, :transitions_to => :deleted | |
| end | |
| # Принята | |
| state :approved do | |
| event :suspend, :transitions_to => :pending | |
| event :archive, :transitions_to => :archived | |
| event :remove, :transitions_to => :deleted | |
| end | |
| # Заархивирована | |
| state :archived do | |
| event :approve, :transitions_to => :approved | |
| event :remove, :transitions_to => :deleted | |
| end | |
| # Удалена | |
| state :deleted | |
| end | |
| # Scope по-умолчанию. Добавляется к каждому запросу. Нужно это помнить. | |
| default_scope do | |
| where(:city_id => City.current_city).displayed.approved.descending | |
| end | |
| # Вакансии, отображаемые на сайте. Вакансии со статусом :deleted вообще | |
| # не должны отображаться на сайте в любых случаях. | |
| scope :displayed, ->{ where(:state => DISPLAYES_STATES) } | |
| # Принятые/на рассмотрении | |
| scope :approved, ->{ where(:state => :approved) } | |
| scope :suspended, ->{ where(:state => :pending) } | |
| scope :archived, ->{ where(:state => :archived) } | |
| scope :deleted, ->{ where(:state => :deleted) } | |
| # Вакансии, у которых истекает срок публикации | |
| scope :expiring, ->{ approved.where(build_expiring_conditions) } | |
| # Актуальные/неактуальные вакансии | |
| scope :relevant, ->{ displayed.where("NOW() < expired_at") } | |
| scope :irrelevant, ->{ displayed.where("NOW() > expired_at") } | |
| scope :descending, ->{ order('approved_at, created_at DESC') } | |
| scope :recent, ->{ displayed.approved.limit(20) } | |
| # Выборка вакансий по рубрике | |
| scope :by_rubric, ->(rubric_id){ joins(:rubrics).where(:rubrics => { :id => rubric_id }) } | |
| before_save :bind_to_company_and_creator | |
| before_save :setup_approve | |
| after_initialize :setup_defaults | |
| # Вакансия актуальна? | |
| def relevant? | |
| (Time.now > expired_at) && approved? | |
| end | |
| # Вакансия неактуальна? | |
| def irrelevant? | |
| not relevant? | |
| end | |
| # Находится ли вакансия в избранном? | |
| def favorite? | |
| favorite.present? | |
| end | |
| def to_s | |
| post | |
| end | |
| def to_param | |
| "#{id}-#{slug}" | |
| end | |
| class << self | |
| def states | |
| workflow_spec.states.keys | |
| end | |
| # Архивирование вакансий. Устанавливаем для неактуальных статус archived | |
| def archive_irrelevant! | |
| Vacancy.unscoped.irrelevant.update_all(:state => 'archived') | |
| end | |
| # Построение условий для поиска вакансий, у которых истекает срок публикации | |
| def build_expiring_conditions | |
| conditions = [] | |
| WARN_EXPIRING_FOR.each do |expire_in_seconds| | |
| # Время в будущем, когда вакансия будет снята с публикации | |
| expires_in = Time.now + expire_in_seconds | |
| # Составляем запрос: expires_in_future BEETWEEN expired_at_begin_of_day AND expired_at_end_of_day | |
| conditions << "('#{expires_in}'::timestamp BETWEEN DATE_TRUNC('day', expired_at) AND DATE_TRUNC('day', expired_at + INTERVAL '1 day'))" | |
| end | |
| "(#{conditions.join(' OR ')})" | |
| end | |
| end | |
| private | |
| # Прикрепляем компанию и пользователя (создателя) к вакансии | |
| def bind_to_company_and_creator | |
| creator = User.current | |
| self.creator_id ||= creator.id | |
| self.company_id = creator.profile.company.id if User.current.is_a?(User::Employer) | |
| end | |
| # Значения по-умолчанию | |
| def setup_defaults | |
| case User.current | |
| when User::Employer | |
| self.contact_person ||= User.current.profile.company.contact_person | |
| self.workplace_address ||= User.current.profile.company.office_address | |
| when User::Manager, User::Admin | |
| self.created_at = Time.now.to_date | |
| end | |
| end | |
| def setup_approve | |
| if state_was != 'approved' && approved? | |
| # При переходе в состояние approved обновляем время аппрува | |
| self.approved_at = Time.now | |
| # Рассчитываем время окончания публикации вакансии | |
| self.expired_at = self.approved_at + PUBLICATION_PERIODS[publication_period.to_sym] | |
| # Уведомляем работодателя | |
| VacancyMailer.vacancy_approved(self).deliver | |
| end | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment