文章目录
  1. 1. 课程目标
  2. 2. 课程复盘
    1. 2.1. 1. 实作 Admin 的 CRUD
      1. 2.1.1. Step 1: 产生 http://localhost:3000/admin/jobs 的网址
      2. 2.1.2. Step 2 : 实作 admin::jobs 的 CRUD
      3. 2.1.3. Step 3: 把通往后台的选单加到下拉选单里:
      4. 2.1.4. Step 4: 限定只有 admin 才可以进后台
      5. 2.1.5. Step 5: 重构 admin 条件,放到 model 里面
      6. 2.1.6. Step 6: 把 admin? 的条件改为由资料库判断
      7. 2.1.7. Step 7: 把你的帐户提升为 admin
      8. 2.1.8. Step 8 限制只有 admin 才可以看到选单:
      9. 2.1.9. Step 9: 把 require_is_admin 移到 application_controller
      10. 2.1.10. Step 10: git 存档
    2. 2.2. 2. 新增“薪资上限”“薪资下限”“联络 Email”
    3. 2.3. 3. 新增栏位,并加上栏位白名单
    4. 2.4. 5. 新增 is_hidden 栏位到 Job
    5. 2.5. 6. 让前后台的 Job List 长得不一样
    6. 2.6. 7. 哪里有好用的 Gems
    7. 2.7. 8. ERB ( Embedded Ruby )
    8. 2.8. 9. 利用 layout 可以做出不同的view
    9. 2.9. 10. 使用 FontAwesome
    10. 2.10. 11. 实作“被隐藏的工作”,不可以被查看到。
    11. 2.11. 12. erb文件中加入按钮
    12. 2.12. 13. routing 加上去 publish 与 hide

课程目标

两个主题:

  • 什么是 Computational Thinking
  • 如何把脑袋的点子落地变成代码

做第一个简单的网站:一个招聘网站。这个网站会跟 Rails 101 很像。你会发现,将脑袋的点子落地变成代码,并不是想像中的难

课程复盘

1. 实作 Admin 的 CRUD

  • 实作 Admin 的 CRUD
  • 身为管理者才可以存取 http://localhost:3000/admin/jobs 下的职缺操作
  • 身为管理者才可以看到 Admin 管理选单的链接
  • admin 的判定应该使用资料库的判断 is_admin

Step 1: 产生 http://localhost:3000/admin/jobs 的网址

1
rails g controller admin::jobs

然后修改 routing

加入

config/routes.rb
1
2
3
namespace :admin do
resources :jobs
end

Step 2 : 实作 admin::jobs 的 CRUD

app/controllers/admin/jobs_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class Admin::JobsController < ApplicationController
before_action :authenticate_user!, only: [:new, :create, :update, :edit, :destroy]
def show
@job = Job.find(params[:id])
end
def index
@jobs = Job.all
end
def new
@job = Job.new
end
def create
@job = Job.new(job_params)
if @job.save
redirect_to admin_jobs_path
else
render :new
end
end
def edit
@job = Job.find(params[:id])
end
def update
@job = Job.find(params[:id])
if @job.update(job_params)
redirect_to admin_jobs_path
else
render :edit
end
end
def destroy
@job = Job.find(params[:id])
@job.destroy
redirect_to admin_jobs_path
end
private
def job_params
params.require(:job).permit(:title, :description)
end
end

新增 app/views/admin/jobs/index.html.erb

app/views/admin/jobs/index.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div class="pull-right">
<%= link_to("Add a job", new_admin_job_path, :class => "btn btn-default" ) %>
</div>
<br><br>
<table class="table table-bordered">
<% @jobs.each do |job| %>
<tr>
<td>
<%= link_to(job.title, admin_job_path(job)) %>
</td>
<td>
<%= link_to("Edit", edit_admin_job_path(job)) %>
<%= link_to("Destroy", admin_job_path(job), :method => :delete, :data => { :confirm => "Are you sure?" }) %>
</td>
<td>
<%= job.created_at %>
</td>
</tr>
<% end %>
</table>

新增 app/views/admin/jobs/new.html.erb

app/views/admin/jobs/new.html.erb
1
2
3
4
5
6
7
8
9
<h1> Add a job </h1>
<%= simple_form_for [:admin,@job] do |f| %>
<%= f.input :title %>
<%= f.input :description %>
<%= f.submit "Submit" %>
<% end %>

新增 app/views/admin/jobs/show.html.erb

app/views/admin/jobs/show.html.erb
1
2
3
4
5
6
<h1> <%= @job.title %> </h1>
<p>
<%= simple_format(@job.description) %>
</p>

新增 app/views/admin/jobs/edit.html.erb

app/views/admin/jobs/edit.html.erb
1
2
3
4
5
6
7
8
9
<h1> Edit a job </h1>
<%= simple_form_for [:admin, @job ] do |f| %>
<%= f.input :title %>
<%= f.input :description %>
<%= f.submit "Submit" %>
<% end %>

Step 3: 把通往后台的选单加到下拉选单里:

可以这么做

app/views/common/_navbar.html.erb
1
2
<li> <%= link_to("Admin Panel", admin_jobs_path) %> </li>
<li> <%= link_to("登出", destroy_user_session_path, method: :delete) %> </li>

Step 4: 限定只有 admin 才可以进后台

这时候我们要设计一个新的 method 叫 require_is_admin

app/controllers/admin/jobs_controller.rb
1
2
3
class Admin::JobsController < ApplicationController
before_action :authenticate_user!, only: [:new, :create, :update, :edit, :destroy]
before_action :require_is_admin

然后呢,再加入一个 require_is_admin 的条件

这里我们姑且把条件叫做 email 是“管理员的 email”(你可以改成你自己的)

app/controllers/admin/jobs_controller.rb
1
2
3
4
5
6
def require_is_admin
if current_user.email != 'xdite@growth.school'
flash[:alert] = 'You are not admin'
redirect_to root_path
end
end

这样其他使用者,就不能进去 admin panel 了。

Step 5: 重构 admin 条件,放到 model 里面

接着呢, current_user.email != ‘xdite@growth.school’ 这样不是很好看,我们应该要把条件改成 if !current_user.admin?

这样比较美观。

所以呢,你可以把刚刚的那一段改成:

app/controllers/admin/jobs_controller.rb
1
2
3
4
5
6
def require_is_admin
if !current_user.admin?
flash[:alert] = 'You are not admin'
redirect_to root_path
end
end

然后在 app/models/user.rb 加入一段 admin? 的自定义

app/models/user.rb
1
2
3
4
5
6
class User < ApplicationRecord
# ....
def admin?
email == 'xdite@growth.school'
end

这样就做了一次“整理的动作”。这样以后你就可以自己重新定义里面的条件。

Step 6: 把 admin? 的条件改为由资料库判断

其实呢,admin 的这个条件,最好不要写死在代码中,比较好的方式,是记在数据库中。所以我们可以这样做:

1
rails g migration add_is_admin_to_user

然后修改 migration 档,变成

db/migrate/xxxxx.rb
1
2
3
4
5
class AddIsAdminToUser < ActiveRecord::Migration[5.0]
def change
add_column :users, :is_admin, :boolean, default: false
end
end

1
rake db:migrate

接着我们再更改 app/models/user.rb 的 admin? 的定义,唯有 user 的 is_admin 这个栏位是 true 时,这个人才会被判定为 admin

app/models/user.rb
1
2
3
def admin?
is_admin
end

Step 7: 把你的帐户提升为 admin

不过我们系统现在都是一般 user 啊,所以我们要把系统刚刚建的 user 提升为 admin。
打开

1
rails console

输入:

1
2
3
4
u = User.first
u.is_admin = true
u.save
exit

这样你的 user 就会变成 admin 了

Step 8 限制只有 admin 才可以看到选单:

刚刚我们有做一个下拉选单嘛,应该要限制是 admin 才能看到下拉选单,那你现在就可以这样改了:

app/views/common/_navbar.html.erb
1
2
3
4
<% if current_user.admin? %>
<li> <%= link_to("Admin Panel", admin_jobs_path) %> </li>
<% end %>
<li> <%= link_to("登出", destroy_user_session_path, method: :delete) %> </li>

Step 9: 把 require_is_admin 移到 application_controller

因为 require_is_admin 将来很多地方会用到,其实你是可以这样做的,把原本在 admin/jobs_controller.rb

app/controllers/admin/jobs_controller.rb
1
2
3
4
5
6
7
8
class Admin::JobsController < ApplicationController
def require_is_admin
if !current_user.admin?
flash[:alert] = 'You are not admin'
redirect_to root_path
end
end
end

这段,搬到 application_controller.rb

app/controllers/application_controller.rb
1
2
3
4
5
6
7
8
9
10
class ApplicationController < ActionController::Base
def require_is_admin
if !current_user.admin?
flash[:alert] = 'You are not admin'
redirect_to root_path
end
end
end

这样之后就更多人可以调用这个 method。

Step 10: git 存档

1
2
git add .
git commit -m "implement part 2"

2. 新增“薪资上限”“薪资下限”“联络 Email”

新增三个栏位:

  • wage_upper_bound (数字)
  • wage_lower_bound (数字)
  • contact_email (字串)
1
rails g migration add_more_detail_to_job

修改 db/migrate/XXX_add_more_detail_to_job.rb

db/migrate/XXX_add_more_detail_to_job.rb
1
2
3
4
5
6
7
class AddMoreDetailToJob < ActiveRecord::Migration[5.0]
def change
add_column :jobs, :wage_upper_bound, :integer
add_column :jobs, :wage_lower_bound, :integer
add_column :jobs, :contact_email, :string
end
end

然后

1
rake db:migrate

3. 新增栏位,并加上栏位白名单

新增以下栏位

1
2
3
<%= f.input :wage_lower_bound, :label => "薪资下限" %>
<%= f.input :wage_upper_bound, :label => "薪资上限" %>
<%= f.input :contact_email %>

加上栏位白名单

既然新增了栏位,我们也要去改

  • app/controllers/admin/jobs_controller.rb
  • app/controllers/jobs_controller.rb

修改下面这一段,加入 :wage_upper_bound, :wage_lower_bound, :contact_email

1
2
3
4
5
6
7
8
9
10
11
12
13
def job_params
params.require(:job).permit(:title, :description, :wage_upper_bound, :wage_lower_bound, :contact_email)
end
```
### 4. 薪资不能为空,最低薪资至少要大于 0
修改 app/models/job.rb
```ruby app/models/job.rb
validates :wage_upper_bound, presence: true
validates :wage_lower_bound, presence: true
validates :wage_lower_bound, numericality: { greater_than: 0}

5. 新增 is_hidden 栏位到 Job

1
rails g migration add_is_hidden_to_job

“预设为隐藏”

db/migrate/(一串数字)_add_is_hidden_to_job.rb
1
2
3
4
5
class AddIsHiddenToJob < ActiveRecord::Migration[5.0]
def change
add_column :jobs, :is_hidden, :boolean, default: true
end
end
1
rake db:migrate

修改所有 new/edit 的表单加上这个栏位

1
<%= f.input :is_hidden %>

6. 让前后台的 Job List 长得不一样

修改

app/views/admin/jobs/index.html.erb
1
2
3
4
5
6
7
8
9
10
<td>
<% if job.is_hidden %>
(Hidden)
<% else %>
(Public)
<% end %>
<%= link_to(job.title, admin_job_path(job)) %>
</td>

html.erb中直接用(Hidden)即可。

翻修到 Helper

在 View 里面写一堆 Ruby Code 实在太丑了,因此我们应该要把这段代码重构成 Helper 。

所以我们应该把刚刚那一段判断式砍掉,换成这样

app/views/admin/jobs/index.html.erb
1
2
3
4
5
<td>
<%= render_job_status(job) %>
<%= link_to(job.title, admin_job_path(job)) %>
</td>

然后加入这一段:

app/helpers/jobs_helper.rb
1
2
3
4
5
6
7
8
9
10
module JobsHelper
def render_job_status(job)
if job.is_hidden
"(Hidden)"
else
"(Public)"
end
end
end

helper中用 “(Hidden)” 这里的字符串需要带双引号。

7. 哪里有好用的 Gems

https://www.ruby-toolbox.com/
http://railscasts.com/

8. ERB ( Embedded Ruby )

在 HTML 中嵌入 RUBY 语法的 ERB ( Embedded Ruby )。

1
2
<%= @post.title %> # 显示 @post.title
<% @post.title %> # 执行 @post.title

实际的例子:

1
2
3
4
5
<% sum = 0 %>
<% for i in 1..10 %>
<% sum = sum + i %>
<% end %>
<%= sum %>

以上的代码表示:执行 1+2+3+4+5+6+7+8+9+10 的运算后,印出 55。

9. 利用 layout 可以做出不同的view

先建立新的layout admin app/views/layouts/admin.html.erb,然后在相应的controller中指定layout。

app/controllers/admin/jobs_controller.rb
1
2
3
4
class Admin::JobsController < ApplicationController
before_action :authenticate_user!, only: [:new, :create, :update, :edit, :destroy]
before_action :require_is_admin
layout "admin"

10. 使用 FontAwesome

网站:http://fontawesome.io/icons/

安装 FontAwesome

1
gem 'font-awesome-rails'

然后执行

1
bundle install

接着修改 app/assets/stylesheets/application.scss,因为与外面有关。
加入:

app/assets/stylesheets/application.scss
1
*= require font-awesome

也加入:

app/assets/stylesheets/application.scss
1
@import "font-awesome";

然后重开 rails server

接着我们要换掉 Helper,修改 app/helpers/jobs_helper.rb 当中的 render_job_status(job)

app/helpers/jobs_helper.rb
1
2
3
4
5
6
7
def render_job_status(job)
if job.is_hidden
content_tag(:span, "", :class => "fa fa-lock")
else
content_tag(:span, "", :class => "fa fa-globe")
end
end

11. 实作“被隐藏的工作”,不可以被查看到。

把 app/controllers/jobs_controller.rb 当中的 show action
改成

app/controllers/jobs_controller.rb
1
2
3
4
5
6
7
8
def show
@job = Job.find(params[:id])
if @job.is_hidden
flash[:warning] = "This Job already archived"
redirect_to root_path
end
end

使用普通用户登录,在浏览器地址栏输入

1
http://localhost:3000/jobs/x (x是被隐藏的工作的ID编号)

会提示不可查看。

12. erb文件中加入按钮

设计按钮,将“隐藏职缺”改成是一个按钮,按下去“隐藏职缺”,再按一次“显示职缺”

app/views/admin/jobs/index.html.erb
1
2
3
4
5
6
<% if job.is_hidden %>
<%= link_to("Publish", publish_admin_job_path(job) , :method => :post, :class => "btn btn-xs btn-default") %>
<% else %>
<%= link_to("Hide", hide_admin_job_path(job), :method => :post, :class => "btn btn-xs btn-default") %>
<% end %>

Bootstrap中的

1
<%= link_to("Publish", publish_admin_job_path(job) , :method => :post, :class => "btn btn-xs btn-default") %>

自动显示为按钮button, 目标路径 publish_admin_job_path,动作 :method => :post。

13. routing 加上去 publish 与 hide

config/routes.rb
1
2
3
4
5
6
7
8
namespace :admin do
resources :jobs do
member do
post :publish
post :hide
end
end
end

设计 publish / hide 的 action

所以你还得在 app/controllers/admin/jobs_controller.rb 加入:

app/controllers/admin/jobs_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
def publish
@job = Job.find(params[:id])
@job.is_hidden = false
@job.save
redirect_to :back
end
def hide
@job = Job.find(params[:id])
@job.is_hidden = true
@job.save
redirect_to :back
end

但是controller中加入很多与数据库相关的操作不符合Rails 风格。将上述内容重构至model中。

首先到 app/models/job.rb 实作 publish! 与 hide!

app/models/job.rb
1
2
3
4
5
6
7
8
9
10
11
class Job < ApplicationRecord
def publish!
self.is_hidden = false
self.save
end
def hide!
self.is_hidden = true
self.save
end
end

再去把 app/controllers/admin/jobs_controller.rb 中的两个 action 换掉:

app/controllers/admin/jobs_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def publish
@job = Job.find(params[:id])
@job.publish!
redirect_to :back
end
def hide
@job = Job.find(params[:id])
@job.hide!
redirect_to :back
end

参考:Rails 风格指南

文章目录
  1. 1. 课程目标
  2. 2. 课程复盘
    1. 2.1. 1. 实作 Admin 的 CRUD
      1. 2.1.1. Step 1: 产生 http://localhost:3000/admin/jobs 的网址
      2. 2.1.2. Step 2 : 实作 admin::jobs 的 CRUD
      3. 2.1.3. Step 3: 把通往后台的选单加到下拉选单里:
      4. 2.1.4. Step 4: 限定只有 admin 才可以进后台
      5. 2.1.5. Step 5: 重构 admin 条件,放到 model 里面
      6. 2.1.6. Step 6: 把 admin? 的条件改为由资料库判断
      7. 2.1.7. Step 7: 把你的帐户提升为 admin
      8. 2.1.8. Step 8 限制只有 admin 才可以看到选单:
      9. 2.1.9. Step 9: 把 require_is_admin 移到 application_controller
      10. 2.1.10. Step 10: git 存档
    2. 2.2. 2. 新增“薪资上限”“薪资下限”“联络 Email”
    3. 2.3. 3. 新增栏位,并加上栏位白名单
    4. 2.4. 5. 新增 is_hidden 栏位到 Job
    5. 2.5. 6. 让前后台的 Job List 长得不一样
    6. 2.6. 7. 哪里有好用的 Gems
    7. 2.7. 8. ERB ( Embedded Ruby )
    8. 2.8. 9. 利用 layout 可以做出不同的view
    9. 2.9. 10. 使用 FontAwesome
    10. 2.10. 11. 实作“被隐藏的工作”,不可以被查看到。
    11. 2.11. 12. erb文件中加入按钮
    12. 2.12. 13. routing 加上去 publish 与 hide