[Ruby]《Ruby on Rails Tutorial》的搬运工之一

ruby-on-rails-tutorials.jpg

背景:

  1. 最近比较闲,想学习ruby on rails
  2. 于是找到了https://www.railstutorial.org 上的首推教程《Ruby on Rails Tutorial》
    屏幕快照 2016-05-29 上午11.04.20.png

    这本书第一章和第二章讲了2个基本demo,实在没啥意思,姑且略过. 从第三章开始到第十二章是从0到1实现了一个类似Twitter的简单社交网站(首页,登录注册,发布推文,关注等功能). 怎么样是不是很棒?
    但是这个本书实在讲得过于详细,对于我这种本身没有那么多时间(也没那么多耐心😢)去一点一点看下来的童鞋,看着实在太着急了,于是准备快速整理下(把里面的干货和代码提取出来),方便大家可以分分钟coding出这个demo出来.
    当然真正学习还是要看原教程,我这个只是"扒皮版本".

<br />

原文链接

RUBY ON RAILS TUTORIAL
https://www.railstutorial.org/book/static_pages

他们的github:

railstutorial/sample_app_rails_4
https://github.com/railstutorial/sample_app_rails_4

<br />

ruby学习框架图

ruby on rails is hard?

开始


前两章略掉...
从第三章开始:

3. Mostly static pages

3.1 Sample app setup

$ rails  new sample_app
$ cd sample_app/

生成我们的APP,ruby会生成如下文件


生成的APP文件

3.2 Static pages

3.2.1 Generated static pages

生成StaticPages 这个controller

$ rails generate controller StaticPages home help

3.2.2 Custom static pages

画UI, 刚才生成了home和help2个页面,默认页面啥也没有,我们来填东西:

a). Custom HTML for the Home page

用vim 或者自己熟悉的编辑器,修改home.html.erb和help.html.erb 2个文件

vim app/views/static_pages/home.html.erb 
<h1>Sample App</h1>
<p> This is the home page for the 
    <a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a> 
    sample application.
</p>

b). Custom HTML for the Help page

vim app/views/static_pages/help.html.erb
<h1>Help</h1>
<p> Get help on the Ruby on Rails Tutorial at the 
<a href="http://www.railstutorial.org/#help">Rails Tutorial help section</a>. 
To get help on this sample app, see the <a href="http://www.railstutorial.org/book"><em>Ruby on Rails Tutorial</em> book</a>.
</p>

3.3 Getting started with testing

执行测试,这本书的教材很重视test,这也是国内开发人员很不重视的地方,想着都留给测试好了,其实开发测试做得好了,代码才会漂亮,质量高. 如果全靠测试,那代码全是东一坨西一坨,全是补丁.
rails 中执行 测试可以在控制台中进行,当然,最简单的步骤是

rake test

下面的我这边执行后的一次结果,可以看到,测试结果提示,"schema.rb doesn't exist yet",让我执行"Run rake db:migrate to create it"

屏幕快照 2016-05-29 下午1.18.12.png

另,原文中教程叫你如何测试一个about界面,这里不详述了,有兴趣的点链接:
Our first step is to write a failing test for the About page...

这里只说下如何搭建about页面
a). 建立路由(vim config/routes.rb)

 vim config/routes.rb
//  Adding the about route.
Rails.application.routes.draw do 
  get 'static_pages/home' 
  get 'static_pages/help' 
  get 'static_pages/about' 
. . .
end

b). controller中增加about action

class StaticPagesController < ApplicationController 
  def home 
  end 
  def help 
  end 
  def about 
  end
end

c). 新建about.html.erb

touch 创建,vim编辑
<h1>About</h1>
<p> 
The <a href="http://www.railstutorial.org/"><em>Ruby on Rails Tutorial</em></a> 
is a 
<a href="http://www.railstutorial.org/book">book</a> 
and 
<a href="http://screencasts.railstutorial.org/">screencast series</a> 
to teach web development with 
<a href="http://rubyonrails.org/">Ruby on Rails</a>. 
This is the sample application for the tutorial.
</p>

3.4 Slightly dynamic pages

3.4.1 Testing titles (Red)

3.4.2 Adding page titles (Green)

这里文中告诉你,ruby真正来了,使用ruby的标志是使用<% ... %>,这里对于初学者有个点注意下:

<% %>: 只是执行<>中的代码
<%= %>:代码还是会执行,同时会在界面显示执行结果

然后我们重新修改下我们的home,help,about界面:

home

help

about

3.4.3 Layouts and embedded Ruby (Refactor)

然后发现每个页面都有<title></title>然后我们代码重新改一下,统一放到app/views/layouts/application.html.erb里面:


application.html.erb

另外home,help,about也对应改一下,改成类似

<h1>Help</h1>
<h1>About</h1>

3.4.4 Setting the root route

编辑config/routes.rb

Rails.application.routes.draw do 
  root 'static_pages#home' 
  get 'static_pages/help' 
  get 'static_pages/about'
end

3.7 Advanced testing setup

3.7.2 Backtrace silencer

config/initializers/backtrace_silencers.rb 中的一行代码解注


屏幕快照 2016-05-29 下午2.15.44.png

<br />

4. Rails-flavored Ruby


4.1 Motivation

前面有provide方法提供title,这里把title再细化,针对不同的页面有个通用的处理title的方法:

vim app/helpers/application_helper.rb

module ApplicationHelper

  # Returns the full title on a per-page basis.
  def full_title(page_title = '')
    base_title = "Ruby on Rails Tutorial Sample App"
    if page_title.empty?
      base_title
    else
      page_title + " | " + base_title
    end
  end
end

这样

<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>

可以简化为

<title><%= full_title(yield:title)></title>

4.2 Strings and methods

4.2.1 Comments

ruby中的注释用 #, ruby的print用puts,当然也可以直接用print,但是print需要自己打印一个"\n"

>> puts "foo" # put string
foo
=> nil

>> print "foo" # print string (same as puts, but without the newline)
foo=> nil

>> print "foo\n" # Same as puts "foo"
foo
=> nil

<br />

5. Filling in the layout


本章开始做个欢迎页面


屏幕快照 2016-05-29 下午2.43.29.png

5.1 Adding some structure

5.1.1 Site navigation
application.html.erb中增加home,help,login的菜单栏

vim app/views/layouts/application.html.erb
屏幕快照 2016-05-29 下午2.53.02.png

home 页面增加注册按钮和图片

vim app/views/static_pages/home.html.erb
屏幕快照 2016-05-29 下午2.51.48.png

5.1.2 Bootstrap and custom CSS

安装bootstrap-sass库:

polen:
说到这个库,一把辛酸泪,从github上搜到了这本教程对应的demo代码(https://github.com/railstutorial/sample_app_rails_4)
结果下载下来各种运行fail,逼得我ruby和bundle都重新安装了好久
因为这个代码里rails的版本太低,里面Gemfile对应的很多库都是低版本的,我们前面使用rails new project_name的时候,默认生成的Gemfile里面库的版本都是很新的
所以你要使用这段github代码的话,运行之前,先把gemfile替换为你本地的,然后在里面加入如下几条即可

gem 'bootstrap-sass',       '2.2.2.0'
gem 'bcrypt',               '3.1.7'
gem 'will_paginate',        '3.0.5'

>```
bootstrap-sass 这个3.0版本和2.0都可以,但是二者是不兼容的,命名规则一个是grayLight,一个是gray-light, 如果你运行的时候报错, 你对应修改下就好

言归正传,回到项目继续:

vim Gemfile

![屏幕快照 2016-05-29 下午3.09.30.png](http://upload-images.jianshu.io/upload_images/173709-d7c3cf72011db30e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

bundle install 或者bundle update

创建custom.css.scss布局文件

touch app/assets/stylesheets/custom.css.scss
vim app/assets/stylesheets/custom.css.scss

@import "bootstrap-sprockets";
@import "bootstrap";

/* universal */
body {
padding-top: 60px;
}

section {
overflow: auto;
}

textarea {
resize: vertical;
}

.center {
text-align: center;
}

.center h1 {
margin-bottom: 10px;
}

/* typography */
h1, h2, h3, h4, h5, h6 {
line-height: 1;
}

h1 {
font-size: 3em;
letter-spacing: -2px;
margin-bottom: 30px;
text-align: center;
}

h2 {
font-size: 1.2em;
letter-spacing: -1px;
margin-bottom: 30px;
text-align: center;
font-weight: normal;
color: #777;
}

p {
font-size: 1.1em;
line-height: 1.7em;
}

/* header */

logo {

float: left;
margin-right: 10px;
font-size: 1.7em;
color: #fff;
text-transform: uppercase;
letter-spacing: -1px;
padding-top: 9px;
font-weight: bold;
}

logo:hover {

color: #fff;
text-decoration: none;
}

CSS布局了,大家都懂.

###5.1.3 Partials
The site layout with partials for the stylesheets and header.
ruby的局部样板Partials,是为了实现页面复用,我们通过`<%= render 'layouts/header' %>`来实现调用


首先对应新建_shim.html.erb,_header.html.erb 和_footer.html.erb

touch app/views/layouts/_shim.html.erb
touch app/views/layouts/_header.html.erb
touch app/views/layouts/_footer.html.erb

![屏幕快照 2016-05-29 下午4.12.29.png](http://upload-images.jianshu.io/upload_images/173709-b1a1d85ead7b2819.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![屏幕快照 2016-05-29 下午4.12.36.png](http://upload-images.jianshu.io/upload_images/173709-e6da93b31555ae1d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![屏幕快照 2016-05-29 下午4.12.43.png](http://upload-images.jianshu.io/upload_images/173709-aee29046d086e216.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

然后customer.css 加入footer的布局

//... 前面的省略

/* footer */
footer {
margin-top: 45px;
padding-top: 5px;
border-top: 1px solid #eaeaea;
color: #777;
}

footer a {
color: #555;
}

footer a:hover {
color: #222;
}

footer small {
float: left;
}

footer ul {
float: right;
list-style: none;
}

footer ul li {
float: left;
margin-left: 15px;
}


然后修改application.html.erb:

vim app/views/layouts/application.html.erb

<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= stylesheet_link_tag "application", media: "all",
"data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= csrf_meta_tags %>
<%= render 'layouts/shim' %>
</head>
<body>
<%= render 'layouts/header' %>
<div class="container">
<%= yield %>
<%= render 'layouts/footer' %>
</div>
</body>
</html>



##5.3 Layout links
###5.3.1 Contact page
参照之前的方法,加入contact:
** route("入口") + controller加action("动作") + 加入contact.html("UI") 
这个3个地方**
懂得童鞋,自己默默去加,不懂的看下面的截图:

![屏幕快照 2016-05-29 下午4.33.35.png](http://upload-images.jianshu.io/upload_images/173709-04451bdd93ffc6b1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

###5.3.2 Rails routes
修改route,增加root路由,同时该写下之前的路由代码:

get 'static_pages/help'
⬇️
get 'help' => 'static_pages#help'

所以我们的config/routes.rb 变成了:

Rails.application.routes.draw do

root 'static_pages#home'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'

end


###5.3.3 Using named routes

<%= link_to "About", '#' %>
⬇️
<%= link_to "About", about_path %>

修改我们的header和footer的html文件:

vim app/views/layouts/_header.html.erb
...
vim app/views/layouts/_footer.html.erb
...

结果如下:
![header](http://upload-images.jianshu.io/upload_images/173709-0c592c4961826cd2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

![footer](http://upload-images.jianshu.io/upload_images/173709-a9c1368eb048d3de.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


##5.4 User signup: A first step
###5.4.1 Users controller
好,前面纠结了半天的界面,布局,其实也就是呈现了个小菜单而已,大概也就是正常工程师5min的工作量吧,而且没啥成就感,接下来,我们终于要开发第一个功能了---注册登录模块.
是不是有点小激动:

ruby的一小步,人类的一大步...
----🍺

首先,Users要玩起来,得需要一个controller:

//generate 可直接写成 g
rails generate controller Users new

###5.4.2 Signup URL
增加路由,不过`generate controller`的时候,会自动增加`get 'users/new'`,我们现在改成我们统一的格式

vim config/routes.rb

Rails.application.routes.draw do

root 'static_pages#home'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'
get 'signup' => 'users#new'
...

然后home.html 也修改,增加signup_path:

vim app/views/static_pages/home.html.erb

<div class="center jumbotron">
<h1>Welcome to the Sample App</h1>

<h2>
This is the home page for the
<a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a>
sample application.
</h2>

<%= link_to "Sign up now!", 'signup_path', class: "btn btn-lg btn-primary" %>
</div>

<%= link_to image_tag("rails.png", alt: "Rails logo"),
'http://rubyonrails.org/' %>

<br />
#6.  [Modeling users](https://www.railstutorial.org/book/modeling_users#cha-modeling_users)
***
ruby和iOS一样也是MVC模式,当然很多语言都是这个模式
我们上一篇新建了controller,这一篇来新建model

##6.1 User model
我们要做这样一个页面:

![sign up](http://upload-images.jianshu.io/upload_images/173709-182a8ac9e4377d48.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

###6.1.1 Database migrations
新建一个model,有2个属性:name和email

rails generate model User name:string email:string

>polen:
注意ruby的默认命名习惯(注意单复数):
a *Users* controller, a *User* model => *migration*: users.table
**就是model用单数,对应的controller和对应的数据库用复数**

然后,迁移("migrating up")数据库:

rake db:migrate

这样就会创建一个sqlite3数据库,当然实际中大家肯定用的是mysql,关于ruby和mysql连接,可以去看
[MySQL Ruby tutorial](http://zetcode.com/db/mysqlrubytutorial/)

>polen:
数据库回滚用:

rake db:rollback


###6.1.2 The model file
![usermodel](http://upload-images.jianshu.io/upload_images/173709-fac189b69eeefb43.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

###6.1.3 Creating user objects
###6.1.4 Finding user objects
###6.1.5 Updating user objects
进入控制台,**CRUD数据(增删改查)**,这部分和代码没直接关系,暂且略过

User.create(name: "A Nother", email: "another@example.org")

<User id: 2, name: "A Nother", email: "another@example.org", created_at:

"2014-07-24 01:05:24", updated_at: "2014-07-24 01:05:24">

foo = User.create(name: "Foo", email: "foo@bar.com")

<User id: 3, name: "Foo", email: "foo@bar.com", created_at: "2014-07-24

01:05:42", updated_at: "2014-07-24 01:05:42">
...
...



##6.2 User validations
###6.2.2 Validating presence
增加数据检查的条件,先设个简单的,检查是否存在

vim app/models/user.rb

class User < ActiveRecord::Base
validates :name, presence: true
//或者: validates(:name, presence: true)
end

###6.2.3 Length validation

class User < ActiveRecord::Base
validates :name, presence: true, length: { maximum: 50 }
validates :email, presence: true, length: { maximum: 255 }
end


###6.2.4 Format validation

class User < ActiveRecord::Base
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+-.]+@[a-z\d-.]+.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX }
end


###6.2.5 Uniqueness validation

class User < ActiveRecord::Base
before_save { self.email = email.downcase }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+-.]+@[a-z\d-.]+.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
end


这里增加了唯一性的检查,

**由唯一性引出索引的问题**,为保证唯一性,对应数据库,需要增加index:

rails generate migration add_index_to_users_email

class AddIndexToUsersEmail < ActiveRecord::Migration
def change
add_index :users, :email, unique: true
end
end

rake db:migrate


##6.3 Adding a secure password
###6.3.1 A hashed password
我们需要保证密码的安全,比如做个md5或者其他hash之类的,那么以下是准备工作:

a). 数据库需要加入password_digest:

$ rails generate migration add_password_digest_to_users password_digest:string

这样就可以看到生成一个add_password_digest_to_users.rb
![屏幕快照 2016-05-29 下午6.08.37.png](http://upload-images.jianshu.io/upload_images/173709-bfbd7bf292bb519d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

然后 

run db:migrate


b). Gemfile引入新库bcrypt, 这种用于对密码做hash处理:

add by polen

gem 'bootstrap-sass', '3.2.0.0'

Use ActiveModel has_secure_password

gem 'bcrypt', '~> 3.1.11'

然后

bundle update

>polen:
bcrypt这个库 gem file里面默认会有(只是被注释掉了),我们解注就可以了,不过默认是3.1.7,新版本已经是3.1.11,我这边直接用最新的了.
另外,这个执行bundle update之后,运行rake test或者直接本地查看我们的页面会报错,`bcrypt LoadError: Cannot load such file`,这个其实是因为我们需要重新rails server 运行一下. 
可以参照:[stackoverflow.com/questions/26553696/](http://stackoverflow.com/questions/26553696/bcrypt-loaderror-cannot-load-such-file)

###6.3.2 User has secure password
6.3.1准备妥当之后,
User model中增加has_secure_password

class User < ActiveRecord::Base
...
...
has_secure_password
end

###6.3.3 Minimum password standards
修改usermodel,增加validates :password:

vim app/models/user.rb

class User < ActiveRecord::Base
before_save { self.email = email.downcase }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+-.]+@[a-z\d-.]+.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, presence: true, length: { minimum: 6 }
end


<br />
#7. [Sign up](https://www.railstutorial.org/book/sign_up#cha-sign_up)
***
注册登录结束,接下来,就是展示user的页面了,我们要做成这个样子:
![show user](http://upload-images.jianshu.io/upload_images/173709-ba69909f68267b74.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##7.1 Showing users
###7.1.1 Debug and Rails environments
真的的大头开始做起来了,也算是第一个复杂一点的页面了,但是毕竟没有像xcode一样可以时时调试,那就需要我们自己加个debug信息.

vim app/views/layouts/application.html.erb

既然是全局加,自然加到application.html这个地方了,
加一句话`<%= debug(params) if Rails.env.development? %>`

<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= stylesheet_link_tag "application", media: "all",
"data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= csrf_meta_tags %>
<%= render 'layouts/shim' %>
</head>
<body>
<%= render 'layouts/header' %>
<div class="container">
<%= yield %>
<%= render 'layouts/footer' %>
<%= debug(params) if Rails.env.development? %>
</div>
</body>
</html>

对应debug信息的UI位置,也要调一调啦:

vim app/assets/stylesheets/custom.css.scss

@import "bootstrap-sprockets";
@import "bootstrap";

/* mixins, variables, etc. */

$gray-medium-light: #eaeaea;

@mixin box_sizing {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
...
...
...
/* miscellaneous */

.debug_dump {
clear: both;
float: left;
width: 100%;
margin-top: 45px;
@include box_sizing;
}

###7.1.2 A Users resource
a). 增加路由

vim config/routes.rb

Rails.application.routes.draw do

root 'static_pages#home'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'
get 'signup' => 'users#new'
resources :users

>polen: 
resources意思是加了个套装的url,所有users相关的都加进去了

b). UI跟上,加个show.html.erb

touch app/views/users/show.html.erb

![屏幕快照 2016-05-29 下午6.34.55.png](http://upload-images.jianshu.io/upload_images/173709-7fc451fe878d6f49.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

c). controller 里也需要加个show方法

vim app/controllers/users_controller.rb

class UsersController < ApplicationController
def new
end

def show
@user = User.find(params[:id])
end
end


###7.1.3 Debugger
加个debug

def show
@user = User.find(params[:id])
debugger
end

###7.1.4 A Gravatar image and a sidebar

a). 修改show.html.erb:

vim app/views/users/show.html.erb

<% provide(:title, @user.name) %>
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<h1>
<%= gravatar_for @user %>
<%= @user.name %>
</h1>
</section>
</aside>
</div>

b). 在users_helper.rb增加  
def gravatar_for(user)方法

vim app/helpers/users_helper.rb

module UsersHelper

Returns the Gravatar for the given user.

def gravatar_for(user)
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
end

c). 刚才增加了侧边位置,以及头像,所以我们要修改布局custom.css.scss

vim app/assets/stylesheets/custom.css.scss

...
...
/* sidebar */

aside {
section.user_info {
margin-top: 20px;
}
section {
padding: 10px 0;
margin-top: 20px;
&:first-child {
border: 0;
padding-top: 0;
}
span {
display: block;
margin-bottom: 3px;
line-height: 1;
}
h1 {
font-size: 1.4em;
text-align: left;
letter-spacing: -1px;
margin-bottom: 3px;
margin-top: 0px;
}
}
}

.gravatar {
float: left;
margin-right: 10px;
}

.gravatar_edit {
margin-top: 15px;
}


##7.2 Signup form
我们再次回到注册,完成注册的表单页面
![屏幕快照 2016-05-29 下午6.48.51.png](http://upload-images.jianshu.io/upload_images/173709-5e540c4a3bd25c61.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

>polen:
补充数据库重置的方法:

rake db:migrate:reset

此方法慎用,自己开发玩玩可以,线上千万不要乱来...

###7.2.1 Using form_for

a). controller 中完善我们的new方法:

vim app/controllers/users_controller.rb

class UsersController < ApplicationController

def show
@user = User.find(params[:id])
debugger
end

def new
@user = User.new
end
end

b). 界面画起来new.html.erb:

vim app/views/users/new.html.erb

<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(@user) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>

  <%= f.label :email %>
  <%= f.email_field :email %>

  <%= f.label :password %>
  <%= f.password_field :password %>

  <%= f.label :password_confirmation, "Confirmation" %>
  <%= f.password_field :password_confirmation %>

  <%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>

</div>
</div>


c). 布局也是要调一调的啊,打开custom.css.scss:

vim app/assets/stylesheets/custom.css.scss

...
...
/* forms */

input, textarea, select, .uneditable-input {
border: 1px solid #bbb;
width: 100%;
margin-bottom: 15px;
@include box_sizing;
}

input {
height: auto !important;
}


###7.2.2 Signup form HTML
其实代码已经完成了,只是这里来对比一下,以为大家可能已经习惯了html语法,当然这里也是支持直接用html写的,但是还是要慢慢习惯过来ruby的写法:
> 不然你学他干嘛😄

用ruby写成的表单的基本框架是这样的:

<%= form_for(@user) do |f| %>
...
...
<% end %>

对比下html写法和ruby写法:

//html:
<label for="user_password">Password</label>
<input id="user_password" name="user[password]" type="password" />

//ruby:
<%= f.label :password %>
<%= f.password_field :password %>


##7.3 Unsuccessful signups
###7.3.1 A working form
下面来实现注册失败的操作:

vim app/controllers/users_controller.rb

class UsersController < ApplicationController

def show
@user = User.find(params[:id])
end

def new
@user = User.new
end

def create
@user = User.new(params[:user]) # Not the final implementation!
if @user.save
# Handle a successful save.
else
render 'new'
end
end
end

###7.3.2 Strong parameters
这个讲了关于多参数的问题,rails早起版本有个attr_accessible用于处理多个参数的问题;从rails4.0 开始,有个称之为strong parameters的方法:

params.require(:user).permit(:name, :email, :password, :password_confirmation)

这里user是必须要的参数,其他属于可选参数.

###7.3.3 Signup error messages
注册时候的错误信息处理:

a). 首先新建个/shared/_error_messages.html.erb:

mkdir app/views/shared
touch app/views/shared/_error_messages.html.erb

b). 修改_error_messages.html.erb,展示具体错误信息

vim app/views/shared/_error_messages.html.erb

<% if @user.errors.any? %>
<div id="error_explanation">
<div class="alert alert-danger">
The form contains <%= pluralize(@user.errors.count, "error") %>.
</div>
<ul>
<% @user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>

c). 布局也是要设置一下的:

vim app/assets/stylesheets/custom.css.scss

...
...

error_explanation {

color: red;
ul {
color: red;
margin: 0 0 30px 0;
}
}

.field_with_errors {
@extend .has-error;
.form-control {
color: $state-danger-text;
}
}

d). 在new.html中加入` <%= render 'shared/error_messages' %>`调用:

vim app/views/users/new.html.erb

<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(@user) do |f| %>
<%= render 'shared/error_messages' %>

  <%= f.label :name %>
  <%= f.text_field :name, class: 'form-control' %>

  <%= f.label :email %>
  <%= f.email_field :email, class: 'form-control' %>

  <%= f.label :password %>
  <%= f.password_field :password, class: 'form-control' %>

  <%= f.label :password_confirmation, "Confirmation" %>
  <%= f.password_field :password_confirmation, class: 'form-control' %>

  <%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>

</div>
</div>


##7.4 Successful signups
###7.4.1 The finished signup form
前面说的`params.require(:user)...`这里就用起来了啊,我们需要定义个`user_params`:

private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end

###7.4.2 The flash
加个小动画:

flash[:success] = "Welcome to the Sample App!"

###以上7.4.1/7.4.2的修改合起来就是:
users_controller.rb和application.html.erb

vim app/controllers/users_controller.rb


class UsersController < ApplicationController

def show
@user = User.find(params[:id])
end

def new
@user = User.new
end

def create
@user = User.new(user_params)
if @user.save
flash[:success] = "Welcome to the Sample App!"
redirect_to @user
else
render 'new'
end
end

private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end


vim app/views/layouts/application.html.erb


<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= stylesheet_link_tag "application", media: "all",
"data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= csrf_meta_tags %>
<%= render 'layouts/shim' %>
</head>
<body>
<%= render 'layouts/header' %>
<div class="container">
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %>"><%= message %></div>
<% end %>
<%= yield %>
<%= render 'layouts/footer' %>
<%= debug(params) if Rails.env.development? %>
</div>
</body>
</html>


##7.5 Professional-grade deployment
这个是关于环境配置和发布的问题:
###7.5.1 SSL in production

vim config/environments/production.rb

...

Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.

config.force_ssl = true
...


###7.5.2 Production webserver
Gemfile增加production所需的库

...
group :production do
gem 'pg', '0.17.1'
gem 'rails_12factor', '0.0.2'
gem 'puma', '3.1.0'
end
...

bundle install

>polen:
这个安装的时候,有些许困难,会遇到一个`Can't find the 'libpq-fe.h header when trying to install pg gem`的问题 ,这个的解决需要

brew install postgresql

参照[stackoverflow.com/questions/6040583](http://stackoverflow.com/questions/6040583/cant-find-the-libpq-fe-h-header-when-trying-to-install-pg-gem)
然后其他的问题,按照错误提示安装所需要的库即可

<br />
#Github:
***
本文所有的代码已上传github:
[polegithub/rails_sample_app_polen](https://github.com/polegithub/rails_sample_app_polen)

#相关:
***
[[Ruby]《Ruby on Rails Tutorial》的搬运工之二](http://www.jianshu.com/p/25d539845cd7)
[[Ruby]《Ruby on Rails Tutorial》的搬运工之三](http://www.jianshu.com/p/b036349adc9c)

***
by polen
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容