Commit 77d9a1de by Quang Vinh Nguyen

Merge branch 'add-job-apply' into 'master'

Add job apply

See merge request !8
parents df57c21f 81a7e69f
......@@ -67,6 +67,8 @@ group :development do
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
gem 'pry'
gem "better_errors"
gem "binding_of_caller"
end
group :test do
......
......@@ -54,7 +54,13 @@ GEM
bcrypt (3.1.12-java)
bcrypt (3.1.12-x64-mingw32)
bcrypt (3.1.12-x86-mingw32)
better_errors (2.4.0)
coderay (>= 1.0.0)
erubi (>= 1.0.0)
rack (>= 0.9.0)
bindex (0.5.0)
binding_of_caller (0.8.0)
debug_inspector (>= 0.0.1)
bootsnap (1.3.0)
msgpack (~> 1.0)
bootsnap (1.3.0-java)
......@@ -94,6 +100,7 @@ GEM
dry-validation (>= 0.10.4)
crass (1.0.4)
database_cleaner (1.7.0)
debug_inspector (0.0.3)
deep_merge (1.2.1)
devise (4.4.3)
bcrypt (~> 3.0)
......@@ -371,6 +378,8 @@ PLATFORMS
x86-mswin32
DEPENDENCIES
better_errors
binding_of_caller
bootsnap (>= 1.1.0)
bootstrap
byebug
......
# frozen_string_literal: true
class EntriesController < ApplicationController
before_action :set_entry, only: [:show, :edit, :update]
before_action :entry_params, only: [:create]
# GET /entries/1
# GET /entries/1.json
def show; end
# GET /entries/new
def new
@entry = if user_signed_in?
Entry.new(entry_name: current_user.name,
entry_email: current_user.email,
entry_phone: current_user.phone,
entry_address: current_user.address)
else
Entry.new
end
end
# POST /entries
# POST /entries.json
def create
@entry = Entry.new(entry_params)
@job = Job.find(params[:job_id])
@user = User.find_by(email: params[:entry][:entry_email])
unless @user
random_password = Devise.friendly_token
@user = User.new(name: params[:entry][:entry_name],
email: params[:entry][:entry_email],
phone: params[:entry][:entry_phone],
address: params[:entry][:entry_address],
password: random_password,
password_confirmation: random_password)
@user.skip_confirmation!
@user.save!
end
@entry.user_id = @user.id
@entry.job_id = @job.id
if @user.jobs.find_by(id: @job.id)
redirect_to job_url(@job), flash: { secondary: 'You has been entry this job.' }
else
if @entry.save
UserMailer.job_apply(@user, @job).deliver_now
redirect_to @entry, flash: { secondary: 'Thank you for apply. Please check your email.' }
else
render :new
end
end
end
# PATCH/PUT /entries/1
# PATCH/PUT /entries/1.json
def update
if @entry.update(entry_params)
redirect_to @entry, notice: 'Entry was successfully updated.'
else
render :edit
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_entry
@entry = Entry.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def entry_params
params.require(:entry).permit(:entry_name, :entry_email, :entry_phone, :entry_address)
end
end
module EntriesHelper
end
class UserMailer < ApplicationMailer
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.user_mailer.job_apply.subject
#
# def job_apply
# @greeting = "Hi"
# mail to: "to@example.org"
# end
def job_apply(user, job)
@user = user
@job = job
mail to: user.email, subject: 'Thank you for apply with VeNJOB'
end
end
class Entry < ApplicationRecord
belongs_to :user, foreign_key: 'user_id'
belongs_to :job, foreign_key: 'job_id'
validates :entry_name, presence: true
validates :entry_email, presence: true
end
......@@ -11,8 +11,8 @@ class Job < ApplicationRecord
dependent: :destroy
has_many :industries, through: :industries_jobs
has_many :entries, dependent: :destroy
has_many :favorite_jobs, dependent: :destroy
has_many :entries, foreign_key: 'job_id'
has_many :users, through: :entries
validates :title, presence: true, length: { maximum: 255 },
uniqueness: { case_sensitive: false }
......
# frozen_string_literal: true
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:recoverable, :rememberable, :validatable,
:confirmable
has_many :entries, dependent: :destroy
has_many :favorite_jobs, dependent: :destroy
validates :name, presence: true, length: { maximum: 255 }
has_many :entries, foreign_key: 'user_id',
dependent: :destroy
has_many :jobs, through: :entries
# validates :name, presence: true, length: { maximum: 255 }
validates :prefix, presence: true
# validates :prefix, presence: true
VALID_PHONE_REGEX = /\A^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}\z/
validates :phone, length: { maximum: 50 },
format: { with: VALID_PHONE_REGEX }
# VALID_PHONE_REGEX = /\A^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}\z/
# validates :phone, length: { maximum: 50 },
# format: { with: VALID_PHONE_REGEX }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX }
validates :password, presence: true, length: { minimum: 8 }
# Sends apply email.
def send_job_apply_email(job)
UserMailer.job_apply(self, job).deliver_now
end
end
......@@ -35,9 +35,10 @@
<%= f.submit "Update" %>
</div>
<% end %>
<!--
<h3>Cancel my account</h3>
<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>
<%= link_to "Back", :back %>
-->
\ No newline at end of file
<%= form_with(model: entry, local: true) do |form| %>
<% if entry.errors.any? %>
<div id="error_explanation">
<h5><%= pluralize(entry.errors.count, "error") %> prohibited this entry from being saved:</h5>
<ul>
<% entry.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= hidden_field_tag :job_id, @job.id %>
<%= form.label :name %><br>
<%= form.text_field :entry_name, class: 'form-control col-sm-6' %><br>
<%= form.label :email %><br>
<%= form.email_field :entry_email, class: 'form-control col-sm-6' %><br>
<%= form.label :phone %><br>
<%= form.telephone_field :entry_phone, class: 'form-control col-sm-6' %><br>
<%= form.label :address %><br>
<%= form.text_area :entry_address, class: 'form-control col-sm-6' %><br>
<%= form.submit yield(:button_text), class: "btn btn-secondary" %>
<%= link_to 'Back', :back, class: "btn btn-secondary" %>
<% end %>
<% provide(:button_text, 'Save') %>
<% @job = Job.find(@entry.job_id) %>
<h1>Editing Entry</h1>
<%= render 'form', entry: @entry %>
\ No newline at end of file
<% provide(:button_text, 'Apply') %>
<% @job = Job.find(params[:job_id]) %>
<h3>Id: <%= @job.id %> -- Job_title: <%= @job.title %> </h3>
<% provide(:job_id, @job.id) %>
<%= render 'form', entry: @entry %>
\ No newline at end of file
<% @job = Job.find(@entry.job_id) %>
<h3>Id: <%= @job.id %> -- Job_title: <%= @job.title %> </h3>
<p>
<strong>Name:</strong>
<%= @entry.entry_name %>
</p>
<p>
<strong>Email:</strong>
<%= @entry.entry_email %>
</p>
<%= link_to 'Edit', edit_entry_path(id: @entry.id), class: "btn btn-secondary" %>
<%= link_to 'Back', job_path(@job), class: "btn btn-secondary" %>
json.partial! "entries/entry", entry: @entry
......@@ -10,6 +10,11 @@
<p>
<%= @job.description %>
</p>
<%= link_to "Apply", apply_path(job_id: @job.id),
class: "btn btn-secondary" %>
<%= link_to 'Back', :back, class: "btn btn-secondary" %>
</section>
</aside>
</div>
......@@ -11,6 +11,21 @@
<li class="nav-item active">
<%= link_to 'City', city_jobs_path, class: 'nav-link' %>
</li>
<% if user_signed_in? %>
<li class="nav-item active">
<%= link_to 'Edit profile', edit_user_registration_path, class: 'nav-link' %>
</li>
<li class="nav-item active">
<%= link_to "Logout", destroy_user_session_path, method: :delete, class: 'nav-link' %>
</li>
<% else %>
<li class="nav-item active">
<%= link_to "Sign up", new_user_registration_path, class: 'nav-link' %>
</li>
<li class="nav-item active">
<%= link_to "Login", new_user_session_path, class: 'nav-link' %>
</li>
<% end %>
</ul>
</div>
</nav>
<p>Dear <%= @user.name %></p>
<p>Job title: <%= @job.title %></p>
<p>Location: <%= @job.cities.first.name %></p>
<p>Company: <%= @job.company.name %></p>
<p>Your submitted information:</p>
<p>Full Name: <%= @user.name %></p>
<p>Email: <%= @user.email %></p>
<p>Best,</p>
<p>Boss</p>
\ No newline at end of file
Dear <%= @user.name %>
Job title: <%= @job.title %>
Location: <%= @job.cities.first.name %>
Company: <%= @job.company.name %>
Your submitted information:
Full Name: <%= @user.name %>
Email: <%= @user.email %>
Best,
boss
\ No newline at end of file
......@@ -18,8 +18,8 @@ Devise.setup do |config|
# 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
# with default "from" parameter.
config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'
# config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'
config.mailer_sender = 'noreply@example.com'
# Configure the class responsible to send e-mails.
# config.mailer = 'Devise::Mailer'
......
Rails.application.routes.draw do
root to: 'jobs#home'
resources :entries, only: [:new, :create, :show, :edit, :update]
get '/apply', to: 'entries#new'
resources :jobs do
collection do
get 'home'
......
......@@ -8,6 +8,7 @@ class DeviseCreateUsers < ActiveRecord::Migration[5.2]
t.string :prefix, default: ''
t.string :phone, default: ''
t.boolean :registration, default: false
t.text :address
## Database authenticatable
t.string :email, null: false, default: ''
......
......@@ -3,8 +3,13 @@ class CreateEntries < ActiveRecord::Migration[5.2]
create_table :entries do |t|
t.references :user, foreign_key: true
t.references :job, foreign_key: true
t.string :entry_name
t.string :entry_email
t.string :entry_phone
t.text :entry_address
t.timestamps
end
add_index :entries, [:user_id, :job_id], unique: true
end
end
require 'rails_helper'
# This spec was generated by rspec-rails when you ran the scaffold generator.
# It demonstrates how one might use RSpec to specify the controller code that
# was generated by Rails when you ran the scaffold generator.
#
# It assumes that the implementation code is generated by the rails scaffold
# generator. If you are using any extension libraries to generate different
# controller code, this generated spec may or may not pass.
#
# It only uses APIs available in rails and/or rspec-rails. There are a number
# of tools you can use to make these specs even more expressive, but we're
# sticking to rails and rspec-rails APIs to keep things simple and stable.
#
# Compared to earlier versions of this generator, there is very limited use of
# stubs and message expectations in this spec. Stubs are only used when there
# is no simpler way to get a handle on the object needed for the example.
# Message expectations are only used when there is no simpler way to specify
# that an instance is receiving a specific message.
#
# Also compared to earlier versions of this generator, there are no longer any
# expectations of assigns and templates rendered. These features have been
# removed from Rails core in Rails 5, but can be added back in via the
# `rails-controller-testing` gem.
RSpec.describe EntriesController, type: :controller do
# This should return the minimal set of attributes required to create a valid
# Entry. As you add validations to Entry, be sure to
# adjust the attributes here as well.
let(:valid_attributes) {
skip("Add a hash of attributes valid for your model")
}
let(:invalid_attributes) {
skip("Add a hash of attributes invalid for your model")
}
# This should return the minimal set of values that should be in the session
# in order to pass any filters (e.g. authentication) defined in
# EntriesController. Be sure to keep this updated too.
let(:valid_session) { {} }
describe "GET #index" do
it "returns a success response" do
entry = Entry.create! valid_attributes
get :index, params: {}, session: valid_session
expect(response).to be_success
end
end
describe "GET #show" do
it "returns a success response" do
entry = Entry.create! valid_attributes
get :show, params: {id: entry.to_param}, session: valid_session
expect(response).to be_success
end
end
describe "GET #new" do
it "returns a success response" do
get :new, params: {}, session: valid_session
expect(response).to be_success
end
end
describe "GET #edit" do
it "returns a success response" do
entry = Entry.create! valid_attributes
get :edit, params: {id: entry.to_param}, session: valid_session
expect(response).to be_success
end
end
describe "POST #create" do
context "with valid params" do
it "creates a new Entry" do
expect {
post :create, params: {entry: valid_attributes}, session: valid_session
}.to change(Entry, :count).by(1)
end
it "redirects to the created entry" do
post :create, params: {entry: valid_attributes}, session: valid_session
expect(response).to redirect_to(Entry.last)
end
end
context "with invalid params" do
it "returns a success response (i.e. to display the 'new' template)" do
post :create, params: {entry: invalid_attributes}, session: valid_session
expect(response).to be_success
end
end
end
describe "PUT #update" do
context "with valid params" do
let(:new_attributes) {
skip("Add a hash of attributes valid for your model")
}
it "updates the requested entry" do
entry = Entry.create! valid_attributes
put :update, params: {id: entry.to_param, entry: new_attributes}, session: valid_session
entry.reload
skip("Add assertions for updated state")
end
it "redirects to the entry" do
entry = Entry.create! valid_attributes
put :update, params: {id: entry.to_param, entry: valid_attributes}, session: valid_session
expect(response).to redirect_to(entry)
end
end
context "with invalid params" do
it "returns a success response (i.e. to display the 'edit' template)" do
entry = Entry.create! valid_attributes
put :update, params: {id: entry.to_param, entry: invalid_attributes}, session: valid_session
expect(response).to be_success
end
end
end
describe "DELETE #destroy" do
it "destroys the requested entry" do
entry = Entry.create! valid_attributes
expect {
delete :destroy, params: {id: entry.to_param}, session: valid_session
}.to change(Entry, :count).by(-1)
end
it "redirects to the entries list" do
entry = Entry.create! valid_attributes
delete :destroy, params: {id: entry.to_param}, session: valid_session
expect(response).to redirect_to(entries_url)
end
end
end
UserMailer#job_apply
Hi, find me in app/views/user_mailer/job_apply
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the EntriesHelper. For example:
#
# describe EntriesHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# expect(helper.concat_strings("this","that")).to eq("this that")
# end
# end
# end
RSpec.describe EntriesHelper, type: :helper do
pending "add some examples to (or delete) #{__FILE__}"
end
# Preview all emails at http://localhost:3000/rails/mailers/user_mailer
class UserMailerPreview < ActionMailer::Preview
# Preview this email at http://localhost:3000/rails/mailers/user_mailer/job_apply
def job_apply
UserMailerMailer.job_apply
end
end
require "rails_helper"
RSpec.describe UserMailer, type: :mailer do
describe "job_apply" do
let(:mail) { UserMailer.job_apply }
it "renders the headers" do
expect(mail.subject).to eq("Job apply")
expect(mail.to).to eq(["to@example.org"])
expect(mail.from).to eq(["from@example.com"])
end
it "renders the body" do
expect(mail.body.encoded).to match("Hi")
end
end
end
require 'rails_helper'
RSpec.describe "Entries", type: :request do
describe "GET /entries" do
it "works! (now write some real specs)" do
get entries_path
expect(response).to have_http_status(200)
end
end
end
require "rails_helper"
RSpec.describe EntriesController, type: :routing do
describe "routing" do
it "routes to #index" do
expect(:get => "/entries").to route_to("entries#index")
end
it "routes to #new" do
expect(:get => "/entries/new").to route_to("entries#new")
end
it "routes to #show" do
expect(:get => "/entries/1").to route_to("entries#show", :id => "1")
end
it "routes to #edit" do
expect(:get => "/entries/1/edit").to route_to("entries#edit", :id => "1")
end
it "routes to #create" do
expect(:post => "/entries").to route_to("entries#create")
end
it "routes to #update via PUT" do
expect(:put => "/entries/1").to route_to("entries#update", :id => "1")
end
it "routes to #update via PATCH" do
expect(:patch => "/entries/1").to route_to("entries#update", :id => "1")
end
it "routes to #destroy" do
expect(:delete => "/entries/1").to route_to("entries#destroy", :id => "1")
end
end
end
require 'rails_helper'
RSpec.describe "entries/edit", type: :view do
before(:each) do
@entry = assign(:entry, Entry.create!(
:entry_name => "MyString",
:entry_email => "MyString"
))
end
it "renders the edit entry form" do
render
assert_select "form[action=?][method=?]", entry_path(@entry), "post" do
assert_select "input[name=?]", "entry[entry_name]"
assert_select "input[name=?]", "entry[entry_email]"
end
end
end
require 'rails_helper'
RSpec.describe "entries/index", type: :view do
before(:each) do
assign(:entries, [
Entry.create!(
:entry_name => "Entry Name",
:entry_email => "Entry Email"
),
Entry.create!(
:entry_name => "Entry Name",
:entry_email => "Entry Email"
)
])
end
it "renders a list of entries" do
render
assert_select "tr>td", :text => "Entry Name".to_s, :count => 2
assert_select "tr>td", :text => "Entry Email".to_s, :count => 2
end
end
require 'rails_helper'
RSpec.describe "entries/new", type: :view do
before(:each) do
assign(:entry, Entry.new(
:entry_name => "MyString",
:entry_email => "MyString"
))
end
it "renders new entry form" do
render
assert_select "form[action=?][method=?]", entries_path, "post" do
assert_select "input[name=?]", "entry[entry_name]"
assert_select "input[name=?]", "entry[entry_email]"
end
end
end
require 'rails_helper'
RSpec.describe "entries/show", type: :view do
before(:each) do
@entry = assign(:entry, Entry.create!(
:entry_name => "Entry Name",
:entry_email => "Entry Email"
))
end
it "renders attributes in <p>" do
render
expect(rendered).to match(/Entry Name/)
expect(rendered).to match(/Entry Email/)
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