每一个不曾起舞的日子都是对生命的辜负。
适合Mac OS X和任何 Linux 发行版本。在安装之前,先码几个概念性的词。
RVM 用于帮你安装Ruby环境,帮你管理多个Ruby环境,帮你管理你开发的每个Ruby应用使用机器上哪个Ruby环境。Ruby环境不仅仅是Ruby本身,还包括依赖的第三方Ruby插件。都由RVM管理。
Rails 著名开发框架。
RubyGems 是一个方便而强大的Ruby程序包管理器( package manager),类似RedHat的RPM。它将一个Ruby应用程序打包到一个gem里,作为一个安装单元。无需安装,最新的Ruby版本已经包含RubyGems了。
Gem 是封装起来的Ruby应用程序或代码库。在终端使用的gem命令,是指通过RubyGems管理Gem包。
Gemfile 定义你的应用依赖哪些第三方包,bundle根据该配置去寻找这些包。
Rake 是一门构建语言,和make类似。Rake是用Ruby写的,Rails用rake扩展来完成多种任务,如数据库初始化、更新等。
Rakefile 是由Ruby编写,Rake的命令执行就是由Rakefile文件定义。
Bundle 相当于多个RubyGems批处理运行。在配置文件gemfilel里说明你的应用依赖哪些第三方包,他自动帮你下载安装多个包,并且会下载这些包依赖的包。
安装系统需要的包
$ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
#安装brew
$ brew install libxml2 libxslt libiconv
#安装 Rails 必要的一些三方库
安装 RVM
$ gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
$ curl -sSL https://get.rvm.io | bash -s stable
$ curl -L https://raw.githubusercontent.com/wayneeseguin/rvm/master/binscripts/rvm-installer | bash -s stable
$ source ~/.rvm/scripts/rvm
#载入 RVM 环境(新开的Termal就不用了)
$ echo "ruby_url=https://cache.ruby-china.org/pub/ruby" > ~/.rvm/user/db
#修改 RVM 下载 Ruby 的源,到 Ruby China 的镜像
$ rvm -v
#检查一下是否安装正确
用 RVM 安装 Ruby
$ rvm list known
#列出已知的 Ruby 版本
$ rvm install 2.3.0
#安装一个 Ruby 版本
设置 Ruby 版本
$ rvm use 2.3.0 --default
#将指定版本的 Ruby 设置为系统默认版本
$ ruby -v
#测试
$ gem -v
$ gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/
$ gem install bundler
安装 Rails 环境
$ gem install rails
$ rails -v
安装 MySQL 数据库
$ sudo apt-get install mysql-server mysql-client libmysqlclient-dev
进入某个文件夹,新建一个项目,使用 mysql 作为数据库:rails new showcase -d mysql
,showcase就是项目的名字。
现在打开这个项目:cd showcase && rails s
。
如果遇到Could not find a JavaScript runtime
,解决方法$sudo apt-get install -y nodejs
;
如果遇到Unknown database 'showcase_development'
,解决方法$rake db:create db:migrate
。
使用The Rails Way的方式展现hello world。routes -> controller -> view,如果需要调用数据库中的数据,则在controller中调用model。
到 routes.rb 中添加一行代码
root 'page#welcome'
新建 app/controllers/page_controller.rb 文件
class PageController < ApplicationController
def welcome
end
end
新建 app/views/page/welome.html 文件
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<h1>hello world</h1>
</body>
</html>
添加about页面,到 routes.rb 中添加代码
get '/about' => 'page#about'
到page_controller.rb中添加
def about
end
新建 app/views/page/about.html 文件
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<h1>about</h1>
</body>
</html>
给welcome页面和about页面加一些内容和简单的样式吧。
首先在app/assets/images
下放一张你喜欢的大图,改名为home-banner-bg.jpg
(不改也行,不过所有的样式名字都显示不出来,233)。
在assets/javascripts
下新建文件夹/vendor
,进入文件夹后执行$wget https://raw.githubusercontent.com/danmillar/jquery-anystretch/master/jquery.anystretch.min.js
,这个插件可以使图片自适应屏幕。
进入到app/assets/javascripts/application.js
,添加//= require vendor/jquery.anystretch.min
。
这样准备工作就做完了。
修改 app/views/page/welcome.html
文件
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Meal</title>
<%= stylesheet_link_tag "application" %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
</head>
<body>
<div class="navbar clearfix">
<div class="container">
<a class="navbar-brand" href="/">
Meetup
</a>
<ul class="nav left">
<li><a href="about">About</a></li>
<li><a href="#">placeholder</a></li>
</ul>
<ul class="nav right">
<li><a href="#">login</a></li>
<li><a href="#">signup</a></li>
</ul>
</div>
</div>
<div class="home-banner" data-stretch="<%= image_url "home-banner-bg.jpg" %>"></div>
<div class="footer">
<div class="container">
出现吧!黑暗泽克斯原始型二,爆裂吧现实!粉碎吧精神! 放逐这个世界!遵从血的盟/约 我在此召唤汝,夜之女王爆裂吧现实 崩断把神经 消失吧 这个世界!愚蠢的人类啊,我再给你一次选择的机会竟敢与身为黑骑士的我提出挑战,做好觉悟了么!
</div>
</div>
<script>
$('.home-banner').anystretch();
</script>
</body>
</html>
修改 app/views/page/about.html
文件
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Meal</title>
<%= stylesheet_link_tag "application" %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
</head>
<body>
<div class="navbar clearfix">
<div class="container">
<a class="navbar-brand" href="/">
Meetup
</a>
<ul class="nav left">
<li><a href="/about">About</a></li>
<li><a href="#">placeholder</a></li>
</ul>
<ul class="nav right">
<li><a href="#">login</a></li>
<li><a href="#">signup</a></li>
</ul>
</div>
</div>
<h1>about</h1>
<div class="footer">
<div class="container">
出现吧!黑暗泽克斯原始型二,爆裂吧现实!粉碎吧精神! 放逐这个世界!遵从血的盟/约 我在此召唤汝,夜之女王爆裂吧现实 崩断把神经 消失吧 这个世界!愚蠢的人类啊,我再给你一次选择的机会竟敢与身为黑骑士的我提出挑战,做好觉悟了么!
</div>
</div>
<script>
$('.home-banner').anystretch();
</script>
</body>
</html>
在app/assets/stylesheets
下新建index.css
body {
font-family: sans-serif;
margin: 0;
font-size: 14px;
color: #666;
}
.container {
width: 1170px;
margin: 0 auto;
}
*, *:before, *:after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.clearfix:before,
.clearfix:after {
content: " ";
display: table;
}
.clearfix:after {
clear: both;
}
.clearfix {
*zoom: 1;
}
ul {
list-style: none;
padding: 0;
margin: 0;
}
.navbar {
background: #222;
position: relative;
z-index: 1000;
}
.navbar a {
color: #fff;
}
.navbar a:hover {
color: #c0865e;
}
.navbar-brand {
float: left;
padding-left: 0;
line-height: 80px;
font-size: 40px;
}
.nav.left {
float: left;
margin-left: 40px;
font-size: 15px;
}
.nav.right {
float: right;
}
.nav li {
float: left;
}
.nav li a {
display: block;
font-size: 1.1em;
line-height: 40px;
padding: 5px 10px;
margin: 15px 10px;
}
.nav li a:hover {
color: #000;
background: #fff;
}
a {
text-decoration: none;
color: #c0865e;
}
a:hover {
color: #845534;
}
.footer {
border-top: 1px solid #c5c5c5;
min-height: 200px;
padding-top: 3em;
padding-bottom: 3em;
background: #f8f5f0;
}
.home-banner {
padding-top: 80px;
height: 1000px;
}
.index .navbar {
background: transparent;
}
welcome.html.erb和about.html.erb中有很多相同的代码,可以把相同的部分提出来,放在application.html.erb中。移动后的三个文件分别为:
application.html.erb
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Meal</title>
<%= stylesheet_link_tag "application" %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
</head>
<body>
<div class="navbar clearfix">
<div class="container">
<a class="navbar-brand" href="/">
Meetup
</a>
<ul class="nav left">
<li><a href="about">About</a></li>
<li><a href="#">placeholder</a></li>
</ul>
<ul class="nav right">
<li><a href="#">login</a></li>
<li><a href="#">signup</a></li>
</ul>
</div>
</div>
<%= yield %>
<div class="footer">
<div class="container">
出现吧!黑暗泽克斯原始型二,爆裂吧现实!粉碎吧精神! 放逐这个世界!遵从血的盟/约 我在此召唤汝,夜之女王爆裂吧现实 崩断把神经 消失吧 这个世界!愚蠢的人类啊,我再给你一次选择的机会竟敢与身为黑骑士的我提出挑战,做好觉悟了么!
</div>
</div>
</body>
</html>
about.html.erb
<h1>about</h1>
welcome.html.erb
<div class="home-banner" data-stretch="<%= image_url "home-banner-bg.jpg" %>"></div>
<script>
$('.home-banner').anystretch();
</script>
随着html页面结构的调整,layout文件的引入,css文件也需要做相应的修改。新建一个目录sections
里面专门放各个页面具体区块的css。把 index.css 移动进去,拆成 layout.css.scss 和 welcome.css.scss 。分别负责 application.html.erb 和 welcome.html.erb 页面的样式。再新建shared
,将common.css.scss放入。
cd app/assets/stylesheets
mkdir sections
mkdir shared
在welcome页面添加一个可以发布聚餐活动的按钮。在 welcome.html.erb 中, class=”home-banner” 的 div 之内添加
<div class="banner-inner container clearfix">
<h1>约饭!</h1>
<p class="subheading">说说你想吃啥呀</p>
<div class="home-banner-links">
<%= link_to "发布新聚餐", "#", class: "banner-btn btn" %>
</div>
</div>
在对应的 css 文件中添加样式
.home-banner {
margin-top: -80px;
padding-top: 80px;
.banner-inner {
height: 1000px;
position: relative;
h1 {
font-family: "museo-sans-condensed";
font-size: 88px;
font-weight: 400;
letter-spacing: -2px;
border-radius: 5px;
margin-top: 60px;
line-height: 1.2;
max-width: 50%;
text-transform: capitalize;
color: #fff;
text-shadow: 0 1px 81px rgba(0, 0, 0, 0.3);
}
.subheading {
color: #fff;
font-weight: 300;
font-size: 1.3em;
margin-top: 26px;
background: rgba(0, 0, 0, 0.5);
display: block;
width: 45%;
padding: 5px 10px;
line-height: 30px;
text-align: center;
}
}
}
.home-banner-links {
position: absolute;
right: 160px;
top: 194px;
.banner-btn {
padding: 15px 15px;
font-size: 1.2em;
font-weight: 300;
font-family: "museo-sans-condensed";
border-radius: 5px;
color: #fff;
background: rgba(0, 0, 0, 0.1);
margin-left: 8px;
border: 2px solid;
position: relative;
top: 200px;
left: -700px;
&:hover {
border: 1px solid rgba(0, 0, 0, 0.2);
}
}
}
在 welcome.html.erb 中添加聚餐列表
<div class="issue-list-header">
<div class="container clearfix">
<h1 class="issue-list-heading">聚餐列表</h1>
</div>
</div>
添加聚餐列表的样式
.issue-list-header {
border-bottom: 1px solid #ddd;
padding-bottom: 30px;
padding-top: 30px;
margin-top: 0;
margin-bottom: 35px;
background: #7EB6AD;
color: #fff;
.issue-list-heading {
font-size: 2em;
font-weight: normal;
}
}
在 welcome.html.erb 中添加一个活动
<div class="container clearfix">
<div class="issue-list">
<article class="issue clearfix">
<div class="avatar">
<a href="#">
<img src=http://img1.3lian.com/gif/more/11/201301/e47524afabdc211536e595743be46e92.jpg alt="">
</a> </div>
<div class="body">
<h5 class="title">
<a href="#">test</a>
</h5>
<a class="read-more" href="#">read</a>
<span class="meta-data">
<a href="#">avatar</a>
</span>
</div>
<div class="issue-comment-count">
<a href="#">
4
</a>
</div>
</article>
</div>
</div>
对应的样式
.issue-list {
background: #fff;
clear: both;
padding: 0 2em;
margin-bottom: 1em;
border: 1px solid #ddd;
article {
border-bottom: 1px solid #e3e3e3;
position: relative;
margin-top: 0;
padding: 1em 0;
.body {
margin-right: 2em;
width: 70%;
float: left;
.read-more{
background-color: #316A72;
color: #fff;
font-size: 13px;
border-radius: 4px;
letter-spacing: -0.3px;
display: inline-block;
line-height: 1.7;
font-weight: 100;
padding: 0 6px;
}
.meta-data {
color: #999;
font-size: 12px;
}
h5 {
font-size: 22px;
line-height: 35px;
font-weight: normal;
margin: 0 0 5px;
a {
color: #555;
&:hover {
color: black;
}
}
}
}
.issue-comment-count {
float: right;
margin-top: 15px;
a {
font-size: 45px;
}
}
.avatar {
width: 75px;
float: left;
img {
width: 65px;
padding: 4px;
border: 1px solid #ddd;
}
}
}
}
修改controller,使数据可以灵活一点地显示。page_controller.rb 中添加
def welcome
@issues = [ { title: "test1", comments: "4" }, { title: "test2", comments: "5" } ]
end
修改 welcome.html.erb 将 issue-list 中的内容抽出来,新建一个文件 _issue_list.html.erb
<div class="issue-list">
<% issues.each do |i| %>
<article class="issue clearfix">
<div class="avatar">
<a href="#">
<img src=http://img1.3lian.com/gif/more/11/201301/e47524afabdc211536e595743be46e92.jpg alt="">
</a></div>
<div class="body">
<h5 class="title">
<%= link_to i[:title], "#" %>
</h5>
<a class="read-more" href="#">read</a>
<span class="meta-data">
<a href="#">avatar</a>
</span>
</div>
<div class="issue-comment-count">
<%= link_to i[:comments], "#" %>
</div>
</article>
<% end %>
</div>
welcome.html.erb 中改为
<%= render partial: 'issue_list', locals: { issues: @issues } %>
配置文件 config/database.yml 里面写明了要使用哪个数据库。建立数据表结构
rails g migration CreateIssues
在 db/migrate 会自动生成一个文件,文件名前面是时间戳,里面可以添加需要的字段。
class CreateIssues < ActiveRecord::Migration
def change
create_table :issues do |t|
t.string :title
t.timestamps
end
end
end
运行 rake db:migrate
,来把修改内容真正写进 mysql 数据库。会生成 db/schema.rb 文件,该文件显示了当前数据库的表结构。
新建 issue.rb 的 model 文件放在 app/models 下面。
class Issue < ActiveRecord::Base
end
这里的 class 命名是很关键的,如果数据库中的表名是 issues 那这里的 class 名就必须是 Issue,也就是首字母大写,同时变成单数。因为 Rails 可以建立自动的 class 到 table 的映射关系。
执行 rails console
或 rails c
对表进行操作。
Issue.create(title: "test111")
Issue.create(title: "test111222")
Issue.all
修改 controller 中加载数据的方法
def welcome
@issues = Issue.all
end
到 _issue_list.html.erb 中,由于数据表中没有添加 commit 个数,所以要将 commit 个数改为固定值
<div class="issue-comment-count">
<%= link_to i[:comments], "11" %>
</div>
对 issue 进行 Create Read Update Delete 操作。参考网站:http://railsforzombies.org/levels/1
用 rails generator 来自动生成 controller ,为了避免生成太多用不到的文件,到 application.rb 中添加
config.generators do |g|
g.assets false
g.helper false
g.test_framework false
end
然后执行 $rails g controller issues show
,在生成的内容中 routes.rb 中的语句删掉。
修改 issues_controller.rb 中的内容,根据 id 从数据库中读取数据。
def show
@issue = Issue.find(params[:id])
end
在新生成的 show.html.erb 中添加
<div class="issue-heading">
<div class="container">
<%= @issue.title %>
</div>
</div>
<div class="container">
<div class="replies">
<article class="reply clearfix">
<div class="avatar">
<img src=http://img1.3lian.com/gif/more/11/201301/e47524afabdc211536e595743be46e92.jpg alt="" class="image-circle">
</div>
<div class="body">
<div class="heading">
<h5 class="name"><a href="#">avatar</a></h5>
</div>
<%= @issue.content %>
</div>
</article>
</div>
</div>
在 sections 中添加相应的样式 issue_show.css.scss
.issue-heading {
border-bottom: 1px solid #ddd;
padding-bottom: 30px;
padding-top: 30px;
margin-top: 0;
margin-bottom: 35px;
background: #7EB6AD;
color: #fff;
font-size: 2em;
}
.reply {
position: relative;
overflow: hidden;
margin-bottom: 30px;
width: 91%;
.heading {
margin-bottom: 5px;
.name {
font-size: 18px;
display: inline;
font-weight: normal;
}
}
.body {
padding: 15px;
border-radius: 5px;
position: relative;
overflow: visible;
float: left;
width: 87%;
border: 1px solid #ddd;
line-height: 26px;
&::before {
content: "";
display: block;
position: absolute;
top: 21px;
left: -6px;
width: 10px;
height: 10px;
background: #fff;
border-left: 1px solid #cad5e0;
border-top: 1px solid #cad5e0;
-moz-transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
}
}
.avatar {
float: left;
margin-right: 29px;
position: relative;
overflow: visible;
text-align: center;
.image-circle {
width: 75px;
border-radius: 50%;
}
}
}
在 issues/show.html.erb 中添加一个删除的链接。
<%= link_to 'Destroy', "/issues/#{@issue.id}", method: :delete, data: { confirm: 'Are you sure?' }, class: "btn btn-primary" %>
在 routes.rb 中添加相应的路由。
delete 'issues/:id' => 'issues#destroy'
到 issues_controller.rb 添加
def destroy
issue = Issue.find(params[:id])
issue.destroy
redirect_to :root
end
到 app/assets/stylesheets/shared/common.css 添加一些按钮样式。
.btn-primary {
color: white;
background: #c0865e;
border-color: #b9784c;
&:hover {
background-color: #b9784c;
border-color: #845534;
}
}
.btn {
display: inline-block;
padding: 6px 12px;
margin-bottom: 0;
font-size: 14px;
font-weight: normal;
line-height: 1.428571429;
text-align: center;
vertical-align: middle;
cursor: pointer;
border: 1px solid transparent;
border-radius: 4px;
white-space: nowrap;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
}
如果删除失败,则是在操纵数据库过程中触发了rails的保护机制,只需要在 application.html.erb 中添加一句 <%= csrf_meta_tags %>
即可。
想要创建新的聚餐信息,将 welcome.html.erb 的发布按钮的信息改为 <%= link_to "发布新聚餐", "/issues/new", class: "banner-btn btn" %>
在 routes.rb 中添加新的路由
get 'issues' => 'issues#index', :as => 'issues'
get '/issues/new' => "issues#new"
post 'issues' => 'issues#create'
在 issues_controller.rb 中添加
def new
@issue = Issue.new
end
def create
Issue.create(issue_params)
redirect_to :root
end
private
def issue_params
params.require(:issue).permit(:title, :content)
end
Strong Parameters 是 Rails 为了防止坏人通过表单提交攻击网站,采用的自我保护机制。如果不加说明任何人都可以在 params[:issue] 中加入任何参数,比如 admin: true 这样就可以给他自己管理员权限了,所以就用这种方式进行修改。使用的方式就是 https://github.com/rails/strong_parameters 。
创建 app/view/issues/new.html.erb 新页面
<div class="new-issue-form-container clearfix">
<div class="new-issue-form clearfix">
<%= form_for @issue do |f| %>
<dl class="form">
<dt><%= f.label :title %></dt>
<dd><%= f.text_field :title %></dd>
</dl>
<dl class="form">
<dt><%= f.label :content %></dt>
<dd><%= f.text_area :content %></dd>
</dl>
<p><%= f.submit "发布新活动", :class => "submit-issue-button btn btn-primary" %></p>
<% end %>
</div>
</div>
在 common.css.sass 中添加关于 form 的样式
form {
input {
font-size: 21px;
width: 100%;
padding: 10px 12px;
color: #555;
}
textarea {
height: 180px;
font-size: 21px;
width: 100%;
padding: 10px 12px;
color: #555;
}
label {
display: inline-block;
margin-bottom: 5px;
}
dd {
margin: 0;
}
}
创建 sections/issue_new.css.scss 添加特有样式
.new-issue-form-container {
width: 800px;
background: white;
margin: 30px auto;
.new-issue-form {
width: 600px;
margin: 10px auto;
}
}
.submit-issue-button {
height: 50px;
width: 100%;
}
到 views/issues/show.html.erb 添加一个 edit 按钮
<%= link_to 'edit', edit_issue_path(@issue), class: "btn btn-primary" %>
到 routes.rb 中,所有的指向 issues_controller.rb 的语句都可以删除,而用一行代替。具体参考文档 http://guides.rubyonrails.org/routing.html 。
resources :issues
issues_controller.rb 中添加
def edit
@issue = Issue.find(params[:id])
end
创建 views/issues/edit.html.erb 复制 views/issues/new.html.erb 即可
到 issues_controller.rb 中来添加 update 功能
def update
i = Issue.find(params[:id])
i.update_attributes(issue_params)
redirect_to :root
end
新建一个 views/issues/_form.html.erb,把 issues/new.html.erb 和 issues/edit.html.erb 共用。
<div class="new-issue-form-container clearfix">
<div class="new-issue-form clearfix">
<%= form_for issue do |f| %>
<dl class="form">
<dt><%= f.label :title %></dt>
<dd><%= f.text_field :title %></dd>
</dl>
<dl class="form">
<dt><%= f.label :content %></dt>
<dd><%= f.text_area :content %></dd>
</dl>
<p><%= f.submit :class => "submit-issue-button btn btn-primary" %></p>
<% end %>
</div>
</div>
把 views/issues/edit.html.erb 和 views/issues/new.html.erb 改为
<%= render partial: 'form', locals: {issue: @issue} %>
活动与留言属于一对多的关系,先来创建留言的 model 和 migration 文件。
rails g model comment content:text username:string email:string issue_id:integer
到 views/issues/show.html.erb 中添加
<%= render partial: 'shared/comment_box', locals: {issue: @issue} %>
创建 views/shared/_comment_box.html.erb
<article class="reply clearfix">
<div class="avatar">
<%= link_to "#" do %>
<%= image_tag "default_avatar.png", class: "image-circle" %>
<% end %>
</div>
<div class="body">
<%= form_tag("/issues/#{issue.id}/comments", method: :post) do %>
<%= label_tag :username, "用户名" %>
<%= text_field_tag(:username) %>
<%= label_tag :email, "邮箱" %>
<%= text_field_tag(:email) %>
<%= text_area_tag(:content) %>
<%= submit_tag '提交评论', class: 'btn btn-primary btn-submit' %>
<% end %>
</div>
</article>
到 routes.rb 添加
post '/issues/:issue_id/comments' => "comments#create"
创建 app/controllers/comments_controller.rb
rails g controller comments
def create
c = Comment.new
c.username = params[:username]
c.email = params[:email]
c.content = params[:content]
c.issue_id = params[:issue_id]
c.save
issue = Issue.find(params[:issue_id])
redirect_to issue
end
将 comment 显示出来,到 views/issues/show.html.erb 中添加
<%= render partial: 'shared/comment_list', locals: {comments: @comments} %>
创建 shared/_comment_list.html.erb
<% comments.each do |c| %>
<div class="reply clearfix">
<div class="avatar">
<%= link_to '#' do %>
<%= image_tag 'default_avatar.png', class: 'image-circle' %>
<% end %>
</div>
<div class="body">
<div class="heading">
<h5 class="name"><%= link_to c.username, "#" %></h5>
<span class="datetime">
<%= time_ago_in_words c.created_at %>
</span>
</div>
<%= c.content %>
</div>
</div>
<% end %>
在 issues_controller.rb 的 show 方法中添加
def show
@issue = Issue.find(params[:id])
@comments = @issue.comments
end
建立一对多的关系,第一步,到 issue.rb 文件中添加:has_many :comments
;第二步,到 comment.rb 中添加:belongs_to :issue
修改评论个数,到 views/page/_issue_list.html.erb 中
- <%= link_to '5', "#" %>
+ <%= link_to i.comments.count, i %>
修改用户头像,在 comment.rb 添加
def user_avatar
gravatar_id = Digest::MD5.hexdigest(self.email.downcase)
"http://gravatar.com/avatar/#{gravatar_id}.png?s=512&d=retro"
end
到 views/shared/_comment_list.html.erb 修改使用头像的地方 <%= image_tag c.user_avatar, class: 'image-circle' %>
创建 users 表,用户密码一般不明文存储,而是经过加密后,存放在 password_digest 这个字段中。
rails g controller users signup
rails g model user name:string email:string password_digest:string
rake db:migrate
使用 has_secure_password 首先要在 Gemfile 里面添加 Bcrypt,其次在表里有 password_digest 这个字段,然后到 user.rb 中,添加 has_secure_password
添加 /signup 页面,到 application.html.erb 中添加指向 /signup 的链接:<li><a href="/signup">signup</a></li>
,然后到 route.rb 中添加:get "signup" => "users#signup", :as => "signup"
、resources :users
到 users_controller.rb 中
def signup
@user = User.new
end
def create
user = User.new(user_params)
user.save
redirect_to :root
end
private
def user_params
params.require(:user).permit!
end
在相应的 app/views/users/signup.html.erb 添加
<div class="signup-form-container clearfix">
<div class="signup-form">
<%= form_for @user do |f| %>
<dl class="form">
<dt><%= f.label :name, "用户名" %></dt>
<dd><%= f.text_field :name %></dd>
</dl>
<dl class="form">
<dt><%= f.label :email %></dt>
<dd><%= f.text_field :email %></dd>
</dl>
<dl class="form">
<dt><%= f.label :password, "密码" %></dt>
<dd><%= f.password_field :password %></dd>
</dl>
<dl class="form">
<dt><%= f.label :password_confirmation, "请再输入一次" %></dt>
<dd><%= f.password_field :password_confirmation %></dd>
</dl>
<p><%= f.submit "注册", :class => "signup-button btn btn-primary" %></p>
<% end %>
</div>
</div>
添加对应的样式 app/assets/stylesheets/sections/users.css.scss
.signup-form-container, .login-form-container{
width: 670px;
margin: 50px auto;
border:1px solid #ddd;
padding: 2em;
.signup-form, .login-form {
width: 100%;
}
.signup-button, .login-button {
padding: 13px;
margin-top: 15px;
width: 100%;
}
}
用这个账户来登陆,在 application.html.erb 中来添加 <%= link_to "login", login_path %>
route.rb 中添加get "login" => "users#login", :as => "login"
users_controller.rb 中添加
def login
end
app/views/users/login.html.erb 中添加
<div class="login-form-container clearfix">
<div class="login-form">
<%= form_tag "/create_login_session" do %>
<dl class="form">
<dt>
<%= label_tag "用户名" %>
</dt>
<dd>
<%= text_field_tag :name, params[:name] %>
</dd>
</dl>
<dl class="form">
<dt>
<%= label_tag "密码" %>
</dt>
<dd>
<%= password_field_tag :password, params[:password] %>
</dd>
</dl>
<p> <%= submit_tag "登录", :class => "login-button btn btn-primary" %> </p>
<div class="need-signup">
<%= link_to "没有账号?注册一个吧", signup_path %>
</div>
<% end %>
</div>
</div>
表单中把数据提交到 “/create_login_session” 在 route.rb 中添加 post "create_login_session" => "users#create_login_session"
在 users_controller.rb 中添加
def create_login_session
user = User.find_by_name(params[:name])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to :root
else
redirect_to :login
end
end
到 application_controller.rb 中添加
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
application.html.erb 中添加
<% if current_user %>
<li><%= link_to current_user.name, "#" %></li>
<li><%= link_to "logout", "#" %></li>
<% else %>
<li><%= link_to "login", login_path %></li>
<li><%= link_to "signup", signup_path %></li>
<% end %>
退出登录,在 application.html.erb 中 logout 对应的这一行改为:<li><%= link_to "logout", logout_path, method: "delete" %></li>
route.rb 中添加:delete "logout" => "users#logout", :as => "logout"
在 users_controller.rb 中修改
def logout
session[:user_id] = nil
redirect_to :root
end
此时就可以登录、退出已经注册了,但是测试时需要重新开一个窗口。
记住密码的功能。为了保持登陆状态,引入了 session 方法,但是 session 中存储的数据毕竟是临时性的,虽然目前最新的浏览器有各种保持临时数据的缓存方式,但是基本上可以认为如果网站关闭了或是关机重启了,session 中的数据也就丢失了。
添加 checkbox 的代码,到 login.html.erb 中的提交按钮上方,添加
<dl class="form remember-me">
<%= check_box_tag :remember_me, 1, params[:remember_me] %>
<%= label_tag :remember_me %>
</dl>
user.css.scss 添加样式
.remember-me {
* {
width: auto;
}
#remember_me {
margin-left: 0;
}
}
为每一个用户生成一串随机数,用来代表 token。
rails g migration AddAuthTokenToUsers auth_token:string
rake db:migrate
user.rb 中,添加
before_create { generate_token(:auth_token) }
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
users_controller.rb 中的 create_login_session 方法修改为
- session[:user_id] = user.id
+ if params[:remember_me]
+ cookies.permanent[:auth_token] = user.auth_token
+ else
+ cookies[:auth_token] = user.auth_token
+ end
退出登录的代码 logout 修改为
- session[:user_id] = nil
+ cookies.delete(:auth_token)
application_controller.rb 中 current_user 改为
def current_user
@current_user ||= User.find_by_auth_token!(cookies[:auth_token]) if cookies[:auth_token]
end
需要注册结束后直接跳转,则在 users_controller.rb 的 create 方法中,user.save 语句之后添加 cookies[:auth_token] = user.auth_token
form validation 表单验证。当用户填写注册表单的时候如果填写的内容有问题,程序能够检查并且报错,避免直接把有问题的内容 直接存入数据库。
user.rb 中添加
validates :name, :email, presence: true
validates :name, :email, uniqueness: { case_sensitive: false }
users_controller.rb 中的 create 方法需要调整,要用实例变量,同时最后不能用 redirect_to 而要用 render
- user = User.new(user_params)
- user.save
- cookies[:auth_token] = user.auth_token
- redirect_to :root
+ @user = User.new(user_params)
+ if @user.save
+ cookies[:auth_token] = @user.auth_token
+ redirect_to :root
+ else
+ render :signup
+ end
在 signup.html.erb 中适当显示报错信息了
<div class="signup-form-container clearfix">
<div class="signup-form">
<%= form_for @user do |f| %>
<dl class="form">
<dt><%= f.label :name, "用户名" %></dt>
<dd><%= f.text_field :name %></dd>
<% if @user.errors[:name].any? %>
<dd class="error"><%= @user.errors[:name][0] %></dd>
<% end %>
</dl>
<dl class="form">
<dt><%= f.label :email %></dt>
<dd><%= f.text_field :email %></dd>
<% if @user.errors[:email].any? %>
<dd class="error"><%= @user.errors[:email][0] %></dd>
<% end %>
</dl>
<dl class="form">
<dt><%= f.label :password, "密码" %></dt>
<dd><%= f.password_field :password %></dd>
<% if @user.errors[:password].any? %>
<dd class="error"><%= @user.errors[:password][0] %></dd>
<% end %>
</dl>
<dl class="form">
<dt><%= f.label :password_confirmation, "请再输入一次" %></dt>
<dd><%= f.password_field :password_confirmation %></dd>
<% if @user.errors[:password_confirmation].any? %>
<dd class="error"><%= @user.errors[:password_confirmation][0] %></dd>
<% end %>
</dl>
<p><%= f.submit "注册", :class => "signup-button btn btn-primary" %></p>
<% end %>
</div>
</div>
common.css.scss 中 form 里面添加
.error {
margin: 5px 0 9px 0;
color: #DB8A14;
}
到 application.rb 中添加 config.i18n.default_locale = 'zh-CN'
添加 config/locals/zh-CN.yml 文件,注意缩进关系,使用两个空格做为一个缩进级别
zh-CN:
navbar:
about: 关于
signup: 注册
logout: 退出
login: 登录
到 application.html.erb 中
<ul class="nav left">
<li><%= link_to t("navbar.about"), "/about" %></li>
</ul>
<ul class="nav right">
<% if current_user %>
<li><%= link_to current_user.name, "#" %></li>
<li><%= link_to t("navbar.logout"), logout_path, method: "delete" %></li>
<% else %>
<li><%= link_to t("navbar.login"), login_path %></li>
<li><%= link_to t("navbar.signup"), signup_path %></li>
<% end %>
</ul>
登录后才能创建新活动,点击首页的发布新活动按钮,如果用户没有登录,无法创建,需要的代码调整是在 issues_controller.rb 中, new 改成
def new
if not current_user
redirect_to :root
return
else
@issue = Issue.new
end
end
隐藏评论框。退出登录条件下再来访问一个活动的展示页面就会报错。因为在评论框的代码中用到了 current_user 。解决方法是到 issues/show.html.erb 中
+ <% if current_user %>
<%= render partial: 'shared/comment_box', locals: {issue: @issue} %>
+ <% else %>
+ <%= link_to "登录发评论", login_path %>
+ <% end %>