Commit 8e8ffb2c by Thanh Hung Pham

Merge branch 'page-job-list' into 'master'

page ID4

See merge request !5
parents 5aa84058 feb815a2
Pipeline #1381 failed with stages
in 0 seconds
......@@ -8,6 +8,9 @@ gem 'rails', '~> 6.1.3', '>= 6.1.3.2'
gem 'bootstrap', '~> 5.0.1'
gem 'nokogiri', '~> 1.11', '>= 1.11.7'
gem 'slim-rails'
gem 'kaminari', '~> 1.2', '>= 1.2.1'
gem 'friendly_id', '~> 5.4', '>= 5.4.2'
gem 'babosa'
# Use sqlite3 as the database for Active Record
gem 'mysql2', '~> 0.5.3'
# Use Puma as the app server
......
......@@ -64,6 +64,7 @@ GEM
public_suffix (>= 2.0.2, < 5.0)
autoprefixer-rails (10.2.5.1)
execjs (> 0)
babosa (1.0.4)
bindex (0.8.1)
bootsnap (1.7.5)
msgpack (~> 1.0)
......@@ -88,12 +89,26 @@ GEM
erubi (1.10.0)
execjs (2.8.1)
ffi (1.15.3)
friendly_id (5.4.2)
activerecord (>= 4.0.0)
globalid (0.4.2)
activesupport (>= 4.2.0)
i18n (1.8.10)
concurrent-ruby (~> 1.0)
jbuilder (2.11.2)
activesupport (>= 5.0.0)
kaminari (1.2.1)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.2.1)
kaminari-activerecord (= 1.2.1)
kaminari-core (= 1.2.1)
kaminari-actionview (1.2.1)
actionview
kaminari-core (= 1.2.1)
kaminari-activerecord (1.2.1)
activerecord
kaminari-core (= 1.2.1)
kaminari-core (1.2.1)
listen (3.5.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
......@@ -219,11 +234,14 @@ PLATFORMS
x86_64-linux
DEPENDENCIES
babosa
bootsnap (>= 1.4.4)
bootstrap (~> 5.0.1)
byebug
capybara (>= 3.26)
friendly_id (~> 5.4, >= 5.4.2)
jbuilder (~> 2.7)
kaminari (~> 1.2, >= 1.2.1)
listen (~> 3.3)
mysql2 (~> 0.5.3)
nokogiri (~> 1.11, >= 1.11.7)
......
......@@ -38,4 +38,23 @@
text-align: right;
font-weight: 500;
font-size: 20px;
}
\ No newline at end of file
}
.form {
width: 700px
}
.card-body {
float: left;
}
.favourite {
float: right;
.btn {
margin-top: 50%;
margin-bottom: 50%;
display: flex;
align-items: center;
justify-content: center;
}
}
class CityController < ApplicationController
def list_city
class CitiesController < ApplicationController
def show
@cities_vietnam = City.cities_by_region(City::REGION_VN_ID)
@cities_international = City.cities_by_region(City::REGION_INTERNATIONAL_ID)
end
......
class IndustryController < ApplicationController
def list_industry
class IndustriesController < ApplicationController
def show
@industry_list = Industry.industry_list
end
end
\ No newline at end of file
class JobsController < ApplicationController
def show
if params[:city_slug].present?
city = City.find_by(slug: params[:city_slug])
jobs = city.jobs
@result = city.name
else
industry = Industry.find_by(slug: params[:industry_slug])
jobs = industry.jobs
@result = industry.name
end
@total = jobs.count
@jobs = jobs.latest_jobs.page(params[:page])
end
end
\ No newline at end of file
class TopController < ApplicationController
def home
@jobs = Job.latest_jobs
@jobs = Job.latest_jobs.limit(Job::LATEST_JOB_NUMBER)
@cities = City.top_cities
@industries = Industry.top_industries
@total_job = Job.all.count
@total_job = Job.count
end
end
end
\ No newline at end of file
class City < ApplicationRecord
extend FriendlyId
friendly_id :name, use: %i[slugged finders]
belongs_to :region
has_and_belongs_to_many :jobs
has_and_belongs_to_many :companies
LATEST_CITY_NUMBER = 9
REGION_VN_ID = 1
REGION_INTERNATIONAL_ID = 2
scope :top_cities, -> { joins(:jobs).group(:name).order('count_all DESC').count.take(LATEST_CITY_NUMBER) }
scope :cities_by_region, ->(value) { joins(:jobs).group(:name).having('count_all >= ?', 1).where('region_id = ?', value).order('count_all DESC').count }
scope :top_cities, -> { joins(:jobs).group(:name, :slug).order('count_all DESC').count.take(LATEST_CITY_NUMBER) }
scope :cities_by_region, ->(value) { joins(:jobs).group(:name, :slug).having('count_all >= ?', 1).where('region_id = ?', value).order('count_all DESC').count }
def normalize_friendly_id(string)
string.to_s.to_slug.normalize(transliterations: :vietnamese).to_s
end
end
\ No newline at end of file
class Company < ApplicationRecord
has_many :jobs
has_many :jobs, dependent: :destroy
has_and_belongs_to_many :cities
end
end
\ No newline at end of file
class Industry < ApplicationRecord
extend FriendlyId
friendly_id :name, use: %i[slugged finders]
has_and_belongs_to_many :jobs
LATEST_INDUSTRY_NUMBER = 9
scope :top_industries, -> { joins(:jobs).group(:name).order('count_all DESC').count.take(LATEST_INDUSTRY_NUMBER) }
scope :industry_list, -> { joins(:jobs).group(:name).having('count_all >= ?', 1).order('count_all DESC').count }
scope :top_industries, -> { joins(:jobs).group(:name, :slug).order('count_all DESC').count.take(LATEST_INDUSTRY_NUMBER) }
scope :industry_list, -> { joins(:jobs).group(:name, :slug).having('count_all >= ?', 1).order('count_all DESC').count }
def normalize_friendly_id(string)
string.to_s.to_slug.normalize(transliterations: :vietnamese).to_s
end
end
\ No newline at end of file
class Job < ApplicationRecord
belongs_to :company
has_many :apply_jobs
has_many :favorite_jobs
has_many :history_jobs
has_many :apply_jobs, dependent: :destroy
has_many :favorite_jobs, dependent: :destroy
has_many :history_jobs, dependent: :destroy
has_and_belongs_to_many :industries
has_and_belongs_to_many :cities
LATEST_JOB_NUMBER = 5
scope :latest_jobs, -> { includes(:cities, :company).order('created_at DESC').limit(LATEST_JOB_NUMBER) }
scope :latest_jobs, -> { includes(:cities, :industries, :company).order('created_at DESC') }
end
\ No newline at end of file
class User < ApplicationRecord
has_many :apply_jobs
has_many :favorite_jobs
has_many :history_jobs
has_many :apply_jobs, dependent: :destroy
has_many :favorite_jobs, dependent: :destroy
has_many :history_jobs, dependent: :destroy
end
......@@ -14,7 +14,7 @@
.row.my-3.text-center.fs-5
- @cities_vietnam.each do |name, amount|
.col-3.p-2.border.mb-1.fw-normal.bg-white
= link_to name, "#"
= link_to name[0], city_slug_path(name[1])
p.mb-1
= amount
#international
......@@ -23,6 +23,6 @@
.row.my-3.text-center.fs-5
- @cities_international.each do |name, amount|
.col-3.p-2.border.mb-1.fw-normal.bg-white
= link_to name, "#"
= link_to name[0], city_slug_path(name[1])
p.mb-1
= amount
\ No newline at end of file
......@@ -6,6 +6,6 @@
.row.my-3.text-center.fs-5
- @industry_list.each do |name, amount|
.col-3.p-2.border.mb-1.fw-normal.bg-white
= link_to name, "#"
= link_to name[0], industry_slug_path(name[1])
p.mb-1
= amount
\ No newline at end of file
.search.p-3.offset-md-2
= form_with(url: '/jobs', method: 'get', local: true) do
= text_field_tag :search, params[:search], placeholder: "Search", class: "form"
= submit_tag "Search", name: nil, class: 'btn-primary'
\ No newline at end of file
- provide :title, 'Job List'
= render 'search'
.container
h5.fw-normal
| Total:
= pluralize(@total, 'job')
h5.fw-normal
| Result for:
= @result
h6.offset-md-4
= paginate @jobs, window: 1
.job-list
- @jobs.each do |job|
.row.bg-white
.col-10.p-3.border.card-body.text-dark
h5.mb-1
= link_to job.title, "#"
p.mb-1
= link_to job.company.name, "#"
p.mb-1
i.fas.fa-dollar-sign.m-1
| Lương:
= job.salary
p.mb-1
i.fas.fa-map-marker-alt.m-1
= link_to job.cities.map(&:name).uniq.join(' | '), "#"
p.mb-1
= truncate(job.overview, length: 250)
.col-sm-2.p-3.border.favourite
= link_to "Farourite", "#", class: "btn btn-outline-primary"
h6.offset-md-4.px-5
= page_entries_info @jobs
h6.offset-md-4
= paginate @jobs, window: 1
\ No newline at end of file
li.page-item
= link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, remote: remote, class: 'page-link'
li.page-item.disabled
= link_to raw(t 'views.pagination.truncate'), '#', class: 'page-link'
li.page-item
= link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, remote: remote, class: 'page-link'
li.page-item
= link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, rel: 'next', remote: remote, class: 'page-link'
- if page.current?
li.page-item.active
= content_tag :a, page, data: { remote: remote }, rel: page.rel, class: 'page-link'
- else
li.page-item
= link_to page, url, remote: remote, rel: page.rel, class: 'page-link'
= paginator.render do
nav
ul.pagination
== first_page_tag unless current_page.first?
== prev_page_tag unless current_page.first?
- each_page do |page|
- if page.left_outer? || page.right_outer? || page.inside_window?
== page_tag page
- elsif !page.was_truncated?
== gap_tag
== next_page_tag unless current_page.last?
== last_page_tag unless current_page.last?
li.page-item
= link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, rel: 'prev', remote: remote, class: 'page-link'
......@@ -3,11 +3,8 @@
h3.p-2
| Total:
= pluralize(@total_job, 'job')
= render 'jobs/search'
.container
.input-group.py-3
input.form-control.rounded[type="search" placeholder="Search" aria-label="Search" aria-describedby="search-addon"]
button.btn.btn-outline-primary[type="button"]
| Search
h4.py-4
| Latest Jobs
- @jobs.each do |job|
......@@ -23,13 +20,13 @@ h3.p-2
= job.salary
p.mb-1
i.fas.fa-map-marker-alt.m-1
= link_to job.cities.map(&:name).join(', '), "#"
= link_to job.cities.map(&:name).uniq.join(' | '), "#"
h4
| Top Cities
.row.my-3.text-center.fs-5
- @cities.each do |name, amount|
.col-4.p-2.border.mb-1.fw-normal.bg-white
= link_to name, "#"
= link_to name[0], city_slug_path(name[1])
p.mb-1
= amount
.d-flex.flex-row-reverse.
......@@ -39,7 +36,7 @@ h3.p-2
.row.my-3.text-center.fs-5
- @industries.each do |name, amount|
.col-4.p-2.border.mb-1.fw-normal.bg-white
= link_to name, "#"
= link_to name[0], industry_slug_path(name[1])
p.mb-1
= amount
.d-flex.flex-row-reverse
......
# frozen_string_literal: true
Kaminari.configure do |config|
config.default_per_page = 20
# config.max_per_page = nil
# config.window = 4
# config.outer_window = 0
# config.left = 0
# config.right = 0
# config.page_method_name = :page
# config.param_name = :page
# config.max_pages = nil
# config.params_on_first_page = false
end
......@@ -30,4 +30,19 @@
# available at https://guides.rubyonrails.org/i18n.html.
en:
hello: "Hello world"
views:
pagination:
first: "&laquo; First"
last: "Last &raquo;"
previous: "&lsaquo; Prev"
next: "Next &rsaquo;"
truncate: "&hellip;"
helpers:
page_entries_info:
one_page:
display_entries:
zero: "No %{entry_name} found"
one: "Displaying <b>1</b> %{entry_name}"
other: "Displaying <b>all %{count}</b> %{entry_name}"
more_pages:
display_entries: "Displaying %{entry_name} <b>%{first}&nbsp;-&nbsp;%{last}</b> of <b>%{total}</b> in total"
Rails.application.routes.draw do
root 'top#home'
get 'cities', to: 'city#list_city'
get 'industries', to: 'industry#list_industry'
get 'cities', to: 'cities#show'
get 'industries', to: 'industries#show'
get 'jobs/city/:city_slug', to: 'jobs#show', as: 'city_slug'
get 'jobs/industry/:industry_slug', to: 'jobs#show', as: 'industry_slug'
end
\ No newline at end of file
class AddSlugToCities < ActiveRecord::Migration[6.1]
def change
add_column :cities, :slug, :string
add_index :cities, :slug, unique: true
end
end
class AddSlugIndustries < ActiveRecord::Migration[6.1]
def change
add_column :industries, :slug, :string
add_index :industries, :slug, unique: true
end
end
......@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2021_07_23_035105) do
ActiveRecord::Schema.define(version: 2021_07_31_111344) do
create_table "apply_jobs", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.bigint "user_id", null: false
......@@ -27,7 +27,9 @@ ActiveRecord::Schema.define(version: 2021_07_23_035105) do
t.string "name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "slug"
t.index ["region_id"], name: "index_cities_on_region_id"
t.index ["slug"], name: "index_cities_on_slug", unique: true
end
create_table "cities_jobs", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
......@@ -66,6 +68,17 @@ ActiveRecord::Schema.define(version: 2021_07_23_035105) do
t.index ["user_id"], name: "index_favorite_jobs_on_user_id"
end
create_table "friendly_id_slugs", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "slug", null: false
t.integer "sluggable_id", null: false
t.string "sluggable_type", limit: 50
t.string "scope"
t.datetime "created_at"
t.index ["slug", "sluggable_type", "scope"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type_and_scope", unique: true, length: { slug: 70, scope: 70 }
t.index ["slug", "sluggable_type"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type", length: { slug: 140 }
t.index ["sluggable_type", "sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_type_and_sluggable_id"
end
create_table "history_jobs", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.bigint "user_id", null: false
t.bigint "job_id", null: false
......@@ -79,6 +92,8 @@ ActiveRecord::Schema.define(version: 2021_07_23_035105) do
t.string "name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "slug"
t.index ["slug"], name: "index_industries_on_slug", unique: true
end
create_table "industries_jobs", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
......
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