Commit 6c47054b by Hoang Phuc Do

Merge branch 'joblist' into 'master'

create job list

See merge request !6
parents 21964a4a 14033567
Pipeline #830 canceled with stages
in 0 seconds
......@@ -28,6 +28,7 @@ gem 'jbuilder', '~> 2.5'
# gem 'bcrypt', '~> 3.1.7'
gem 'nokogiri'
gem 'whenever'
gem 'kaminari'
# Use ActiveStorage variant
# gem 'mini_magick', '~> 4.8'
......
......@@ -84,6 +84,18 @@ GEM
io-like (0.3.1)
jbuilder (2.10.0)
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.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
......@@ -199,6 +211,7 @@ DEPENDENCIES
chromedriver-helper
coffee-rails (~> 4.2)
jbuilder (~> 2.5)
kaminari
listen (>= 3.0.5, < 3.2)
mysql2 (>= 0.4.4, < 0.6.0)
nokogiri
......
......@@ -13,4 +13,5 @@
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require jquery.min
//= require_tree .
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
// Place all the styles related to the error controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
.box_content_404 {
width: 100vw;
height: 100vh;
z-index: 2000;
// height: 900px;
position: fixed;
top: 60px;
left: 0;
right: 0;
bottom: 0;
background-color: #fff;
}
.box_content_404_img {
margin: auto;
width: 700px
}
.img_404 {
width: 100%;
}
.box_content_404_text {
text-align: center;
span {
font-size: 30px;
font-weight: 800;
color: #99a6d5;
}
}
.box_content_404_back_to_home {
text-align: center;
a {
font-size: 22px;
color: #1a2c55;
&:hover {
text-decoration: none;
color: red;
}
}
}
# frozen_string_literal: true
# /home/hungnt/project/venjob/app/common/slug.rb
module Slug
def self.to_slug(str)
str = str.to_s.strip.downcase
accents = {
%w[à á ạ ả ã â ầ ấ ậ ẩ ẫ ă ằ ắ ặ ẳ ẵ] => 'a',
%w[è é ẹ ẻ ẽ ê ề ế ệ ể ễ] => 'e',
%w[ì í ị ỉ ĩ] => 'i',
%w[ò ó ọ ỏ õ ô ồ ố ộ ổ ỗ ơ ờ ớ ợ ở ỡ] => 'o',
%w[ù ú ụ ủ ũ ư ừ ứ ự ử ữ] => 'u',
%w[ỳ ý ỵ ỷ ỹ] => 'y',
%w[đ] => 'd'
}
accents.each do |ac, rep|
ac.each do |s|
str = str.tr(s, rep)
end
end
str = str.gsub(/[^a-zA-Z0-9 ]/, '')
str = str.gsub(/[ ]+/, ' ')
str.tr(' ', '-')
end
end
# frozen_string_literal: true
# Controller error
class ErrorController < ApplicationController
def page_not_found; end
def internal_server_error; end
end
......@@ -2,4 +2,24 @@
# Job controller
class JobController < ApplicationController
before_action :load_data_dropdown, only: :index
def index
model = params[:model].classify.constantize
obj = model.find_by(slug: params[:slug])
render_result(obj)
end
private
def load_data_dropdown
@industries = Industry.order(name: :asc).all
@cities = City.select(:id, :name)
end
def render_result(obj)
@keyword = obj.name
@data = obj.jobs.page(params[:page])
render 'result_data'
end
end
module ErrorHelper
end
......@@ -2,11 +2,13 @@
# Description/Explanation of Person class
class City < ApplicationRecord
before_save :convert_to_slug
RANGE = 69
has_many :city_jobs
has_many :jobs, through: :city_jobs
enum area: { international: 0, domestic:1}
has_many :jobs, through: :city_jobs
enum area: { international: 0, domestic: 1 }
scope :domestic, -> { where(area: 1) }
scope :international, -> { where(area: 0) }
scope :all_cities, -> { select :id, :name }
......@@ -15,4 +17,8 @@ class City < ApplicationRecord
.order(Arel.sql('count(jobs.id) DESC'))
.take(number)
end
def convert_to_slug
self.slug = Slug.to_slug("#{name} #{rand(10000)}")
end
end
......@@ -3,5 +3,10 @@
# Description/Explanation of Person class
class Company < ApplicationRecord
COMPANY_SECURITY = 1
before_save :convert_to_slug
has_many :jobs
def convert_to_slug
self.slug = Slug.to_slug("#{name} #{rand(10000)}")
end
end
......@@ -2,6 +2,7 @@
# Description/Explanation of Person class
class Industry < ApplicationRecord
before_save :convert_to_slug
has_many :industry_jobs
has_many :jobs, through: :industry_jobs
scope :top_industries, ->(number) do joins(:jobs)
......@@ -9,4 +10,8 @@ class Industry < ApplicationRecord
.order(Arel.sql('count(jobs.id) DESC'))
.take(number)
end
def convert_to_slug
self.slug = Slug.to_slug("#{name} #{rand(10000)}")
end
end
......@@ -2,7 +2,7 @@
<div class="col-lg-3 col-md-4">
<div class="box_cityjobs">
<div class="box_cityjobs_name">
<%= link_to city.name, '#', class: 'cityjobs_link' %>
<%= link_to city.name, jobs_path(model: 'city', slug: city.slug), class: 'cityjobs_link' %>
</div>
<div class="box_cityjobs_count">
<span><%= city.jobs.count %> Công việc</span>
......
<% provide(:title, 'Internal Server Error') %>
<div class="box_content_404">
<div class="container">
<div class="col-lg-12">
<div class="box_content_404_img">
<%= image_tag '500.png', class: 'img_404'%>
</div>
</div><br>
<div class="col-lg-12">
<div class="box_content_404_text">
<span>Có vài lỗi trong đường dẫn này<br>
Đừng lo lắng! Xin lỗi bạn vì sự bất tiện trên
</span>
</div>
</div>
<div class="col-lg-12">
<div class="box_content_404_back_to_home">
<%= link_to 'Cùng mình quay lại trang chủ nhé', root_path %>
</div>
</div>
</div>
</div>
<% provide(:title, 'Page Not Found') %>
<div class="box_content_404">
<div class="container">
<div class="col-lg-12">
<div class="box_content_404_img">
<%= image_tag '404.svg', class: 'img_404' %>
</div>
</div><br>
<div class="col-lg-12">
<div class="box_content_404_text">
<span>Chúng tôi không tìm thấy trang bạn bạn yêu cầu!</span>
</div>
</div>
<div class="col-lg-12">
<div class="box_content_404_back_to_home">
<%= link_to 'Cùng mình quay lại trang chủ nhé', root_path %>
</div>
</div>
</div>
</div>
......@@ -31,23 +31,13 @@
<div class="icon_list">
<i class="fa fa-list-ul" aria-hidden="true"></i>
</div>
<select class="show_list_industries">
<option value="*" selected disabled hidden class="select_first">Tất cả ngành nghề</option>
<% @industries.each do |val| %>
<option value="<%= val.id %>"><%= val.name %></option>
<% end %>
</select>
<%= select_tag 'industry', options_from_collection_for_select(@industries, 'id', 'name'), class: 'show_list_industries' %>
</div>
<div class="search_location">
<div class="icon_list">
<i class="fas fa-map-marker-alt"></i>
</div>
<select class="show_list_cities">
<option value="*" selected disabled hidden class="select_first">Tất cả Tỉnh thành</option>
<% @cities.each do |val| %>
<option value="<%= val.id %>"><%= val.name %></option>
<% end %>
</select>
<%= select_tag 'city', options_from_collection_for_select(@cities, 'id', 'name', '1'), class: 'show_list_cities' %>
</div>
<div class="search_submit">
<button type="submit" class="btn_search_submit">
......@@ -72,23 +62,13 @@
<div class="icon_list">
<i class="fa fa-list-ul" aria-hidden="true"></i>
</div>
<select class="show_list_industries">
<option value="*" selected disabled hidden class="select_first">Tất cả ngành nghề</option>
<% @industries.each do |val| %>
<option value="<%= val.id %>"><%= val.name %></option>
<% end %>
</select>
<%= select_tag 'industry', options_from_collection_for_select(@industries, 'id', 'name'), class: 'show_list_industries' %>
</div>
<div class="search_location">
<div class="icon_list">
<i class="fas fa-map-marker-alt"></i>
</div>
<select class="show_list_cities">
<option value="*" selected disabled hidden class="select_first">Tất cả Tỉnh thành</option>
<% @cities.each do |val| %>
<option value="<%= val.id %>"><%= val.name %></option>
<% end %>
</select>
<%= select_tag 'city', options_from_collection_for_select(@cities, 'id', 'name', '1'), class: 'show_list_cities' %>
</div>
<div class="search_submit">
<button type="submit" class="btn_search_submit">
......@@ -112,22 +92,12 @@
</div>
<div class="col-sm-6 col-xs-12">
<div class="search_industries_mobile">
<select class="show_list_industries_mobile">
<option value="*" selected disabled hidden class="select_first">Tất cả ngành nghề</option>
<% @industries.each do |val| %>
<option value="<%= val.id %>"><%= val.name %></option>
<% end %>
</select>
<%= select_tag 'industry', options_from_collection_for_select(@industries, 'id', 'name'), class: 'show_list_industries_mobile' %>
</div>
</div>
<div class="col-sm-6 col-xs-12">
<div class="search_location_mobile">
<select class="show_list_cities_mobile">
<option value="*" selected disabled hidden class="select_first">Tất cả Tỉnh thành</option>
<% @cities.each do |val| %>
<option value="<%= val.id %>"><%= val.name %></option>
<% end %>
</select>
<%= select_tag 'city', options_from_collection_for_select(@cities, 'id', 'name', '1'), class: 'show_list_cities_mobile' %>
</div>
</div>
</div>
......
......@@ -8,10 +8,11 @@
<div class="col-lg-4 col-md-4 col-sm-6 col-xs-12">
<div class="box_info_city">
<div class="ct_name">
<%= link_to city.name, '#' ,class: 'link_ct' %>
<!-- <%= link_to city.name, "/jobs/city/#{city.id}" ,class: 'link_ct' %> -->
<%= link_to city.name, jobs_path(model: 'city', slug: city.slug),class: 'link_ct' %>
</div>
<div class="ct_jobs_count">
<%= link_to "#{city.jobs.count} công việc", '#' ,class: 'link_ct' %>
<%= link_to "#{city.jobs.count} công việc", jobs_path(model: 'city', slug: city.slug),class: 'link_ct' %>
</div>
</div>
</div>
......
......@@ -8,10 +8,10 @@
<div class="col-lg-4 col-md-4 col-sm-6 col-xs-12">
<div class="box_info_city">
<div class="ct_name">
<%= link_to industry.name, '#', class: 'link_ct' %>
<%= link_to industry.name, jobs_path(model: 'industry', slug: industry.slug), class: 'link_ct' %>
</div>
<div class="ct_jobs_count">
<%= link_to "#{industry.jobs.count} công việc", '#', class: 'link_ct' %>
<%= link_to "#{industry.jobs.count} công việc", jobs_path(model: 'industry', slug: industry.slug), class: 'link_ct' %>
</div>
</div>
</div>
......
<div class="col-lg-3 col-md-4">
<div class="box_cityjobs">
<div class="box_cityjobs_name">
<%= link_to industry.name, '#', class: 'cityjobs_link' %>
<%= link_to industry.name, jobs_path(model: 'industry', slug: industry.slug), class: 'cityjobs_link' %>
</div>
<div class="box_cityjobs_count">
<span><%= industry.jobs.count %> Công việc</span>
......
<div class="container">
<div class="row">
<div class="col-sm-12">
<div class="box_jobs">
<div class="col-sm-12 d-block d-sm-none">
<div class="link_favorite_top block_link_favorite md">
<span><%= link_to '<i class="far fa-heart"></i>'.html_safe, '#', class: 'link_favorite' %><span>
</div>
</div>
<div class="row">
<div class="col-sm-10 col-md-9 col-lg-10">
<div class="box_info">
<div class="lol">
<%= link_to data.name, '#', class: 'job_name' %>
</div>
<div class="cop">
<h5 class="box_info_copany_name"><i class="far fa-building"></i> <%= data.company.name %></h5>
</div>
<div class="loc">
<h5 class="box_info_location"><i class="fas fa-map-marker-alt"></i>
<%= data.cities.map(&:name).join(' | ') %>
</h5>
</div>
<h5 class="box_info_salary"><i class="fas fa-dollar-sign"></i>&nbsp; Lương: <%= data.salary %></h5>
<div class="coc">
<h5 class="box_info_des"><%= strip_tags(data.description) %></h5>
</div>
</div>
</div>
<div class="col-sm-2 col-md-3 d-none d-sm-block col-lg-2">
<div class="box_link_favotite">
<div class="block_link_favorite lg">
<span><i class="far fa-heart"></i> <%= link_to 'Yêu thích', '#', class: 'link_favorite' %><span>
</div>
<div class="block_link_favorite md">
<span><%= link_to '<i class="far fa-heart"></i>'.html_safe, '#', class: 'link_favorite' %><span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<% provide(:title ,'Kết quả tìm kiếm') %>
<%= render 'home/banner_and_search' %>
<div class="padding_index"></div>
<div class="container">
<div class="row">
<div class="col-lg-12">
<div class="breadcrumb_total_search">
<span class="breadcrumb-item active">
<% if @data.total_count > 0 %>
&nbsp;<b><%= @data.total_count %></b>&nbsp;kết quả phù hợp với từ khóa&nbsp;<b><%= @keyword %></b>&nbsp;
<% else %>
Không có kết quả phù hợp với từ khóa&nbsp;<b><%= @keyword %></b>
<% end %>
</span>
</div>
</div>
<div class="col-lg-12">
<div class="breadcrumb_total_search_pagination_jobs">
<div class="pagination_jobs">
<div class="paginator">
<%= paginate @data %>
</div>
</div>
</div>
</div>
</div>
</div>
<%= render 'job/modal_login'%>
<%= render partial: 'block_info_job', collection: @data, as: :data %>
<div class="container">
<div class="row">
<div class="col-lg-12">
<div class="breadcrumb_total_search_pagination_jobs">
<div class="pagination_jobs">
<div class="paginator">
<%= paginate @data %>
</div>
</div>
</div>
</div>
</div>
</div>
<%= render 'shared/scroll_top' %>
<li class="page-item">
<%= link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, remote: remote, class: 'page-link' %>
</li>
<li class='page-item disabled'>
<%= link_to raw(t 'views.pagination.truncate'), '#', class: 'page-link' %>
</li>
<li class="page-item">
<%= link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, remote: remote, class: 'page-link' %>
</li>
<li class="page-item">
<%= link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, rel: 'next', remote: remote, class: 'page-link' %>
</li>
<% if page.current? %>
<li class="page-item active">
<%= content_tag :a, page, data: { remote: remote }, rel: page.rel, class: 'page-link' %>
</li>
<% else %>
<li class="page-item">
<%= link_to page, url, remote: remote, rel: page.rel, class: 'page-link' %>
</li>
<% end %>
<%= paginator.render do %>
<nav>
<ul class="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 %>
<% end %>
<% end %>
<%= next_page_tag unless current_page.last? %>
<%= last_page_tag unless current_page.last? %>
</ul>
</nav>
<% end %>
<li class="page-item">
<%= link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, rel: 'prev', remote: remote, class: 'page-link' %>
</li>
......@@ -10,6 +10,7 @@ module Venjob
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 5.2
config.exceptions_app = self.routes
config.autoload_paths << Rails.root.join('lib/service')
config.autoload_paths << Rails.root.join('lib/src')
# Settings in config/environments/* take precedence over those specified here.
......
......@@ -10,7 +10,7 @@ Rails.application.configure do
config.eager_load = false
# Show full error reports.
config.consider_all_requests_local = true
config.consider_all_requests_local = false
# Enable/disable caching. By default caching is disabled.
# Run rails dev:cache to toggle caching.
......
# frozen_string_literal: true
Kaminari.configure do |config|
config.default_per_page = 20
# config.max_per_page = nil
config.window = 3
# 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
Rails.application.routes.draw do
# frozen_string_literal: true
Rails.application.routes.draw do
root 'home#index'
get 'industry/index'
get 'city/index'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
get 'industries', to: 'industry#index', as: :industry_index
get 'cities', to: 'city#index', as: :city_index
# Search
get 'jobs/:model/:slug', to: 'job#index', as: :jobs
# Rails error
match '/404', to: 'error#page_not_found', via: :all
match '/500', to: 'error#internal_server_error', via: :all
end
# frozen_string_literal: true
class AddColumnSlugToTableCities < ActiveRecord::Migration[5.2]
def change
add_column :cities, :slug, :string
end
end
class AddColumnSlugToTableIndustries < ActiveRecord::Migration[5.2]
def change
add_column :industries, :slug, :string
end
end
class AddColumnSlugToTableCompanies < ActiveRecord::Migration[5.2]
def change
add_column :companies, :slug, :string
end
end
......@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_07_29_064551) do
ActiveRecord::Schema.define(version: 2020_08_05_075807) do
create_table "applied_jobs", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t|
t.bigint "user_id"
......@@ -29,6 +29,7 @@ ActiveRecord::Schema.define(version: 2020_07_29_064551) do
t.integer "area"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
end
create_table "city_jobs", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t|
......@@ -46,6 +47,7 @@ ActiveRecord::Schema.define(version: 2020_07_29_064551) do
t.text "short_description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
end
create_table "favorites", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t|
......@@ -66,6 +68,7 @@ ActiveRecord::Schema.define(version: 2020_07_29_064551) do
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
end
create_table "industry_jobs", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t|
......
......@@ -5,7 +5,7 @@ require 'open-uri'
# rake task
namespace :crawler do
task populate: :environment do
NUMBER_LINK_WILL_BE_CRAWLER = 5
NUMBER_LINK_WILL_BE_CRAWLER = 8
Company.find_or_create_by(name: 'Bảo mật') do |company|
company.address = 'Vui lòng xem trong mô tả công việc'
company.short_description = 'Vui lòng xem trong mô tả công việc'
......
require 'test_helper'
class ErrorControllerTest < ActionDispatch::IntegrationTest
# test "the truth" do
# assert 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