您的位置:首页 > 大数据 > 人工智能

Rails 实战——图书管理系统——图书后台

2018-03-26 09:28 471 查看

目标

建立图书管理后台,实现图书CRUD、会员系统、 “上架与下架” 一键切换,借书单。

在本教程中两个符号 “*…” 中间插入的代码新增代码。

1、配置路由

设定后台图书的 CURD、前台图书的路由

config/routes.rb

Rails.application.routes.draw do
root 'welcome#index'
* resources :users
* resources :sessions
resources :books
namespace :admin do #使用命名空间 namespace
resources :books
end
* # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end


2、建立 Book 数据表

2.1 数据库中建立 book 数据表

$ rails g migration create_books


db/migrate/xxxx一堆数字xxxx_create_books.rb

class CreateBooks < ActiveRecord::Migration[5.1]
* def change
*   create_table :books do |t|
t.string :title
t.text   :text

t.timestamps
*   end
* end
end


2.2 建立 book 模型

$ touch app/models/book.rb


app/models/book.rb

class Book < ApplicationRecord
end


2.3 测试

终端进入 rails c (后台金手指)

rails c  #进入 rails 金手指
u = Book.new
u.title = "Hello"
u.text = "World"
u.save
exit     #退出 rails 金手指




3、实现 Book 后台的 CRUD

3.1 Book的New

终端执行

mkdir app/controllers/admin
touch app/controllers/admin/books_controller.rb


配置文件 app/controllers/admin/books_controller.rb

class Admin::BooksController < ApplicationController
# 使用命名空间 namespace ,class的命名使用 Admin::BooksController 格式
def new
@book = Book.new
end

def create
@book = Book.new(book_params)

if @book.save
#查询单个数据必须传递参数实现检索定位,例如@book
redirect_to book_path(@book)
#重定向 >> 图书 show 页面
else
render "new"
end
end

private

#健壮参数,简化参数代码,实现 rails 预筛选安全机制。
def book_params
params.require(:book).permit(:title, :text)
end
end


终端执行

mkdir app/views/admin/books
touch app/views/admin/books/new.html.erb


配置文件 app/views/admin/books/new.html.erb

<h1>新书上架</h1>
#使用命名空间 namespace ,传递参数使用数组[:admin, @book]
<%= form_for [:admin, @book] do |f| %>
<p>
<%= f.label :title %>
<%= f.text_field :title %>
</p>

<p>
<%= f.label :text %>
<%= f.text_area :text %>
</p>

<p>
<%= f.submit "提交"%>
</p>
<% end %>




3.2 Book的show

修改文件 app/controllers/admin/books_controller.rb

class Admin::BooksController < ApplicationController
def index
@books = Book.all
end

* def new
* end

* def create
* end

def show
@book = Book.find(params[:id])
end
end


终端执行

book 后台新建的图书,要让所有人都看到,需要新建文件 app/views/books

mkdir app/views/books
touch app/views/books/show.html.erb
touch app/views/admin/books/index.html.erb


配置图书展示页 app/views/books/show.html.erb

<h1>图书简介</h1>
<p>
<strong>书名:</strong>
<%= @book.title %>
</p>
<p>
<strong>简介:</strong>
<%= @book.text %>
</p>


3.3 Book的edit

修改文件 app/controllers/admin/books_controller.rb

class Admin::BooksController < ApplicationController
......
* def show
* end

def edit
@book = Book.find(params[:id])
end

def update
@book = Book.find(params[:id])

if @book.update(book_params)
#查询某数据表所有数据,可以省略传递参数
redirect_to admin_books_path
else
render "edit"
end
end

......
end


终端执行

touch app/views/admin/books/edit.html.erb


配置文件 app/views/admin/books/edit.html.erb

<h1>图书修改</h1>
<%= form_for [:admin, @book] do |f| %>
<p>
<%= f.label :title %>
<%= f.text_field :title %>
</p>

<p>
<%= f.label :text %>
<%= f.text_area :text %>
</p>

<p>
<%= f.submit "提交"%>
</p>
<% end %>




配置图书后台首页 app/views/admin/books/index.html.erb

<h1>图书馆后台</h1>
<p>
<%= link_to "新书上架", new_admin_book_path %>
</p>

<table class="table table-bordered table-hover">
<tr class="text-info">
<th>书名</th>
<th>简介</th>
<th>操作</th>
</tr>
<% @books.each do |book| %>
<tr>
<td><%= book.title %></td>
<td><%= book.text %></td>
<td>
<%= link_to "显示", book_path(book) %><span style="margin-left: 5px">|</span>
<%= link_to "编辑", edit_admin_book_path(book) %><span style="margin-left: 5px">|</span>
</td>
</tr>
<% end %>
</table>




3.3 Book的 delete

修改文件 app/controllers/admin/books_controller.rb

class Admin::BooksController < ApplicationController
......
* def update
* end

def destroy
@book = Book.find(params[:id])
@book.destroy

redirect_to admin_books_path
end

* private
......
end


修改文件 app/views/admin/books/index.html.erb

删除动作直接在后台首页执行,需要再次确认删除提示

*       <%= link_to "编辑", edit_admin_book_path(book) %><span style="margin-left: 5px">|</span>
<%= link_to "删除", admin_book_path(book),
method: :delete, data: { confirm: "确定删除本书?"} %>
*     </td>
*   </tr>
* <% end %>
</table>




4、管理员可以登录后台系统

4.1 users 数据表增加 is_admin 字段

终端执行

rails g migration add_is_admin_to_user


配置文件 db/migrate/xxxx一堆数字xxxx_add_is_admin_to_user.rb

class AddIsAdminToUser < ActiveRecord::Migration[5.1]
* def change
add_column :users, :is_admin, :boolean, deafault: false
* end
end


4.2 进入金手指 rails c ,手动配置管理员

rails c
u = User.first
u.is_admin = true
u.save
exit


4.3 加入管理员验证机制

修改文件 app/controllers/admin/books_controller.rb

class Admin::BooksController < ApplicationController
before_action :admin_required

* def index
end


修改文件 app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
* protect_from_forgery with: :exception

def admin_required
if !current_user.present?
redirect_to '/' , alert: "你不是管理员"
#在 rails5.1环境中,消息提示未出现,之后解决
end
end
end


4.4 建立后台布局( layout)

修改文件 app/controllers/admin/books_controller.rb

class Admin::BooksController < ApplicationController
layout "admin"
* before_action :admin_required
.....
end


终端执行

touch app/views/layouts/admin.html.erb
#建立后台布局文件


配置文件 app/views/layouts/admin.html.erb

<!DOCTYPE html>
<html>
<head>
<title>图书馆 后台</title>
<%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<div class="container">
<%= render "common/navbar" %>
<div class="row">
<div class="col-md-2">
<ul class="nav nav-pills nav-stacked" style="max-width: 300px;">
<li> <%= link_to("图书", admin_books_path) %> </li>
</ul>
</div>
<div class="col-md-10">
<%= yield %>
</div>
</div>
</div>
</body>
</html>


git add .
git commit -m "only admin can access backend panel"


5、图书状态“上架与下架”一键更改

5.1 路由配置

设定一键切换图书状态的路由

修改文件 config/routes.rb

Rails.application.routes.draw do
.......
* resources :books
* namespace :admin do
resources :books do
collection do
post "book_update"
end
end
* end
end


5.2 books 数据表增加 book_state字段

终端执行

#添加图书状态字段
rails g migration add_book_state_to_book

#添加图书库存字段
rails g migration add_book_stock_to_book


配置文件 db/migrate/xxxx一堆数字xxxx_add_book_state_to_book.rb

class AddBookStateToBook < ActiveRecord::Migration[5.1]
* def change
add_column :books, :book_state, :string
* end
end


配置文件 db/migrate/xxxx一堆数字xxxx_add_book_stock_to_book.rb

class AddBookStockToBook < ActiveRecord::Migration[5.1]
* def change
add_column :books, :book_stock, :integer
* end
end


5.3 Controller 设置图书状态切换方法

修改文件 app/controllers/admin/books_controller.rb

* def destroy

def book_update
@book = Book.find(params[:id])     #接受view层传递的id参数
if @book.book_state == "上架"       #图书状态如果为"上架"字符串
@book.update(book_state: "下架")  #更新为"下架"字符串状态
flash[:error] = "下架成功"
else                               #图书状态为非"上架"字符串
@book.update(book_state: "上架")  #更新为"上架"字符串状态
flash[:error] = "上架成功"
end
redirect_to admin_books_path
end

* private

* def book_params
params.require(:book).permit(:title, :text, :book_stock, :book_state)
* end
end


5.4 View 层, 配置 book_state 代码

修改文件 app/views/admin/books/index.html.erb

<h1>图书馆后台</h1>
+ <%=flash[:error]%>
+ <%=flash[:waning]%>
+ <%=flash[:notice]%>

<p>
+ <%= link_to "新书上架", new_admin_book_path %>
</p>
<table class="table table-bordered table-hover">
<tr class="text-info">
<th>书名</th>
<th>简介</th>
+   <th>库存</th>
+   <th>状态</th>
<th>操作</th>
</tr>
<% @books.each do |book| %>
<tr class="text-info">
<td><%= book.title %></td>
<td><%= book.text %></td>
+     <td><%= book.book_stock %></td>
+     <td><%= link_to("#{book.book_state}", book_update_admin_books_path(:id => book.id),
method: :post , :class => "btn btn-xs btn-default") %></td>




6、借书单实作

6.1 配置路由

设定借书单、借书、还书的路由。

config/routes.rb

* namespace :admin do
.....
# 本页代码最下方
resources :borrows        #借书单
resources :books do
member do
post :add_to_borrow   #借书
post :return_book     #还书
end
end


6.2 建立 borrows 与 borrow_items 数据表

终端执行

rails g migration create_borrows
rails g migration create_borrow_items


配置文件 db/migrate/xxxx一堆数字xxxx_borrow.rb

class CreateBorrows < ActiveRecord::Migration[5.1]
* def change
*   create_table :borrows do |t|

t.timestamps
*   end
* end
end


配置文件 db/migrate/xxxx一堆数字xxxx_borrow_items.rb

class CreateBorrowItems < ActiveRecord::Migration[5.1]
* def change
*   create_table :borrow_items do |t|
t.integer :borrow_id
t.integer :book_id
t.integer :quantity, default: 1

t.timestamps
*   end
* end
end


6.3 建立 borrow 与 borrow_item 的模型

终端执行

touch app/models/borrow.rb
touch app/models/borrow_item.rb


配置文件 app/models/borrow.rb

class Borrow < ApplicationRecord
has_many :borrow_items
has_many :books, through: :borrow_items, source: :book

def add_book_to_borrow(book)
bi = borrow_items.build
bi.book = book
bi.quantity = 1
bi.save
end
end


配置文件 app/models/borrow_item.rb

class BorrowItem < ApplicationRecord
belongs_to :book
belongs_to :borrow
end


6.4 Model 层,测试借书动作

终端进入 rails c (后台金手指)

rails c
book = Book.first
Borrow.create
borrow = Borrow.first
borrow.add_book_to_borrow(book)
borrow.borrow_items


6.5 Controller 层,配置文件

终端执行

touch app/controllers/borrows_controller.rb


配置文件 app/controllers/borrows_controller.rb

class BorrowsController < ApplicationController
end


修改文件 app/controllers/books_controller.rb

class BooksController < ApplicationController
......
* def show
* end

def add_to_borrow   #加入借书单
@book = Book.find(params[:id])
if !current_borrow.books.include?(@book)
current_borrow.add_book_to_borrow(@book)
@book.book_stock = @book.book_stock - 1
@book.save

flash[:notice] = "成功将 #{@book.title} 加入借书单"
else
flash[:waning] = "你的借书单已有本书"
end
redirect_to books_path
end

def return_book    #还书
@borrow_item = BorrowItem.find(params[:id])
if @borrow_item.destroy
@borrow_item.book.book_stock = @borrow_item.book.book_stock + 1
@borrow_item.book.save
redirect_to borrows_path
flash[:notice] = "还书成功"
else
flash[:error] = "还书失败"
end
end
*end


6.5 View 层,配置借书、还书、借书单

修改文件 app/views/common/_navbar.html.erb ,导航栏加入借书单按钮

*       <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
*           <ul class="nav navbar-nav navbar-right">
<li>
<%= link_to borrows_path do  %>
借书单 <i class="fa fa-shopping-borrow"> </i> ( <%= current_borrow.books.count %> )
<% end %>
</li>
*             <% if !current_user %>
*               <li><%= link_to("注册", new_user_path) %> </li>


终端执行

mkdir app/views/borrows
touch app/views/borrows/index.html.erb


配置文件 app/views/borrows/index.html.erb

<h1>借书单</h1>
<table class="table table-bordered table-hover">
<tr class="text-info">
<th>书名</th>
<th>简介</th>
<th>库存</th>
<th>操作</th>
</tr>
<% current_borrow.borrow_items.each do |borrow_item| %>
<tr>
<th><%= borrow_item.book.title %></th>
<th><%= borrow_item.book.text %></th>
<th><%= borrow_item.book.book_stock %></th>
<th><%= link_to '还书', return_book_book_path(:id => borrow_item.id),
:method => :post, :class => "btn btn-primary btn-lg btn-danger" %></th>
</tr>
<% end %>
</table>




修改文件 app/views/books/index.html.erb ,加入借书按钮

*     <td><%= book.book_stock %></td>
*     <td>
*         <%= link_to '显示', book_path(book) %>
<%if current_user%>
<span style="margin-left: 5px;">|</span>
<%= link_to '借阅', add_to_borrow_book_path(:id => book.id), :method => :post, :class => "btn btn-primary btn-lg btn-danger" %>
<%end%>
*     </td>


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: