Commit d570f109 by Tô Ngọc Ánh

resolve conflict

parents d17806cb 9e711633
...@@ -67,4 +67,5 @@ gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] ...@@ -67,4 +67,5 @@ gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
## ##
gem 'nokogiri' gem 'nokogiri'
gem 'whenever', require: false gem 'whenever', require: false
gem 'kaminari'
## ##
...@@ -88,6 +88,18 @@ GEM ...@@ -88,6 +88,18 @@ GEM
io-like (0.3.1) io-like (0.3.1)
jbuilder (2.10.0) jbuilder (2.10.0)
activesupport (>= 5.0.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) listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4) rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7) rb-inotify (~> 0.9, >= 0.9.7)
...@@ -204,6 +216,7 @@ DEPENDENCIES ...@@ -204,6 +216,7 @@ DEPENDENCIES
coffee-rails (~> 4.2) coffee-rails (~> 4.2)
dotenv-rails dotenv-rails
jbuilder (~> 2.5) jbuilder (~> 2.5)
kaminari
listen (>= 3.0.5, < 3.2) listen (>= 3.0.5, < 3.2)
mysql2 (>= 0.4.4, < 0.6.0) mysql2 (>= 0.4.4, < 0.6.0)
nokogiri nokogiri
......
class JobsController < ApplicationController class JobsController < ApplicationController
def index
@locations = Location.select(:id, :city)
@industries = Industry.select(:id, :name)
object = params[:model].classify.constantize.find_by_slug(params[:slug])
@keyword = object.try(:name) || object.try(:city)
@jobs = object.jobs.all.includes(:company, :locations, :industries).page(params[:page])
end
def show def show
@job = Job.find_by(id: params[:id]) @job = Job.find_by(id: params[:id])
end end
......
require './lib/common/convert_slug'
class Industry < ApplicationRecord class Industry < ApplicationRecord
include ConvertSlug
scope :with_count_job, -> { joins(:jobs).group(:industry_id).select('industries.*, count(jobs.id) as job_count') } scope :with_count_job, -> { joins(:jobs).group(:industry_id).select('industries.*, count(jobs.id) as job_count') }
scope :top_industries, ->(number) { with_count_job.order(Arel.sql('job_count DESC')).limit(number) } scope :top_industries, ->(number) { with_count_job.order(Arel.sql('job_count DESC')).limit(number) }
has_and_belongs_to_many :jobs has_and_belongs_to_many :jobs
before_save :add_slug, unless: :slug
private
def add_slug
self.slug = "#{self.to_slug(self.name)}-#{Time.now.to_i}#{rand(10000)}"
end
end end
class Job < ApplicationRecord class Job < ApplicationRecord
NUMBER_LATEST_JOB = 6 NUMBER_LATEST_JOB = 6
WORDS_SHORT_DESCRIPTION = 250
belongs_to :company belongs_to :company
has_many :applied_jobs has_many :applied_jobs
......
require './lib/common/convert_slug.rb'
class Location < ApplicationRecord class Location < ApplicationRecord
include ConvertSlug
scope :with_count_job, -> { joins(:jobs).group(:location_id).select('locations.*, count(jobs.id) as job_count') } scope :with_count_job, -> { joins(:jobs).group(:location_id).select('locations.*, count(jobs.id) as job_count') }
scope :top_locations, ->(number) { with_count_job.order(Arel.sql('job_count DESC')).limit(number) } scope :top_locations, ->(number) { with_count_job.order(Arel.sql('job_count DESC')).limit(number) }
scope :international, -> { where(oversea: true) } scope :international, -> { where(oversea: true) }
...@@ -8,4 +12,12 @@ class Location < ApplicationRecord ...@@ -8,4 +12,12 @@ class Location < ApplicationRecord
has_many :locations_jobs has_many :locations_jobs
has_many :jobs, through: :locations_jobs has_many :jobs, through: :locations_jobs
before_save :add_slug, unless: :slug
private
def add_slug
self.slug = "#{self.to_slug(self.city)}-#{Time.now.to_i}#{rand(10000)}"
end
end end
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
<% job.locations.each do |location| %> <% job.locations.each do |location| %>
<%= location.city %> <%= location.city %>
<% end %> <% end %>
<strong>Salary: </strong><%= job.salary %>
</p> </p>
<p><strong>Salary: </strong><%= job.salary %></p>
</div> </div>
</div> </div>
</div> </div>
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<div class='overlay'></div> <div class='overlay'></div>
<div class='box_seach text-center'> <div class='box_seach text-center'>
<h3>We have <%= @total_jobs %> jobs for you</h3> <h3>We have <%= @total_jobs %> jobs for you</h3>
<%= render 'shared/searchbar' %> <%= render 'shared/searchbar', my_class: nil %>
</div> </div>
</div> </div>
<div id='latest-jobs' class='my-4 text-center'> <div id='latest-jobs' class='my-4 text-center'>
......
<div class='col-4 my-2'> <div class='col-4 my-2'>
<div class='card'> <div class='card'>
<%= link_to '#', class: 'card-body text-decoration-none' do %> <%= link_to jobs_path(model: 'industry', slug: industry.slug), class: 'card-body text-decoration-none' do %>
<h5 class='card-title font-weight-bold'><%= industry.name %></h5> <h5 class='card-title font-weight-bold'><%= industry.name %></h5>
<p class='card-text'><%= pluralize(industry.job_count, 'Job') %></p> <p class='card-text'><%= pluralize(industry.job_count, 'Job') %></p>
<% end %> <% end %>
......
<div class='card flex-md-row align-items-center my-2'>
<div class='card-body'>
<%= link_to job.title, '#', class: 'card-title font-weight-bold text-decoration-none' %>
<p class='card-text'><%= job.company.name %></p>
<p class='mb-0'>
<strong>Work place:</strong>
<% job.locations.each do |location| %>
<%= location.city %>
<% end %>
</p>
<p><strong>Salary: </strong><%= job.salary %></p>
<p class='card-text'><%= strip_tags(job.description).truncate(Job::WORDS_SHORT_DESCRIPTION) %></p>
</div>
<div class='btn-favorite p-2'>
<%= link_to 'Favorite', '#', class: 'btn btn-outline-danger btn-lg' %>
</div>
</div>
<div class='px-5'>
<%= render 'shared/searchbar', my_class: 'd-flex flex-column flex-md-row' %>
</div>
<div>
<div class='message text-center'>
<h3>We found <%= pluralize(@jobs.total_count, 'result') %> for "<%= @keyword %>" </h3>
</div>
<hr>
<div class='content'>
<%= paginate @jobs %>
<%= render partial: 'jobs/job', collection: @jobs %>
<%= paginate @jobs %>
</div>
</div>
...@@ -22,7 +22,10 @@ ...@@ -22,7 +22,10 @@
<%= link_to industry.name, '#', class: 'vertical-divider text-dark' %> <%= link_to industry.name, '#', class: 'vertical-divider text-dark' %>
<% end %> <% end %>
</h5> </h5>
<h5><i class="fas fa-wallet"></i> <%= @job.level %></h5>
<h5><i class="fas fa-wallet"></i> <%= @job.experience %></h5>
<h5><i class="fas fa-wallet"></i> <%= @job.salary %></h5> <h5><i class="fas fa-wallet"></i> <%= @job.salary %></h5>
<h5><i class="fas fa-wallet"></i> <%= @job.expiration_date %></h5>
<hr> <hr>
<h3><strong>Description:</strong></h3> <h3><strong>Description:</strong></h3>
<%= @job.description.html_safe %> <%= @job.description.html_safe %>
......
<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 justify-content-end">
<%= 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>
...@@ -9,9 +9,11 @@ ...@@ -9,9 +9,11 @@
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head> </head>
<body class='container'> <body>
<%= render 'shared/header' %> <%= render 'shared/header' %>
<div class='container'>
<%= yield %> <%= yield %>
</div>
<%= render 'shared/footer' %> <%= render 'shared/footer' %>
</body> </body>
</html> </html>
<div class='col-4 my-2'> <div class='col-4 my-2'>
<div class='card'> <div class='card'>
<%= link_to '#', class: 'card-body text-decoration-none' do %> <%= link_to jobs_path(model: 'location', slug: location.slug), class: 'card-body text-decoration-none' do %>
<h5 class='card-title font-weight-bold'><%= location.city %></h5> <h5 class='card-title font-weight-bold'><%= location.city %></h5>
<p class='card-text'><%= pluralize(location.job_count, 'Job') %></p> <p class='card-text'><%= pluralize(location.job_count, 'Job') %></p>
<% end %> <% end %>
......
<%= form_tag '#', method: :get, class: 'mt-4' do %> <%= form_tag '#', method: :get, class: "mt-4 form-group #{my_class}" do %>
<%= search_field_tag :search, params[:keyword], placeholder: 'Search', class: 'form-control my-2' %> <%= search_field_tag :search, params[:keyword], placeholder: 'Search', class: 'form-control m-2' %>
<%= select_tag :industry, options_from_collection_for_select(@industries, :id, :name, '1'), class: 'form-control my-2' %> <%= select_tag :industry, options_from_collection_for_select(@industries, :id, :name, '1'), class: 'form-control m-2' %>
<%= select_tag :location, options_from_collection_for_select(@locations, :id, :city, '1'), class: 'form-control my-2' %> <%= select_tag :location, options_from_collection_for_select(@locations, :id, :city, '1'), class: 'form-control m-2' %>
<%= submit_tag 'Search', class: 'btn btn-outline-success my-2 my-sm-0' %> <%= submit_tag 'Search', class: 'btn btn-outline-success m-2' %>
<% end %> <% end %>
# 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
...@@ -3,5 +3,6 @@ Rails.application.routes.draw do ...@@ -3,5 +3,6 @@ Rails.application.routes.draw do
get 'cities', to: 'locations#index' get 'cities', to: 'locations#index'
get 'industries', to: 'industries#index' get 'industries', to: 'industries#index'
get 'detail/:id', to: 'jobs#show', as: :job get 'detail/:id', to: 'jobs#show', as: :job
get 'jobs/:model/:slug', to: 'jobs#index', as: :jobs
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end end
class AddSlugToIndustries < ActiveRecord::Migration[5.2]
def change
add_column :industries, :slug, :string
add_index :industries, :slug, unique: true
end
end
class AddSlugToLocations < ActiveRecord::Migration[5.2]
def change
add_column :locations, :slug, :string
add_index :locations, :slug, 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: 2020_07_20_075150) do ActiveRecord::Schema.define(version: 2020_08_05_034659) do
create_table "applied_jobs", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| create_table "applied_jobs", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t|
t.bigint "user_id" t.bigint "user_id"
...@@ -55,6 +55,8 @@ ActiveRecord::Schema.define(version: 2020_07_20_075150) do ...@@ -55,6 +55,8 @@ ActiveRecord::Schema.define(version: 2020_07_20_075150) do
t.string "name" t.string "name"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.string "slug"
t.index ["slug"], name: "index_industries_on_slug", unique: true
end end
create_table "industries_jobs", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| create_table "industries_jobs", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t|
...@@ -82,6 +84,8 @@ ActiveRecord::Schema.define(version: 2020_07_20_075150) do ...@@ -82,6 +84,8 @@ ActiveRecord::Schema.define(version: 2020_07_20_075150) do
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.boolean "oversea" t.boolean "oversea"
t.string "slug"
t.index ["slug"], name: "index_locations_on_slug", unique: true
end end
create_table "locations_jobs", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| create_table "locations_jobs", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t|
......
module ConvertSlug
def 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.parameterize
end
end
...@@ -13,7 +13,7 @@ class CsvImport ...@@ -13,7 +13,7 @@ class CsvImport
next if row['category'].blank? || row['category'].match(/^[0-9]+$/).present? next if row['category'].blank? || row['category'].match(/^[0-9]+$/).present?
title = row['name'].strip title = row['name'].strip
company = Company.find_or_create_by(name: row['company name']) do |c| company = Company.find_or_create_by(name: row['company name'].strip) do |c|
c.description = "Contact email: #{row['contact email']}\n"\ c.description = "Contact email: #{row['contact email']}\n"\
"Contact name: #{row['contact name']}\n"\ "Contact name: #{row['contact name']}\n"\
"Contact phone: #{row['contact phone']}" "Contact phone: #{row['contact phone']}"
......
namespace :create_slug do
desc 'Create slug model Location'
task locations: :environment do
Location.all.each do |location|
location.update_attributes(slug: "#{location.to_slug(location.city)}-#{Time.now.to_i}#{rand(10000)}")
end
end
desc 'Create slug model Industry'
task industries: :environment do
Industry.all.each do |industry|
industry.update_attributes(slug: "#{industry.to_slug(industry.name)}-#{Time.now.to_i}#{rand(10000)}")
end
end
desc 'Create slug to all model'
task all: %i[locations industries]
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