Commit 424b9d2b by phuctmZigexn

Merge branch 'Task/15_favorite_job_ID8_history_ID9' into 'master'

Feature favorite and history

See merge request !15
parents a06436f1 3a2d621e
...@@ -65,4 +65,4 @@ gem 'nokogiri', '~> 1.11', '>= 1.11.7' ...@@ -65,4 +65,4 @@ gem 'nokogiri', '~> 1.11', '>= 1.11.7'
gem 'httparty', '~> 0.18.1' gem 'httparty', '~> 0.18.1'
gem 'active_storage_validations', '~> 0.9.5' gem 'active_storage_validations', '~> 0.9.5'
gem 'devise', '~> 4.8' gem 'devise', '~> 4.8'
gem 'jquery-rails', '~> 4.4' gem 'jquery-rails', '~> 4.4'
\ No newline at end of file
...@@ -65,95 +65,35 @@ footer { ...@@ -65,95 +65,35 @@ footer {
} }
} }
// Top page // flash message
// search /*flash*/
.alert-error {
background-color: #f2dede;
// latest-job border-color: #eed3d7;
color: #b94a48;
text-align: left;
}
.latest-job { .alert-alert {
.job-item { background-color: #f2dede;
font-size: 14px; border-color: #eed3d7;
.job-title { color: #b94a48;
text-decoration: none; text-align: left;
color: black;
font-size: 20px;
font-weight: 500;
}
.job-caption {
line-height: 18px;
.job-company {
text-decoration: none;
font-size: 14px;
color: $gray-700;
}
.job-salary {
color: #008563;
margin: 0;
}
.job-locations {
ul {
list-style: none;
margin: 0 0 6px 0;
padding: 0;
color: $gray-700;
}
}
.job-desc {
overflow: hidden;
text-overflow: ellipsis;
line-height: 18px;
-webkit-line-clamp: 2;
max-height: 36px;
display: -webkit-box;
-webkit-box-orient: vertical;
}
}
}
} }
// top_cities .alert-success {
background-color: #dff0d8;
border-color: #d6e9c6;
color: #468847;
text-align: left;
}
.top_cities { .alert-notice {
.city-item { background-color: #dff0d8;
margin-bottom: 12px; border-color: #d6e9c6;
a { color: #468847;
font-size: 18px; text-align: left;
text-decoration: none;
color: #287ab9;
margin: 10px 0;
}
}
.all-cities-btn {
color: #287ab9;
font-size: 20px;
text-decoration: none;
}
.all-cities-btn:hover {
text-decoration: underline;
}
} }
// top_industries
.top_industries {
.industry-item {
margin-bottom: 12px;
a {
font-size: 18px;
text-decoration: none;
color: #287ab9;
margin: 10px 0;
}
}
.all-industries-btn {
color: #287ab9;
font-size: 20px;
text-decoration: none;
}
.all-industries-btn:hover {
text-decoration: underline;
}
}
// cities list
...@@ -9,7 +9,7 @@ class ApplicationController < ActionController::Base ...@@ -9,7 +9,7 @@ class ApplicationController < ActionController::Base
def configure_permitted_parameters def configure_permitted_parameters
devise_parameter_sanitizer.permit :sign_up, keys: %i[name address phone email password] devise_parameter_sanitizer.permit :sign_up, keys: %i[name address phone email password]
devise_parameter_sanitizer.permit :account_update, keys: %i[name email address phone password current_password] devise_parameter_sanitizer.permit :account_update, keys: %i[name email address phone password cv]
end end
private private
......
class AppliesController < ApplicationController class AppliesController < ApplicationController
before_action :authenticate_user!
before_action :load_job, only: %i[new confirm create] before_action :load_job, only: %i[new confirm create]
def index
@jobs = current_user.apply_jobs.eager_load(job: %i[cities cities_jobs company])
.page(params[:page]).per(Job::JOB_PER_PAGE)
end
def new def new
if use_apply_job_session? if use_apply_job_session?
build_params = session[:apply_job] build_params = session[:apply_job]
...@@ -11,7 +17,6 @@ class AppliesController < ApplicationController ...@@ -11,7 +17,6 @@ class AppliesController < ApplicationController
def confirm def confirm
@apply = current_user.apply_jobs.build(apply_params) @apply = current_user.apply_jobs.build(apply_params)
@apply.job = @job
if @apply.valid? if @apply.valid?
@blob = ActiveStorage::Blob.create_and_upload!( @blob = ActiveStorage::Blob.create_and_upload!(
...@@ -28,7 +33,6 @@ class AppliesController < ApplicationController ...@@ -28,7 +33,6 @@ class AppliesController < ApplicationController
def create def create
@apply = current_user.apply_jobs.build(apply_params) @apply = current_user.apply_jobs.build(apply_params)
@apply.job = @job
@apply.cv = ActiveStorage::Blob.find(session[:blob_id]) @apply.cv = ActiveStorage::Blob.find(session[:blob_id])
if @apply.save if @apply.save
...@@ -54,10 +58,6 @@ class AppliesController < ApplicationController ...@@ -54,10 +58,6 @@ class AppliesController < ApplicationController
params.require(:apply_job).permit(:user_name, :email, :cv, :job_id) params.require(:apply_job).permit(:user_name, :email, :cv, :job_id)
end end
def current_user
@current_user ||= User.first
end
def use_apply_job_session? def use_apply_job_session?
request.referer&.include?('confirm') && session[:apply_job].present? request.referer&.include?('confirm') && session[:apply_job].present?
end end
......
class FavoriteJobsController < ApplicationController
before_action :logged_in_user
before_action :load_job, only: %i[create destroy]
def index
@favorite_jobs = current_user.favorite_jobs.eager_load(job: %i[cities cities_jobs company])
.page(params[:page]).per(Job::JOB_PER_PAGE)
end
def create
@favorite_job = current_user.favorite_jobs.build(job_id: @job.id)
respond_to :js if @favorite_job.save
end
def destroy
@favorite_job = current_user.favorite_jobs.find_by(job_id: @job.id)
respond_to :js if @favorite_job.destroy
end
private
def load_job
@job = Job.find_by(id: params[:job_id])
end
end
class HistoryJobsController < ApplicationController
before_action :logged_in_user
def index
@history_jobs = current_user.history_jobs.eager_load(job: %i[cities cities_jobs company])
.page(params[:page]).per(Job::JOB_PER_PAGE)
end
end
class JobsController < ApplicationController class JobsController < ApplicationController
before_action :history, only: :show
def index def index
if job_params.present? if job_params.present?
search search
...@@ -14,6 +16,13 @@ class JobsController < ApplicationController ...@@ -14,6 +16,13 @@ class JobsController < ApplicationController
private private
def history
return unless user_signed_in?
history = current_user.history_jobs.find_or_initialize_by(job_id: params[:id])
history.update(updated_at: Time.current)
end
def search def search
if job_params.key?(:model) && job_params.key?(:slug) # search by model if job_params.key?(:model) && job_params.key?(:slug) # search by model
model = params[:model].classify.constantize model = params[:model].classify.constantize
......
# frozen_string_literal: true
class Users::ConfirmationsController < Devise::ConfirmationsController
# GET /resource/confirmation/new
# POST /resource/confirmation
# def create
# super
# end
# GET /resource/confirmation?confirmation_token=abcdef
# def show
# super
# end
protected
def after_confirmation_path_for(resource_name, resource)
sign_in(resource)
token = resource.send(:set_reset_password_token)
signup_infomation_path(reset_password_token: token)
end
end
# frozen_string_literal: true
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
# You should configure your model like this:
# devise :omniauthable, omniauth_providers: [:twitter]
# You should also create an action method in this controller like this:
# def twitter
# end
# More info at:
# https://github.com/heartcombo/devise#omniauth
# GET|POST /resource/auth/twitter
# def passthru
# super
# end
# GET|POST /users/auth/twitter/callback
# def failure
# super
# end
# protected
# The path used when OmniAuth fails
# def after_omniauth_failure_path_for(scope)
# super(scope)
# end
end
# frozen_string_literal: true
class Users::PasswordsController < Devise::PasswordsController
# GET /resource/password/new
# def new
# super
# end
# POST /resource/password
# def create
# super
# end
# GET /resource/password/edit?reset_password_token=abcdef
# def edit
# super
# end
# PUT /resource/password
# def update
# super
# end
# protected
# def after_resetting_password_path_for(resource)
# super(resource)
# end
# The path used after sending reset password instructions
# def after_sending_reset_password_instructions_path_for(resource_name)
# super(resource_name)
# end
end
# frozen_string_literal: true
class Users::RegistrationsController < Devise::RegistrationsController
# before_action :configure_sign_up_params, only: [:create]
# before_action :configure_account_update_params, only: [:update]
def information
self.resource = resource_class.new
signed_in_resource
render :infomation
end
def send_mail; end
protected
def update_resource(resource, params)
resource.update_without_password(params)
end
def after_inactive_sign_up_path_for(resource)
scope = Devise::Mapping.find_scope!(resource)
router_name = Devise.mappings[scope].router_name
context = router_name ? send(router_name) : self
context.respond_to?(:send_signup_mail_path) ? context.send_signup_mail_path : "/"
end
end
# frozen_string_literal: true
class Users::SessionsController < Devise::SessionsController
# before_action :configure_sign_in_params, only: [:create]
# GET /resource/sign_in
# def new
# super
# end
# POST /resource/sign_in
# def create
# super
# end
# DELETE /resource/sign_out
# def destroy
# super
# end
# protected
# If you have extra params to permit, append them to the sanitizer.
# def configure_sign_in_params
# devise_parameter_sanitizer.permit(:sign_in, keys: [:attribute])
# end
end
# frozen_string_literal: true
class Users::UnlocksController < Devise::UnlocksController
# GET /resource/unlock/new
# def new
# super
# end
# POST /resource/unlock
# def create
# super
# end
# GET /resource/unlock?unlock_token=abcdef
# def show
# super
# end
# protected
# The path used after sending unlock password instructions
# def after_sending_unlock_instructions_path_for(resource)
# super(resource)
# end
# The path used after unlocking the resource
# def after_unlock_path_for(resource)
# super(resource)
# end
end
class UsersController < ApplicationController class UsersController < ApplicationController
before_action :logged_in_user # before_action :logged_in_user
def show def show
@user = User.find(params[:id]) @user = current_user
end end
end end
module DeviseHelper
def devise_error_messages!
return '' if resource.errors.empty?
messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
html = <<-HTML
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<button type="button" class="close" data-dismiss="alert">
<span aria-hidden="true">&times;</span>
</button>
<strong>
#{pluralize(resource.errors.count, 'error')} must be fixed
</strong>
#{messages}
</div>
HTML
html.html_safe
end
end
...@@ -3,6 +3,11 @@ ...@@ -3,6 +3,11 @@
// a relevant structure within app/javascript and only use these pack files to reference // a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled. // that code so it'll be compiled.
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .
import Rails from "@rails/ujs" import Rails from "@rails/ujs"
import Turbolinks from "turbolinks" import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage" import * as ActiveStorage from "@rails/activestorage"
......
...@@ -78,21 +78,39 @@ Validator = function(options) { ...@@ -78,21 +78,39 @@ Validator = function(options) {
} }
} }
Validator.isRequired = function (selector) { Validator.isRequired = function (selector, message) {
return { return {
selector: selector, selector: selector,
test: function (value) { test: function (value) {
return value.trim() ? undefined : "This field can't be blank" return value.trim() ? undefined : message || "This field can't be blank"
} }
} }
} }
Validator.isEmail = function (selector) { Validator.isEmail = function (selector, message) {
return { return {
selector: selector, selector: selector,
test: function (value) { test: function (value) {
var regex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; var regex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return regex.test(value) ? undefined : 'Email invalid'; return regex.test(value) ? undefined : message || 'Email invalid';
}
}
}
Validator.minLenght = function (selector, min, message) {
return {
selector: selector,
test: function (value) {
return value.length >= min ? undefined : message || 'field too short';
}
}
}
Validator.isConfirmed = function (selector, getConfirmValue, message) {
return {
selector: selector,
test: function (value) {
return value == getConfirmValue() ? undefined : message || 'Incorrect password';
} }
} }
} }
......
class HistoryJob < ApplicationRecord class HistoryJob < ApplicationRecord
before_save :history_count
belongs_to :job belongs_to :job
belongs_to :user belongs_to :user
private
def history_count
history_list = user.history_jobs.order(updated_at: :desc)
history_list.last.destroy if history_list.count >= 20
end
end end
class Job < ApplicationRecord class Job < ApplicationRecord
scope :jobs_of, ->(model, user_id) do
joins(model.to_sym)
.where("#{model.to_sym}.user_id = #{user_id}")
.eager_load(:cities, :cities_jobs, :company)
end
LATEST_JOBS_LIMIT = 5 LATEST_JOBS_LIMIT = 5
JOB_PER_PAGE = 20 JOB_PER_PAGE = 20
...@@ -7,9 +13,9 @@ class Job < ApplicationRecord ...@@ -7,9 +13,9 @@ class Job < ApplicationRecord
belongs_to :company belongs_to :company
has_many :apply_jobs, dependent: :destroy has_many :apply_jobs, dependent: :destroy
has_many :favorite_jobs, dependent: :destroy has_many :favorite_jobs, dependent: :destroy
has_many :history_job, dependent: :destroy has_many :history_jobs, dependent: :destroy
def self.sort_by_date(page: 1, per_page: limit) def self.sort_by_date(page: 1, per_page: 1)
includes(:cities, :cities_jobs, :company).order(created_at: :desc).page(page).per(per_page).references(:cities) includes(:cities, :cities_jobs, :company).order(created_at: :desc).page(page).per(per_page).references(:cities)
end end
end end
class User < ApplicationRecord class User < ApplicationRecord
# Include default devise modules. Others available are: ACCEPT_CONTENT_TYPE = 'application/pdf, application/msword, application/zip, application/xls, application/xlsx'.freeze
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable, devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable :recoverable, :rememberable, :validatable, :confirmable
has_many :apply_jobs, dependent: :destroy has_many :apply_jobs, dependent: :destroy
has_many :favorite_jobs, dependent: :destroy has_many :favorite_jobs, dependent: :destroy
has_many :history_jobs, dependent: :destroy has_many :history_jobs, dependent: :destroy
has_one_attached :cv has_one_attached :cv
validates :cv, content_type: { in: ACCEPT_CONTENT_TYPE,
message: 'must be a valid cv format' },
size:
{ less_than: 5.megabytes,
message: 'should be less than 5MB' }
def update_without_password(params, *options)
if params[:password].blank?
params.delete(:password)
params.delete(:password_confirmation) if params[:password_confirmation].blank?
end
result = update(params, *options)
clean_up_passwords
result
end
def favorite?(job)
@favorite_job_ids ||= Set.new(favorite_jobs.pluck(:job_id))
@favorite_job_ids.include?(job.id)
end
protected
def password_required?
confirmed? ? super : false
end
end end
.job-item
.job-head.d-flex.align-items-center.justify-content-between
= link_to applied_job.job.title, applied_job.job, class: 'job-title fs-3 text-decoration-none text-reset'
- if user_signed_in? && current_user.favorite?(applied_job.job)
= render 'shared/unfavorite', job_id: applied_job.job.id
- else
= render 'shared/favorite', job_id: applied_job.job.id
.job-caption
= link_to applied_job.job.company.name, '#', class: 'job-company text-decoration-none text-secondary'
p.job-salary.text-success
| Salary: #{applied_job.job.salary}
ul.list-unstyled
= show_location(applied_job.job.cities)
.job-desc
= truncate(simple_format(applied_job.job.description), escape: false, length: 250)
.applied-at
strong Applied at:
= applied_job.updated_at.strftime('%d/%m/%Y')
hr.my-4
- provide(:title, 'User Apply Jobs')
.container.py-5
h1.text-center.my-job-label My Job
.no-padding.d-flex.align-items-center.flex-column
.page-info.p-2
= page_entries_info @jobs
.page-info.p-2
= paginate @jobs
= render partial: "my_jobs", collection: @jobs, as: :applied_job
.no-padding.d-flex.align-items-center.flex-column
.page-info.p-2
= page_entries_info @jobs
.page-info.p-2
= paginate @jobs
$("#favorite-<%= @job.id %>").html("<%= escape_javascript(render('shared/unfavorite', job_id: @job.id)) %>");
$("#unfavorite-<%= @job.id %>").html("<%= escape_javascript(render('shared/favorite', job_id: @job.id)) %>");
- provide(:title, 'History page')
- if @favorite_jobs.empty?
h2 No jobs in your history
- else
= render partial: 'shared/jobs_list_index', object: @favorite_jobs, as: 'jobs'
- provide(:title, 'History page')
- if @history_jobs.empty?
h2 No jobs in your history
- else
= render partial: 'shared/jobs_list_index', object: @history_jobs, as: 'jobs'
...@@ -15,7 +15,12 @@ ...@@ -15,7 +15,12 @@
- @jobs.each do |job| - @jobs.each do |job|
/ job / job
.job-item .job-item
= link_to job.title, job, class: 'job-title fs-3 text-decoration-none text-reset' .job-head.d-flex.align-items-center.justify-content-between
= link_to job.title, job, class: 'job-title fs-3 text-decoration-none text-reset'
- if user_signed_in? && current_user.favorite?(job)
= render 'shared/unfavorite', job_id: job.id
- else
= render 'shared/favorite', job_id: job.id
.job-caption .job-caption
= link_to job.company.name, '#', class: 'job-company text-decoration-none text-secondary' = link_to job.company.name, '#', class: 'job-company text-decoration-none text-secondary'
p.job-salary.text-success p.job-salary.text-success
......
...@@ -85,4 +85,7 @@ ruby: ...@@ -85,4 +85,7 @@ ruby:
= info = info
.job-apply.d-flex.align-items-center.justify-content-between .job-apply.d-flex.align-items-center.justify-content-between
= link_to 'Apply for this job', apply_job_path(job_id: @job.id), class: 'btn btn-primary' = link_to 'Apply for this job', apply_job_path(job_id: @job.id), class: 'btn btn-primary'
= link_to 'Favorite', '#', class: 'btn btn-primary' - if user_signed_in? && current_user.favorite?(@job)
= render 'shared/unfavorite', job_id: @job.id
- else
= render 'shared/favorite', job_id: @job.id
...@@ -6,11 +6,17 @@ header.navbar.navbar-fixed-top.navbar-inverse ...@@ -6,11 +6,17 @@ header.navbar.navbar-fixed-top.navbar-inverse
ul.nav.navbar-nav.navbar-right.text-light ul.nav.navbar-nav.navbar-right.text-light
- if user_signed_in? - if user_signed_in?
li li
= link_to "Profile", current_user = link_to "Apply jobs", apply_jobs_path
li
= link_to "History", history_jobs_path
li
= link_to "Favorite", favorite_jobs_path
li
= link_to "Profile", user_profile_path
li li
= link_to "Log out", destroy_user_session_path, method: :delete = link_to "Log out", destroy_user_session_path, method: :delete
- else - else
li li
= link_to "Log in", new_user_session_path = link_to "Log in", login_path
li li
= link_to "Sign up", new_user_registration_path = link_to "Sign up", signup_path
...@@ -12,12 +12,7 @@ html ...@@ -12,12 +12,7 @@ html
= yield(:head) = yield(:head)
body body
= render 'layouts/header' = render 'layouts/header'
.container-fluid style ="min-height:80vh;" .container-fluid style ="min-height:80vh;"
/ .container-fluid class=("text-center alert alert-#{notice}")
/ p.notice
/ = notice
/ p.alert
/ = alert
- flash.each do |message_type, message| - flash.each do |message_type, message|
div class=("text-center alert alert-#{message_type}") = message div class=("text-center alert alert-#{message_type}") = message
= yield = yield
......
div id="favorite-#{job_id}"
= link_to favorite_jobs_path(job_id: job_id, format: :js),
method: :post,
remote: true,
class: 'btn btn-primary'
| Favorite
.container.py-5
.no-padding.d-flex.align-items-center.flex-column
.page-info.p-2
= page_entries_info jobs
.page-info.p-2
= paginate jobs
.container
= form_with(url: apply_job_path, method: :get) do |f|
- jobs.each do |item|
.row
.col-1.job-check.align-self-center
= f.radio_button :job_id, item.job.id, class: 'btn-check', id: "option-#{item.job.id}"
= f.label 'Choose', class: 'btn btn-outline-primary', for: "option-#{item.job.id}"
.job-item.col-10
.job-head
= link_to item.job.title, item.job, class: 'job-title fs-3 text-decoration-none text-reset'
.job-caption
= link_to item.job.company.name, '#', class: 'job-company text-decoration-none text-secondary'
p.job-salary.text-success
| Salary: #{item.job.salary}
ul.list-unstyled
= show_location(item.job.cities)
.job-desc
= truncate(simple_format(item.job.description), escape: false, length: 250)
.job-fav.col-1
- if user_signed_in? && current_user.favorite?(item.job)
= render 'shared/unfavorite', job_id: item.job.id
- else
= render 'shared/favorite', job_id: item.job.id
hr.my-4
.d-flex.justify-content-center
= f.submit 'Apply job', class: 'btn btn-primary w-50'
.no-padding.d-flex.align-items-center.flex-column
.page-info.p-2
= page_entries_info jobs
.page-info.p-2
= paginate jobs
div id="unfavorite-#{job_id}"
= link_to favorite_job_path(current_user, job_id: job_id, format: :js),
method: :delete,
remote: true,
class: 'btn btn-secondary'
| UnFavorite
<h2><%= t "devise.invitations.edit.header" %></h2>
<%= form_for(resource, as: resource_name, url: invitation_path(resource_name), html: { method: :put }) do |f| %>
<%= render "users/shared/error_messages", resource: resource %>
<%= f.hidden_field :invitation_token, readonly: true %>
<% if f.object.class.require_password_on_accepting %>
<div class="field">
<%= f.label :password %><br />
<%= f.password_field :password %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %>
</div>
<% end %>
<div class="actions">
<%= f.submit t("devise.invitations.edit.submit_button") %>
</div>
<% end %>
<h2><%= t "devise.invitations.new.header" %></h2>
<%= form_for(resource, as: resource_name, url: invitation_path(resource_name), html: { method: :post }) do |f| %>
<%= render "users/shared/error_messages", resource: resource %>
<% resource.class.invite_key_fields.each do |field| -%>
<div class="field">
<%= f.label field %><br />
<%= f.text_field field %>
</div>
<% end -%>
<div class="actions">
<%= f.submit t("devise.invitations.new.submit_button") %>
</div>
<% end %>
<p><%= t("devise.mailer.invitation_instructions.hello", email: @resource.email) %></p>
<p><%= t("devise.mailer.invitation_instructions.someone_invited_you", url: root_url) %></p>
<p><%= link_to t("devise.mailer.invitation_instructions.accept"), accept_invitation_url(@resource, invitation_token: @token) %></p>
<% if @resource.invitation_due_at %>
<p><%= t("devise.mailer.invitation_instructions.accept_until", due_date: l(@resource.invitation_due_at, format: :'devise.mailer.invitation_instructions.accept_until_format')) %></p>
<% end %>
<p><%= t("devise.mailer.invitation_instructions.ignore") %></p>
<%= t("devise.mailer.invitation_instructions.hello", email: @resource.email) %>
<%= t("devise.mailer.invitation_instructions.someone_invited_you", url: root_url) %>
<%= accept_invitation_url(@resource, invitation_token: @token) %>
<% if @resource.invitation_due_at %>
<%= t("devise.mailer.invitation_instructions.accept_until", due_date: l(@resource.invitation_due_at, format: :'devise.mailer.invitation_instructions.accept_until_format')) %>
<% end %>
<%= t("devise.mailer.invitation_instructions.ignore") %>
<p>Hello <%= @resource.email %>!</p>
<p>Someone has requested a link to change your password. You can do this through the link below.</p>
<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p>
<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>
p
| Dear #{@resource.email}!
p You have a new password!
p Your password for signing in to VenJOB was recently changed. If you made this change, then we're all set.
p= link_to 'Change my password', reset_password_url(reset_password_token: @token)
p If you did not make this change, please reset your password to secure your account. Then reply to this email to notify us.
p Either way, feel free to reach out with any questions you might have. We're here to help.
p Best
\ No newline at end of file
- provide(:title, "Change password") - provide(:title, 'Change password')
.container .container
.row.justify-content-center .row.justify-content-center
.col-6 .col-6
h2.text-center.my-5 h2.text-center.my-5
| Change your password | Set your password
= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| = form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f|
= render "users/shared/error_messages", resource: resource = render 'users/shared/error_messages', resource: resource
= f.hidden_field :reset_password_token = f.hidden_field :reset_password_token
.field .field.row.mb-5.form-group
= f.label :password, "New password", class: 'form-label' .col-4
br/ = f.label :password, 'New password', class: 'form-label'
- if @minimum_password_length .col-8
em = f.password_field :password, autofocus: true, autocomplete: 'new-password', class: 'form-control mb-2'
| (#{@minimum_password_length} characters minimum) span.form-msg
br/ .field.row.mb-5.form-group
= f.password_field :password, autofocus: true, autocomplete: "new-password", class: 'form-control mb-2' .col-4
.field = f.label :password_confirmation, 'Password Confirmation', class: 'form-label'
= f.label :password_confirmation, "Confirm new password", class: 'form-label' .col-8
br/ = f.password_field :password_confirmation, autocomplete: 'new-password', class: 'form-control mb-2'
= f.password_field :password_confirmation, autocomplete: "new-password", class: 'form-control mb-2' span.form-msg
.actions .actions.row.justify-content-end
= f.submit "Change my password", class: 'btn btn-primary w-100 my-4' .col-8
= render "users/shared/links" = f.submit 'Set my password', class: 'btn btn-primary w-50 my-4', data: { disable_with: false }
javascript:
Validator({
form: '#new_user',
errorSelector: '.form-msg',
rules: [
Validator.isRequired('#user_password'),
Validator.minLenght('#user_password', 6, 'Use 6 characters or more for your password'),
Validator.isRequired('#user_password_confirmation'),
Validator.isConfirmed('#user_password_confirmation', function() {
return document.querySelector('#new_user #user_password').value;
}, 'Those passwords didn’t match.'),
]
})
- provide(:title, "Forgot password") - provide(:title, 'Forgot password')
.container .container
.row.justify-content-center .row.justify-content-center
.col-6 .col-6
h2.text-center.my-5 h2.text-center.my-5
| Forgot your password? | Forgot password
= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| = form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f|
= render "users/shared/error_messages", resource: resource = render 'users/shared/error_messages', resource: resource
.field .field.row.form-group.mb-4
= f.label :email, class: 'form-label' .col-2
br/ = f.label :email, class: 'form-label'
= f.email_field :email, autofocus: true, autocomplete: "email", class: 'form-control mb-2' .col-10
.actions = f.email_field :email, autofocus: true, autocomplete: 'email', class: 'form-control mb-2'
= f.submit "Send me reset password instructions", class: 'btn btn-primary w-100 my-4' span.form-msg
= render "users/shared/links" - if devise_mapping.confirmable? && controller_name != 'confirmations'
p
= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name), class: 'text-decoration-none'
.actions.row.justify-content-end
.col-10.d-flex.justify-content-center
= f.submit 'Confirm your email', class: 'btn btn-primary w-75 my-4', data: { disable_with: false }
javascript:
Validator({
form: '#new_user',
errorSelector: '.form-msg',
rules: [
Validator.isRequired('#user_email'),
Validator.isEmail('#user_email')
]
})
- provide(:title, "Edit profile") - provide(:title, 'Edit profile')
.container .container
.row.justify-content-center .row.justify-content-center
.col-6 .col-8
h2.text-center.my-5 h2.text-center.my-5
| Edit | Edit
= resource_name.to_s.humanize = resource_name.to_s.humanize
= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| = form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f|
= render "users/shared/error_messages", resource: resource = render 'users/shared/error_messages', resource: resource
.field .field.row.mb-2.form-group
= f.label :email, class: 'form-label' .col-3
br = f.label :email, class: 'form-label'
= f.email_field :email, autofocus: true, autocomplete: "email", class: 'form-control mb-2' .col-9
.field = f.email_field :email, autofocus: true, autocomplete: 'email', class: 'form-control mb-2'
span.form-msg
.field.row.mb-2.form-group
- if devise_mapping.confirmable? && resource.pending_reconfirmation? - if devise_mapping.confirmable? && resource.pending_reconfirmation?
div div
| Currently waiting confirmation for: | Currently waiting confirmation for:
= resource.unconfirmed_email = resource.unconfirmed_email
.field .field.row.mb-2.form-group
= f.label :name, class: 'form-label' .col-3
br = f.label :name, class: 'form-label'
= f.text_field :name, autofocus: true, autocomplete: "name", class: 'form-control mb-2' .col-9
.field = f.text_field :name, autofocus: true, autocomplete: 'name', class: 'form-control mb-2'
= f.label :address, class: 'form-label' span.form-msg
br .field.row.mb-2.form-group
= f.text_field :address, autofocus: true, autocomplete: "address", class: 'form-control mb-2' .col-3
.field = f.label :address, class: 'form-label'
= f.label :phone, class: 'form-label' .col-9
br = f.text_field :address, autofocus: true, autocomplete: 'address', class: 'form-control mb-2'
= f.text_field :phone, autofocus: true, autocomplete: "phone", class: 'form-control mb-2' span.form-msg
.field .field.row.mb-2.form-group
= f.label :password, class: 'form-label' .col-3
i = f.label :phone, class: 'form-label'
| (leave blank if you don't want to change it) .col-9
br = f.text_field :phone, autofocus: true, autocomplete: 'phone', class: 'form-control mb-2'
= f.password_field :password, autocomplete: "new-password", class: 'form-control mb-2' span.form-msg
- if @minimum_password_length .field.row.mb-2.form-group
em .col-3
= @minimum_password_length = f.label :cv, class: 'form-label'
| characters minimum .col-9
.field = f.file_field :cv, accept: ApplyJob::ACCEPT_CONTENT_TYPE, class: 'form-control', direct_upload: true
= f.label :password_confirmation, class: 'form-label'
br .row.my-4.justify-content-end
= f.password_field :password_confirmation, autocomplete: "new-password", class: 'form-control mb-2' .col-9
.field hr
= f.label :current_password, class: 'form-label' p
i |(leave password blank if you don't want to change it)
| (we need your current password to confirm your changes)
br .field.row.mb-2.form-group
= f.password_field :current_password, autocomplete: "current-password", class: 'form-control mb-2' .col-3
.actions = f.label :password, class: 'form-label'
= f.submit "Done", class: "btn btn-primary w-100 my-4" .col-9
= f.password_field :password, autocomplete: 'new-password', class: 'form-control mb-2'
span.form-msg
.field.row.mb-2.form-group
.col-3
= f.label :password_confirmation, class: 'form-label'
.col-9
= f.password_field :password_confirmation, autocomplete: 'new-password', class: 'form-control mb-2'
span.form-msg
.actions.row.justify-content-end
.col-9
= f.submit 'Done', class: 'btn btn-primary w-50 my-4', data: { disable_with: false }
hr hr
h3 h3
| Delete my account | Delete my account
p p
| Click the button below to delete account | Click the button below to delete account
= button_to "Delete", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete, class: "btn btn-primary w-100 my-4" = button_to 'Delete', registration_path(resource_name), data: { confirm: 'Are you sure?' }, method: :delete, class: 'btn btn-primary w-100 my-4'
= link_to "Home", :back = link_to 'Home', :back
\ No newline at end of file
javascript:
Validator({
form: '#edit_user',
errorSelector: '.form-msg',
rules: [
Validator.isRequired('#user_email'),
Validator.isEmail('#user_email'),
Validator.isRequired('#user_name')
]
})
\ No newline at end of file
- provide(:title, 'Edit profile')
.container
.row.justify-content-center
.col-8
h2.text-center.my-5
| Register
= resource_name.to_s.humanize
= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f|
= render 'users/shared/error_messages', resource: resource
.field.row.mb-2.form-group
- if devise_mapping.confirmable? && resource.pending_reconfirmation?
div
| Currently waiting confirmation for:
= resource.unconfirmed_email
.field.row.mb-2.form-group
.col-3
= f.label :name, class: 'form-label'
.col-9
= f.text_field :name, autofocus: true, autocomplete: 'name', class: 'form-control mb-2'
span.form-msg
.field.row.mb-2.form-group
.col-3
= f.label :address, class: 'form-label'
.col-9
= f.text_field :address, autofocus: true, autocomplete: 'address', class: 'form-control mb-2'
span.form-msg
.field.row.mb-2.form-group
.col-3
= f.label :phone, class: 'form-label'
.col-9
= f.text_field :phone, autofocus: true, autocomplete: 'phone', class: 'form-control mb-2'
span.form-msg
.field.row.mb-2.form-group
.col-3
= f.label :password, class: 'form-label'
.col-9
= f.password_field :password, autocomplete: 'new-password', class: 'form-control mb-2'
span.form-msg
.field.row.mb-2.form-group
.col-3
= f.label :password_confirmation, class: 'form-label'
.col-9
= f.password_field :password_confirmation, autocomplete: 'new-password', class: 'form-control mb-2'
span.form-msg
.field.row.mb-2.form-group
.col-3
= f.label :cv, class: 'form-label'
.col-9
= f.file_field :cv, accept: ApplyJob::ACCEPT_CONTENT_TYPE, class: 'form-control', direct_upload: true
.actions.row.justify-content-end
.col-9
= f.submit 'Register', class: 'btn btn-primary w-50 my-4', data: { disable_with: false }
javascript:
Validator({
form: '#new_user',
errorSelector: '.form-msg',
rules: [
Validator.isRequired('#user_name'),
Validator.isRequired('#user_password'),
Validator.isRequired('#user_password_confirmation'),
Validator.isConfirmed('#user_password_confirmation', function () {
return document.querySelector('#new_user #user_password').value;
}, 'password confirmation does not match')
]
})
\ No newline at end of file
- provide(:title, "Sign Up") - provide(:title, 'Sign Up')
.container .container
.row.justify-content-center .row.justify-content-center
...@@ -6,36 +6,36 @@ ...@@ -6,36 +6,36 @@
h2.text-center.my-5 h2.text-center.my-5
| Sign up | Sign up
= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| = form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
= render "users/shared/error_messages", resource: resource = render 'users/shared/error_messages', resource: resource
.field .field
= f.label :email, class: 'form-label' = f.label :email, class: 'form-label'
br br
= f.email_field :email, autofocus: true, autocomplete: "email", class: 'form-control mb-2' = f.email_field :email, autofocus: true, autocomplete: 'email', class: 'form-control mb-2'
.field / .field
= f.label :name, class: 'form-label' / = f.label :name, class: 'form-label'
br / br
= f.text_field :name, autofocus: true, autocomplete: "name", class: 'form-control mb-2' / = f.text_field :name, autofocus: true, autocomplete: 'name', class: 'form-control mb-2'
.field / .field
= f.label :address, class: 'form-label' / = f.label :address, class: 'form-label'
br / br
= f.text_field :address, autofocus: true, autocomplete: "address", class: 'form-control mb-2' / = f.text_field :address, autofocus: true, autocomplete: 'address', class: 'form-control mb-2'
.field / .field
= f.label :phone, class: 'form-label' / = f.label :phone, class: 'form-label'
br / br
= f.text_field :phone, autofocus: true, autocomplete: "phone", class: 'form-control mb-2' / = f.text_field :phone, autofocus: true, autocomplete: 'phone', class: 'form-control mb-2'
.field / .field
= f.label :password, class: 'form-label' / = f.label :password, class: 'form-label'
- if @minimum_password_length / - if @minimum_password_length
em / em
| ( / | (
= @minimum_password_length / = @minimum_password_length
| characters minimum) / | characters minimum)
br / br
= f.password_field :password, autocomplete: "new-password", class: 'form-control mb-2' / = f.password_field :password, autocomplete: 'new-password', class: 'form-control mb-2'
.field / .field
= f.label :password_confirmation, class: 'form-label' / = f.label :password_confirmation, class: 'form-label'
br / br
= f.password_field :password_confirmation, autocomplete: "new-password", class: 'form-control mb-2' / = f.password_field :password_confirmation, autocomplete: 'new-password', class: 'form-control mb-2'
.actions .actions
= f.submit "Sign up", class: "btn btn-primary w-100 my-5" = f.submit 'Sign up', class: 'btn btn-primary w-100 my-5'
= render "users/shared/links" = render 'users/shared/links'
\ No newline at end of file \ No newline at end of file
.container.text-center
h2.my-5
| Register
p
| Thank you for register our service, an confirmation email with registration link has been sent to your email. Please check your email within 24 hours.
p
| Please note that the registration link is only valid for 24 hours.
p
| Over that period, you will have to register your email again.
\ No newline at end of file
- provide(:title, 'Log in')
.container .container
.row.justify-content-center .row.justify-content-center
.col-6 .col-6
h2.text-center.my-5 h2.text-center.my-5
| Log in | Log in
= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| = form_for(resource, as: resource_name, url: session_path(resource_name)) do |f|
.field .field.row.form-group.mb-4
= f.label :email, class: 'form-label' .col-2
br = f.label :email, class: 'form-label'
= f.email_field :email, autofocus: true, autocomplete: "email", class: 'form-control mb-2' .col-10
.field = f.email_field :email, autofocus: true, autocomplete: 'email', class: 'form-control mb-2'
= f.label :password, class: 'form-label' span.form-msg
br .field.row.form-group.mb-4
= f.password_field :password, autocomplete: "current-password", class: 'form-control mb-2' .col-2
- if devise_mapping.rememberable? = f.label :password, class: 'form-label'
.field .col-10
= f.check_box :remember_me = f.password_field :password, autocomplete: 'current-password', class: 'form-control mb-2'
= f.label :remember_me, class: 'form-label' span.form-msg
.actions - if devise_mapping.rememberable?
= f.submit "Log in", class: "btn btn-primary w-100 my-5" .field
= render "users/shared/links" = f.check_box :remember_me
\ No newline at end of file = f.label :remember_me, class: 'form-label mx-2'
- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations'
= link_to 'Forgot password?', forgot_password_path, class: 'text-decoration-none'
.actions.row.justify-content-end
.col-10.d-flex.justify-content-around
= f.submit 'Log in', class: 'btn btn-primary w-25', data: { disable_with: false }
= link_to 'Sign up', new_registration_path(resource_name), class: 'text-decoration-none w-25 btn btn-secondary'
javascript:
Validator({
form: '#new_user',
errorSelector: '.form-msg',
rules: [
Validator.isRequired('#user_email'),
Validator.isEmail('#user_email'),
Validator.isRequired('#user_password')
]
})
- if controller_name != 'sessions' - if controller_name != 'sessions'
= link_to "Log in", new_session_path(resource_name), class: 'text-decoration-none' = link_to 'Log in', new_session_path(resource_name), class: 'text-decoration-none'
br/ br/
- if devise_mapping.registerable? && controller_name != 'registrations' - if devise_mapping.registerable? && controller_name != 'registrations'
= link_to "Sign up", new_registration_path(resource_name), class: 'text-decoration-none' = link_to 'Sign up', new_registration_path(resource_name), class: 'text-decoration-none btn btn-primary'
br/ br/
- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' - if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations'
= link_to "Forgot your password?", new_password_path(resource_name), class: 'text-decoration-none' = link_to 'Forgot your password?', new_password_path(resource_name), class: 'text-decoration-none'
br/ br/
- if devise_mapping.confirmable? && controller_name != 'confirmations' - if devise_mapping.confirmable? && controller_name != 'confirmations'
= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name), class: 'text-decoration-none' = link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name), class: 'text-decoration-none'
......
...@@ -24,7 +24,7 @@ Devise.setup do |config| ...@@ -24,7 +24,7 @@ Devise.setup do |config|
# Configure the e-mail address which will be shown in Devise::Mailer, # Configure the e-mail address which will be shown in Devise::Mailer,
# note that it will be overwritten if you use your own mailer class # note that it will be overwritten if you use your own mailer class
# with default "from" parameter. # with default "from" parameter.
config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com' config.mailer_sender = 'user@venjob.com'
# Configure the class responsible to send e-mails. # Configure the class responsible to send e-mails.
# config.mailer = 'Devise::Mailer' # config.mailer = 'Devise::Mailer'
...@@ -134,6 +134,55 @@ Devise.setup do |config| ...@@ -134,6 +134,55 @@ Devise.setup do |config|
# Send a notification email when the user's password is changed. # Send a notification email when the user's password is changed.
# config.send_password_change_notification = false # config.send_password_change_notification = false
# ==> Configuration for :invitable
# The period the generated invitation token is valid.
# After this period, the invited resource won't be able to accept the invitation.
# When invite_for is 0 (the default), the invitation won't expire.
# config.invite_for = 24.hours
# Number of invitations users can send.
# - If invitation_limit is nil, there is no limit for invitations, users can
# send unlimited invitations, invitation_limit column is not used.
# - If invitation_limit is 0, users can't send invitations by default.
# - If invitation_limit n > 0, users can send n invitations.
# You can change invitation_limit column for some users so they can send more
# or less invitations, even with global invitation_limit = 0
# Default: nil
# config.invitation_limit = 5
# The key to be used to check existing users when sending an invitation
# and the regexp used to test it when validate_on_invite is not set.
# config.invite_key = { email: /\A[^@]+@[^@]+\z/ }
# config.invite_key = { email: /\A[^@]+@[^@]+\z/, username: nil }
# Ensure that invited record is valid.
# The invitation won't be sent if this check fails.
# Default: false
# config.validate_on_invite = true
# Resend invitation if user with invited status is invited again
# Default: true
# config.resend_invitation = false
# The class name of the inviting model. If this is nil,
# the #invited_by association is declared to be polymorphic.
# Default: nil
# config.invited_by_class_name = 'User'
# The foreign key to the inviting model (if invited_by_class_name is set)
# Default: :invited_by_id
# config.invited_by_foreign_key = :invited_by_id
# The column name used for counter_cache column. If this is nil,
# the #invited_by association is declared without counter_cache.
# Default: nil
# config.invited_by_counter_cache = :invitations_count
# Auto-login after the user accepts the invite. If this is false,
# the user will need to manually log in after accepting the invite.
# Default: true
# config.allow_insecure_sign_in_after_accept = false
# ==> Configuration for :confirmable # ==> Configuration for :confirmable
# A period that the user is allowed to access the website even without # A period that the user is allowed to access the website even without
# confirming their account. For instance, if set to 2.days, the user will be # confirming their account. For instance, if set to 2.days, the user will be
...@@ -224,7 +273,7 @@ Devise.setup do |config| ...@@ -224,7 +273,7 @@ Devise.setup do |config|
# Time interval you can reset your password with a reset password key. # Time interval you can reset your password with a reset password key.
# Don't put a too small interval or your users won't have the time to # Don't put a too small interval or your users won't have the time to
# change their passwords. # change their passwords.
config.reset_password_within = 6.hours config.reset_password_within = 24.hours
# When set to false, does not sign a user in automatically after their password is # When set to false, does not sign a user in automatically after their password is
# reset. Defaults to true, so a user is signed in automatically after a reset. # reset. Defaults to true, so a user is signed in automatically after a reset.
......
...@@ -41,7 +41,8 @@ en: ...@@ -41,7 +41,8 @@ en:
signed_up: "Welcome! You have signed up successfully." signed_up: "Welcome! You have signed up successfully."
signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated." signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated."
signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked." signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked."
signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account." # signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account."
signed_up_but_unconfirmed: ""
update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirmation link to confirm your new email address." update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirmation link to confirm your new email address."
updated: "Your account has been updated successfully." updated: "Your account has been updated successfully."
updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again." updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again."
......
Rails.application.routes.draw do Rails.application.routes.draw do
devise_for :users devise_for :users, controllers: {
sessions: 'users/sessions',
confirmations: 'users/confirmations',
registrations: 'users/registrations'
}
devise_scope :user do
get '/login', to: 'devise/sessions#new', as: :login
get '/my/info', to: 'devise/registrations#edit', as: :edit_profile
get '/forgot_password', to: 'devise/passwords#new', as: :forgot_password
get '/reset_password', to: 'devise/passwords#edit', as: :reset_password
get '/register/1', to: 'devise/registrations#new', as: :signup
get '/register/2', to: 'users/registrations#send_mail', as: :send_signup_mail
get '/register/3', to: 'users/registrations#information', as: :signup_infomation
end
root 'top#index' root 'top#index'
resources :cities, only: %i[index] resources :cities, only: %i[index]
resources :industries, only: %i[index] resources :industries, only: %i[index]
get '/jobs/:model/:slug', to: 'jobs#index', as: :job_list resources :favorite_jobs, only: %i[index create destroy]
resources :jobs, only: %i[index show]
resources :jobs, only: %i[index show] get '/jobs/:model/:slug', to: 'jobs#index', as: :job_list
resources :users, only: %i[index show] get '/my', to: 'users#show', as: :user_profile
get '/my/jobs', to: 'applies#index', as: :apply_jobs
get '/apply', to: 'applies#new', as: :apply_job
get '/apply', to: 'applies#new', as: :apply_job post '/confirm', to: 'applies#confirm', as: :confirm_job
post '/confirm', to: 'applies#confirm', as: :confirm_job post '/done', to: 'applies#create', as: :done_job
post '/done', to: 'applies#create', as: :done_job get '/history', to: 'history_jobs#index', as: :history_jobs
end end
.container.text-center
h2.my-5
| Register
p
| Thank you for register our service, an confirmation email with registration link has been sent to your email. Please check your email within 24 hours.
p
| Please note that the registration link is only valid for 24 hours.
p
| Over that period, you will have to register your email again.
\ No newline at end of file
...@@ -8,6 +8,5 @@ class RemoveFieldFromUsers < ActiveRecord::Migration[6.1] ...@@ -8,6 +8,5 @@ class RemoveFieldFromUsers < ActiveRecord::Migration[6.1]
remove_column :users, :activated_at, :datetime remove_column :users, :activated_at, :datetime
remove_column :users, :password_reset_digest, :string remove_column :users, :password_reset_digest, :string
remove_column :users, :password_reset_sent_at, :datetime remove_column :users, :password_reset_sent_at, :datetime
end end
end end
...@@ -21,7 +21,7 @@ class AddDeviseToUsers < ActiveRecord::Migration[6.1] ...@@ -21,7 +21,7 @@ class AddDeviseToUsers < ActiveRecord::Migration[6.1]
# t.string :current_sign_in_ip # t.string :current_sign_in_ip
# t.string :last_sign_in_ip # t.string :last_sign_in_ip
## Confirmable # # Confirmable
# t.string :confirmation_token # t.string :confirmation_token
# t.datetime :confirmed_at # t.datetime :confirmed_at
# t.datetime :confirmation_sent_at # t.datetime :confirmation_sent_at
......
class DeviseInvitableAddToUsers < ActiveRecord::Migration[6.1]
def up
change_table :users do |t|
t.string :invitation_token
t.datetime :invitation_created_at
t.datetime :invitation_sent_at
t.datetime :invitation_accepted_at
t.integer :invitation_limit
t.references :invited_by, polymorphic: true
t.integer :invitations_count, default: 0
t.index :invitation_token, unique: true # for invitable
t.index :invited_by_id
end
end
def down
change_table :users do |t|
t.remove_references :invited_by, polymorphic: true
t.remove :invitations_count, :invitation_limit, :invitation_sent_at, :invitation_accepted_at, :invitation_token, :invitation_created_at
end
end
end
class AddConfirmableToUsers < ActiveRecord::Migration[6.1]
def change
add_column :users, :confirmation_token, :string
add_column :users, :confirmed_at, :datetime
add_column :users, :confirmation_sent_at, :datetime
add_column :users, :unconfirmed_email, :string
add_index :users, :confirmation_token, unique: true
end
end
class AddIndexToFavoriteJobs < ActiveRecord::Migration[6.1]
def change
add_index :favorite_jobs, %i[job_id job_id], unique: true
end
end
class RemoveDeviseInvitable < ActiveRecord::Migration[6.1]
def change
def change
remove_column :users, :invitation_token, :string
remove_column :users, :invitation_created_at, :datetime
remove_column :users, :invitation_sent_at, :datetime
remove_column :users, :invitation_accepted_at, :datetime
remove_column :users, :invitation_limit, :integer
remove_references :users, :invited_by, :references
remove_column :users, :invitations_count, :integer
remove_column :users, :invitation_token, :index
remove_column :users, :invited_by_id, :index
end
end
end
class RemoveIndexFormFavorite < ActiveRecord::Migration[6.1]
def change
remove_index :favorite_jobs, name: :index_favorite_jobs_on_job_id_and_job_id
end
end
class AddNewIndexToFavorite < ActiveRecord::Migration[6.1]
def change
add_index :favorite_jobs, %i[job_id user_id], unique: true
end
end
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2021_08_05_105601) do ActiveRecord::Schema.define(version: 2021_09_07_064156) do
create_table "active_storage_attachments", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| create_table "active_storage_attachments", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "name", null: false t.string "name", null: false
...@@ -80,6 +80,7 @@ ActiveRecord::Schema.define(version: 2021_08_05_105601) do ...@@ -80,6 +80,7 @@ ActiveRecord::Schema.define(version: 2021_08_05_105601) do
t.bigint "user_id", null: false t.bigint "user_id", null: false
t.datetime "created_at", precision: 6, null: false t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false
t.index ["job_id", "user_id"], name: "index_favorite_jobs_on_job_id_and_user_id", unique: true
t.index ["job_id"], name: "index_favorite_jobs_on_job_id" t.index ["job_id"], name: "index_favorite_jobs_on_job_id"
t.index ["user_id"], name: "index_favorite_jobs_on_user_id" t.index ["user_id"], name: "index_favorite_jobs_on_user_id"
end end
...@@ -138,7 +139,23 @@ ActiveRecord::Schema.define(version: 2021_08_05_105601) do ...@@ -138,7 +139,23 @@ ActiveRecord::Schema.define(version: 2021_08_05_105601) do
t.datetime "remember_created_at" t.datetime "remember_created_at"
t.string "phone" t.string "phone"
t.string "address" t.string "address"
t.string "invitation_token"
t.datetime "invitation_created_at"
t.datetime "invitation_sent_at"
t.datetime "invitation_accepted_at"
t.integer "invitation_limit"
t.string "invited_by_type"
t.bigint "invited_by_id"
t.integer "invitations_count", default: 0
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["email"], name: "index_users_on_email", unique: true t.index ["email"], name: "index_users_on_email", unique: true
t.index ["invitation_token"], name: "index_users_on_invitation_token", unique: true
t.index ["invited_by_id"], name: "index_users_on_invited_by_id"
t.index ["invited_by_type", "invited_by_id"], name: "index_users_on_invited_by"
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment