Professional Documents
Culture Documents
xdite
This book is for sale at http://leanpub.com/rails-101
This version was published on 2014-06-10
This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.
2013 - 2014 xdite
Also By xdite
Maintainable Rails View
Lean SaaS
Land Dream Rails Job
Contents
CHANGELOG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Logdown . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
2
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Rails . .
Git . . . . . . . . . .
. . . . . . . .
Linux Command Line
.
.
.
.
5
5
6
6
Ruby on Rails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
8
0 - Hello World .
. . . . . . . .
Hello World .
Rails Routing . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
13
13
19
22
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
24
25
26
30
31
33
36
39
41
43
45
48
50
CONTENTS
51
53
60
2 - Group - RESTFul . . . .
Ch 2.1 Post . . . . . . . . . . . . . . . . . . . . . . . .
Ch 2.1.1 Groups controller show Post
Ch 2.1.2 Posts Controller new . . . . . . . . . . .
Ch 2.1.3 Posts Controller create . . . . . . . . . .
Ch 2.1.4 Posts Controller edit . . . . . . . . . . .
Ch 2.1.5 Posts Controller update . . . . . . . . . .
Ch 2.1.6 Posts Controller destroy . . . . . . . . .
Ch 2.1.7 before_action . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
63
64
67
69
70
72
73
74
75
3 - Group Post . .
Ch 3.0 devise Rails 4 . . . . . . . . . . . . . . .
Ch 3.1 Action
Ch 3.2 Group User . . . . . . .
Ch 3.3 Post User . . . . . . . .
78
79
83
84
91
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4 - User . . . . . . . . . .
Ch 4.1
Ch 4.1.2 model method after create . . . . . . . . . . .
Ch 4.1.3 join quit action . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. 96
. 98
. 101
. 103
5 - Account . . . . . . . . . . . .
Ch 5.1 User Group
Ch 5.2 User .
Ch 5.3 DESC . . . . . . .
Ch 5.4 Group DESC . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
105
106
108
111
112
6 - Refactor code . . . . . . .
Ch 6.1 helper code . .
Ch 6.2 helper html
Ch 6.3 partial html . . . .
Ch 6.4 scope query . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
115
116
117
119
121
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
126
127
128
131
132
CONTENTS
Asset Pipeline .
SCSS . . . . . . . . . . . .
CoffeeScript . . . . . . . .
Asset Pipeline . .
Rails 4 with Asset Pipeline
. . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
133
133
136
138
140
141
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . .
Ruby on Rails . . . . . . . . . . .
Testing . . . . . . . . . . . . . . .
. . . . . . . . . . .
Ruby / Rails code . . . . . . . . .
Ruby code . . . . . . .
Object-oriend Design in Ruby on Rails
Rails . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
142
142
143
143
143
144
144
145
145
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
Resources of latest Ruby . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
CHANGELOG
2014/01
Fix
2013/12
Fix
Upgrade Bootstrappers
Fix Bootstrappers
mysql SQLite
Fix production hack
TODO
RESTFul
Recap
Facebook https://www.facebook.com/groups/rails101/
2013/11
Bootstrapper, Rails 4.0.0 , Repo
Helper
Partial
Scope
Capistrano
Asset Pipeline
Rails 4.0.0 production hack
2013/06 Ch6
xdite Ruby on Rails 6 ( Since 2007 )
Web blog Blog.XDite.net Rails
Logdown
Logdown Rocodev Blog
rails101 coupon USD $10 Logdown
sdlong
http://blog.xdite.net
http://blog.xdite.net
http://paperclip.io/pages/about
http://rocodev.com
http://logdown.com
http://rocodev.com
1.
2.
3.
4.
5.
6.
7.
8.
https://www.facebook.com/groups/rails101/ FB
Google Stack Overflow
@
migration
touch tmp/restart.txt
http://guides.rubyonrails.org
development.log Chrome DevTools Console
2009 Rails Developer
Rails
Developer
Rails Rails /
build
Rails
Facebook https://www.facebook.com/groups/rails101/
Gist
https://github.com/xdite/groupme
Rails Rails
Stackoverflow
http://gist.github.com
http://stackoverflow.com/
Rails
Git
Vim SublimeText2
Linux Command Line
Git
Codeshool Git Rails
Git
TryGit http://www.codeschool.com/courses/try-git
GitReal http://www.codeschool.com/courses/git-real
GitReal2 http://www.codeschool.com/courses/git-real-2
1. Github
2. Git
https://github.com
git commit
git push
git pull
git branch
git checkout
git merge
Rails
Vim
c9s Vim Hacks vim
Sublimtext 2
Sunlimtext 2 : http://www.sublimetext.com/2
Sublime Text SublimeText
http://c9s.blogspot.com/2009/08/vim-hacks-coscup.html
https://www.facebook.com/SublimeTextTW
http://docs.sublimetext.tw/
http://peepcode.com/products/meet-the-command-line
http://peepcode.com/products/advanced-command-line
http://peepcode.com/products/meet-the-command-line
http://peepcode.com/products/advanced-command-line
Ruby on Rails
Rails Rails
lib gem
OSX 10.8MySQLImageMagickreadline .
project
https://github.com/rocodev/guides/wiki/setup-mac-development
Rails Developer
Rails Developer MacBook + Best Practices /
brewLivereload Mac OS Gem
Rails
Linux package system maintainer Rails Developer
Framework
Rails Mac
http://rocodev.com
Ruby on Rails
1. Mac 10.9
2. Apple Store Xcode 5.0.4 Command Tools )
1
2
3
Homebrew
4
5
6
XQuartz
Ruby on Rails
ImageMagick / MySQL
1
2
3
4
5
6
7
8
9
10
Imagemagick
MySQL
http://dev.mysql.com/downloads/mysql/
Ruby on Rails
10
1
2
3
4
1
2
3
4
5
6
RVM
Ruby 2.0
1
2
3
4
$
$
$
$
gem
gem
gem
gem
Ruby gems
install
install
install
install
https://rvm.beginrescueend.com/
Ruby on Rails
11
$ curl get.pow.cx | sh
Setting
Pow /.pow
project Pow wiki
1
2
$ cd ~/.pow/
$ ln -s ~/projects/wiki
http://wiki.dev http://localhost:3000/
Powder Pow
Powder
Pow
http://pow.cx
http://37signals.com/
http://rack.rubyforge.org/
http://www.modrails.com/
http://pow.cx
http://pow.cx
https://github.com/Rodreegez/powder
Ruby on Rails
1
.rvmrc
1
rvm 2.0.0
12
0 - Hello World
Rails
http://gembundler.com/
http://pow.cx
http://ihower.tw/rails3/environment-and-bundler.html
0 - Hello World
Rails 4.0.0
1
groupmy
1
$ cd groupmy
14
0 - Hello World
15
Bundler
Bundler
Bundler Ruby
Bundler
Bundler Gemfile Rails Gemfile
source 'https://rubygems.org'
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
# Turbolinks makes following links in your web application faster. Read more: htt\
ps://github.com/rails/turbolinks
gem 'turbolinks'
27
28
29
30
http://gembundler.com/
http://gembundler.com/
0 - Hello World
31
32
33
34
16
group :doc do
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', require: false
end
35
36
37
38
39
40
41
42
43
44
45
46
# Use debugger
# gem 'debugger', group: [:development, :test]
Bundler
bundle check :
bundle install :
bundle install
0 - Hello World
17
Pow
Rails Webserver rails s
port 3000 http://localhost:3000
Pow
Pow Pow http://groupmy.
dev rails s port 3000
rails s Ctrl-C
Server config/routes.rb
config/enviroments/*.rb config/database.yml Server
Ctrl-C rails s
.powrc
1
2
3
4
powder open
http://pow.cx
0 - Hello World
18
rvm reload
bundle install
powder restart
touch tmp/restart.txt
development.log
rails s
0 - Hello World
19
Hello World
http://groupmy.dev/
Rails
Hello World
Hello World pages controller wecleom action
0 - Hello World
1
2
3
4
5
6
7
8
9
10
1: pages controller
2: welcome action
app/controllers/pages_controller.rb
1
2
3
4
app/views/pages/welcome.html.erb
1
Hello World!
4:
Hello World!
20
21
0 - Hello World
Hello world
0 - Hello World
Rails Routing
Rails config/routes.rb mapping
routing
1
get "subscriptions/new"
2
3
4
5
resources :posts do
resources :comments
end
6
7
8
9
namespace :admin do
resources :posts
end
10
11
12
22
23
0 - Hello World
Ruby on Rails
Group
Group
Group Post model CRUD
http://groupme.dev/group/1/post/2
Route
resources resources)
Rails RESTful
before_action
25
Ch 1.0 CRUD
CRUD Create()Read()Update()Destroy()
Rails RESTful
Convention CRUD-like
26
Post content
post scaffold
1
db:migrate
1
$ rake db:migrate
2
3
4
5
6
7
8
9
10
11
12
http://groupme.dev/groups
27
http://groupme.dev/posts/new
28
29
Scaffold
groups post model migration
groups posts CRUD controller / action / view
config/routes resources :groups resources :posts
What is db migration?
web phpmyadmin db
Rails db migration
phpmyadmin
db migration project
db schema
db db
automation db schema db
migration file
CRUD Rails
CRUD scaffold
30
Ch 1.0 Bootstrappers
Bootstrappers 2012
Boostrap Theme Gem Rails Best Practice
bootstrappers
bootstrappers
bootstrappers
bootstrappers groupme
https://github.com/xdite/bootstrappers
http://twitter.github.io/bootstrap/
Ch 1.1 Group
Group model
invoke
create
create
invoke
create
create
active_record
db/migrate/20130529180541_create_groups.rb
app/models/group.rb
test_unit
test/models/group_test.rb
test/fixtures/groups.yml
Group model
rake db:migrate
1
2
3
4
31
groups controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
app/controllers/groups_controller.rb
erb
app/views/groups
test_unit
test/controllers/groups_controller_test.rb
helper
app/helpers/groups_helper.rb
test_unit
test/helpers/groups_helper_test.rb
assets
coffee
app/assets/javascripts/groups.js.coffee
scss
app/assets/stylesheets/groups.css.scss
groups routing
config/routes.rb
1
resources :groups
32
33
Ch 1.1 () RESTful
Rails 1.2 RESTful 2.0
RESTful Rails
RESTful Rails
Rails RESTful
RESTful Rails
web
Rails
Rails Rails RESTful
RESTful
34
Rails RESTful
config/routes.rb resources
Groupme::Application.routes.draw do
resources :groups
end
35
RESTful
def index
@groups = Group.all
end
36
view
touch app/views/groups/index.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="span12">
<div class="group">
<%= link_to("New group", new_group_path , :class => "btn btn-mini btn-primary\
pull-right" ) %>
</div>
<table class="table">
<thead>
<tr>
<td> # </td>
<td> Title </td>
<td> Descroption </td>
</tr>
</thead>
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<tbody>
<% @groups.each do |group| %>
<tr>
<td> # </td>
<td> <%= link_to(group.title, group_path(group)) %> </td>
<td> <%= group.description %> </td>
<td> <%= link_to("Edit", edit_group_path(group), :class => "btn btn-mini"\
) %>
<%= link_to("Delete", group_path(group), :class => "btn btn-mini", :meth\
od => :delete, :confirm => "Are you sure?" ) %>
</td>
</tr>
<% end %>
</tbody>
</table>
30
31
</div>
37
def index
@groups = Group.all
end
38
def show
@group = Group.find(params[:id])
end
view
touch app/views/groups/show.html.erb
<div class="span12">
2
3
4
5
6
<div class="group">
<%= link_to("Edit", edit_group_path(@group) , :class => "btn btn-mini btn-pri\
mary pull-right" ) %>
</div>
7
8
9
10
11
12
</div>
39
40
def show
@group = Group.find(params[:id])
end
def new
@group = Group.new
end
Group object
view
touch app/views/groups/new.html.erb
<div class="span12">
2
3
4
5
6
7
8
9
10
11
<div class="form-actions">
<%= f.submit "Submit", :disable_with => 'Submiting...', :class => "btn btn\
-primary" %>
</div>
<% end %>
12
13
</div>
41
def new
@group = Group.new
end
42
43
def create
@group = Group.new(params[:group])
@group.save
4
5
6
redirect_to groups_path
end
Group title
group
title group new
app/models/group.rb group
1
2
3
4
5
end
1
2
def create
@group = Group.new(group_params)
3
4
5
6
7
8
9
if @group.save
redirect_to groups_path
else
render :new
end
end
10
11
12
private
13
14
15
16
17
def group_params
params.require(:group).permit(:title, :description)
end
44
app/views/groups/new.html.erb view
1
<div class="span12">
2
3
4
5
6
7
8
9
10
11
<div class="form-actions">
<%= f.submit "Submit", :disable_with => 'Submiting...', :class => "btn btn\
-primary" %>
</div>
<% end %>
12
13
</div>
45
Hack
mass-assignment etc.
:
attr_accessible
attr_accessible
attr_accessible
Admin mass-assignment
Rails 3.1 scoped mass assignment model
scoped mass assignment
http://blog.xdite.net/posts/2012/03/05/github-hacked-rails-security/
46
controller model
controller controller
solution strong_parameters
Rails DHH
1
2
3
4
5
6
7
8
def update
Post.find(params[:id]).update_attributes!(post_params)
end
9
10
11
12
13
14
private
def post_params
params[:post].slice(:title, :content)
end
end
https://github.com/rails/strong_parameters/
47
Strong Parameters
strong_parameters permit
throw exception
1
2
3
4
5
6
7
8
9
10
11
private
def person_params
params.require(:person).permit(:name, :age)
end
end
Strong Parameters
controller Railscast
Nested Attributes
Orgngized to Class
http://railscasts.com/episodes/371-strong-parameters
def edit
@group = Group.find(params[:id])
end
view
touch app/views/groups/edit.html.erb
<div class="span12">
2
3
4
5
6
7
8
9
10
11
<div class="form-actions">
<%= f.submit "Submit", :disable_with => 'Submiting...', :class => "btn btn\
-primary" %>
</div>
<% end %>
12
13
</div>
48
def edit
@group = Group.find(params[:id])
end
49
50
def update
@group = Group.find(params[:id])
3
4
5
6
7
8
9
if @group.update(group_params)
redirect_to group_path(@group)
else
render :edit
end
end
app/views/posts/edit.html.erb view
1
<div class="span12">
2
3
4
5
6
7
8
9
10
11
<div class="form-actions">
<%= f.submit "Submit", :disable_with => 'Submiting...', :class => "btn btn\
-primary" %>
</div>
<% end %>
12
13
</div>
def destroy
@group = Group.find(params[:id])
3
4
@group.destroy
5
6
7
redirect_to groups_path
end
Group CRUD
Group Index
51
52
app/views/posts/index.html.erb view
<tr>
<td>
<td>
<td>
<td>
1
2
3
4
5
6
7
8
9
10
# </td>
<%= link_to(group.title, group_path(group)) %> </td>
<%= group.description %> </td>
<%= link_to("Edit", edit_group_path(group), :class => "btn btn-mini"\
) %>
<%= link_to("Delete", group_path(group), :class => "btn btn-mini", :meth\
od => :delete, :confirm => "Are you sure?" ) %>
</td>
</tr>
RESTful
53
on Rails
What is REST?
REST
1.
2.
3.
4.
5.
(resource)
resource identifier
(generic connector interface)
resource idetifier
(stateless)
web services
resource indentifier URI
generic connector interface HTTP
54
URIhttp://example.com/resources/
Web Services accept return media typeJSONXML YAML
Web Services resources request methid : POSTGETPUT
DELETE
RESTful Web HTTP
GET
GET
URI
http://example.com/resources/
URI
http://example.com/resources/142
media type
XMLJSON
PUT
URI
http://example.com/resources/
URI
http://example.com/resources/142
URI
POST
URI
http://example.com/resources/
URI
http://example.com/resources/142
/
URL
PUT
POST
55
DELETE
DELETE
URI http://example.com/resources/
URI http://example.com/resources/142
56
1
2
def add_friend
end
3
4
5
def remove_friend
end
6
7
8
def create_post
end
9
10
11
def delete_post
end
REST resource
1
2
3
class FriendShipController
def create
end
4
5
6
7
def destroy
end
end
8
9
10
11
class PostController
def create
end
12
13
14
15
def destroy
end
end
http://www.slideshare.net/vishnu/discovering-a-world-of-resources-on-rails
Action
57
as Resource
6
7
8
9
10
11
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @posts }
end
end
Helper
REST Rails REST implementation
controller method
index
show
new
edit
create
update
destroy
CRUDweb services
Rails HTTP generic connector interface HTTP verb GETPOST
PUTDELETE
GET
1
2
3
4
<%=
<%=
<%=
<%=
POST
1
<%= form_for @post , :url => posts_path , :html => {:method => :post} do |f| %>
PUT
1
2
<%= form_for @post , :url => post_path(@post) , :html => {:method => :put} do |\
f| %>
Destroy
1
58
59
<h1>New post</h1>
2
3
4
5
6
7
8
9
10
11
def create
@post = Post.new(params[:post])
if @post.save
flash[:notice] = 'Post was successfully created.'
redirect_to post_path(@post)
else
render :action => "new"
end
end
REST
Wikipedia: REST
Wikipedia: ROA
DHH: Discovering a world of Resource on Rails
ihower: Rails RESTful
ihower: REST RESTful
http://baike.baidu.com/view/1077487.htm
http://zh.wikipedia.org/wiki/REST
http://en.wikipedia.org/wiki/Resource-oriented_architecture
http://en.wikipedia.org/wiki/Resource-oriented_architecture
http://ihower.tw/blog/archives/1566
http://ihower.tw/blog/archives/1542
More
60
resources :photos do
member do
get 'preview'
end
end
1
2
3
resources :photos do
get 'preview', :on => :member
end
Collection
URI /photos/search GET search_photos_path search_photos_url Url Helper
1
2
3
4
5
resources :photos do
collection do
get 'search'
end
end
61
1
2
3
resources :photos do
get 'search', :on => :collection
end
Nested Resources
resources Post Comment
1
2
3
resources :posts do
resources :comments
end
2
3
before_filter :find_post
4
5
6
7
def index
@comments = @post.comments
end
8
9
protected
10
11
12
13
14
def find_post
@post = Post.find(params[:post_id])
end
end
62
Namespace Resources
/admin/posts/1/edit URL Nested Resources
URL Namespace
1
2
3
4
5
namespace :admin do
# Directs /admin/products/* to Admin::PostsController
# (app/controllers/admin/posts_controller.rb)
resources :posts
end
2 - Group -
RESTFul
has_many, belongs_to
resources resources )
before_action
2 - Group - RESTFul
Ch 2.1 Post
Post model
invoke
create
create
invoke
create
create
active_record
db/migrate/20130529200707_create_posts.rb
app/models/post.rb
test_unit
test/models/post_test.rb
test/fixtures/posts.yml
Post model
rake db:migrate
1
2
3
4
64
2 - Group - RESTFul
posts controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
app/controllers/posts_controller.rb
erb
app/views/posts
test_unit
test/controllers/posts_controller_test.rb
helper
app/helpers/posts_helper.rb
test_unit
test/helpers/posts_helper_test.rb
assets
coffee
app/assets/javascripts/posts.js.coffee
scss
app/assets/stylesheets/posts.css.scss
posts routing
config/routes.rb
1
resources :groups
1
2
3
resources :groups do
resources :posts
end
65
2 - Group - RESTFul
Group Post
2
3
4
has_many :posts
validates :title, :presence => true
5
6
end
66
2 - Group - RESTFul
def show
@group = Group.params([:id])
@posts = @group.posts
end
67
2 - Group - RESTFul
view
app/views/groups/show.html.erb
1
2
3
<div class="span12">
<div class="group pull-right">
<%= link_to("Edit", edit_group_path(@group) , :class => "btn btn-mini ")%>
4
5
6
7
8
9
10
11
12
13
<table class="table">
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<tbody>
<% @posts.each do |post| %>
<tr>
<td> <%= post.content %> </td>
<td> <%= link_to("Edit", edit_group_post_path(post.group, post), :class => \
"btn btn-mini")%>
<%= link_to("Delete", group_post_path(post.group, post), :class => "btn b\
tn-mini", :method => :delete, :confirm => "Are you sure?" ) %> </td>
</tr>
<% end %>
</tbody>
</table>
</div>
68
2 - Group - RESTFul
def new
@group = Group.find(params[:group_id])
@post = @group.posts.build
end
view
touch app/views/posts/new.html.erb
<div class="span12">
2
3
4
5
6
7
8
9
10
<div class="form-actions">
<%= f.submit "Submit", :disable_with => 'Submiting...', :class => "btn btn\
-primary" %>
</div>
<% end %>
11
12
</div>
69
2 - Group - RESTFul
70
def create
@group = Group.find(params[:group_id])
@post = @group.posts.new(post_params)
4
5
6
7
8
9
10
if @post.save
redirect_to group_path(@group)
else
render :new
end
end
11
12
private
13
14
15
16
17
def post_params
params.require(:post).permit(:content)
end
2
3
4
belongs_to :group
validates :content, :presence => true
5
6
end
2 - Group - RESTFul
71
http://edgeguides.rubyonrails.org/active_record_validations.html
2 - Group - RESTFul
def edit
@group = Group.find(params[:group_id])
@post = @group.posts.find(params[:id])
end
view
touch app/views/posts/edit.html.erb
1
<div class="span12">
2
3
4
5
6
7
8
9
10
<div class="form-actions">
<%= f.submit "Submit", :disable_with => 'Submiting...', :class => "btn btn\
-primary" %>
</div>
<% end %>
11
12
</div>
72
2 - Group - RESTFul
def update
@group = Group.find(params[:group_id])
@post = @group.posts.find(params[:id])
4
5
6
7
8
9
10
if @post.update(post_params)
redirect_to group_path(@group)
else
render :edit
end
end
73
2 - Group - RESTFul
def destroy
@group = Group.find(params[:group_id])
@post = @group.posts.find(params[:id])
4
5
@post.destroy
6
7
8
redirect_to group_path(@group)
end
Post CRUD
74
2 - Group - RESTFul
Ch 2.1.7 before_action
Posts action
1
@group = Group.find(params[:group_id])
before_action
private find_group method
1
2
3
def find_group
@group = Group.find(params[:group_id])
end
before_action :find_group
action
1
@group = Group.find(params[:group_id])
2
3
before_action :find_group
4
5
6
7
def new
@post = @group.posts.build
end
8
9
def create
10
11
@post = @group.posts.new(post_params)
12
13
14
15
if @post.save
redirect_to group_path(@group)
else
75
2 - Group - RESTFul
16
17
18
render :new
end
end
19
20
21
22
def edit
@post = @group.posts.find(params[:id])
end
23
24
def update
25
26
@post = @group.posts.find(params[:id])
27
28
29
30
31
32
33
if @post.update(post_params)
redirect_to group_path(@group)
else
render :edit
end
end
34
35
36
def destroy
37
38
@post = @group.posts.find(params[:id])
39
40
@post.destroy
41
42
43
redirect_to group_path(@group)
end
44
45
46
private
47
48
49
50
51
def find_group
@group = Group.find(params[:group_id])
end
52
53
54
55
56
def post_params
params.require(:post).permit(:content)
end
end
76
2 - Group - RESTFul
before_action controller
before_action only action
1
except action
1
77
3 - Group Post
Group
/ Group Post
GroupPost
gem
devise
method login_required
before_action login_required
session current_user
devise
https://github.com/plataformatec/devise/wiki
3 - Group Post
79
gem
devise
devise Rails
LockableConfirmableRecoverable
Facebook OmniAuthable
Bootstrappers devise gem
Gemfile
1
gem 'devise'
bundle
bundle install
rails g devise:install
user model
rails generate devise user
devise
<%= link_to( "Sign Up" ,new_user_registration_path) %>
<%= link_to( "Login", new_user_session_path ) %>
<%= link_to("Logout",destroy_user_session_path, :method => :delete ) %>
devise method
1. current_user.blank?
2. current_user
https://github.com/plataformatec/devise
3 - Group Post
80
login_required
Bootstrappers app/controller/application_controller.rb
methodlogin_required
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def login_required
if current_user.blank?
respond_to do |format|
format.html {
authenticate_user!
}
format.js{
render :partial => "common/not_logined"
}
format.all {
head(:unauthorized)
}
end
end
15
16
end
action before_action
3 - Group Post
81
devise
rails g devise:views
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
invoke
create
create
invoke
create
create
create
create
create
create
create
create
create
create
create
create
invoke
create
create
create
create
Devise::Generators::SharedViewsGenerator
app/views/devise/shared
app/views/devise/shared/_links.erb
simple_form_for
app/views/devise/confirmations
app/views/devise/confirmations/new.html.erb
app/views/devise/passwords
app/views/devise/passwords/edit.html.erb
app/views/devise/passwords/new.html.erb
app/views/devise/registrations
app/views/devise/registrations/edit.html.erb
app/views/devise/registrations/new.html.erb
app/views/devise/sessions
app/views/devise/sessions/new.html.erb
app/views/devise/unlocks
app/views/devise/unlocks/new.html.erb
erb
app/views/devise/mailer
app/views/devise/mailer/confirmation_instructions.html.erb
app/views/devise/mailer/reset_password_instructions.html.erb
app/views/devise/mailer/unlock_instructions.html.erb
3 - Group Post
82
app/views/devise/registrations/new.html.erb name
<h2>Sign up</h2>
2
3
4
5
6
7
8
9
10
11
12
<div class="form-inputs">
<%= f.input :email, :required => true, :autofocus => true %>
<%= f.input :name, :required => true %>
<%= f.input :password, :required => true %>
<%= f.input :password_confirmation, :required => true %>
</div>
13
14
15
16
17
<div class="form-actions">
<%= f.button :submit, "Sign up" %>
</div>
<% end %>
18
19
app/controller/application_controller
1
2
3
4
protected
5
6
7
8
9
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:name, :email, :passw\
ord, :password_confirmation) }
end
https://github.com/plataformatec/devise/tree/rails4#strong-parameters
3 - Group Post
Ch 3.1 Action
/ Group Post
Groups controller
1
2
3
Posts controller
1
2
3
83
3 - Group Post
1
2
active_record
db/migrate/20130531141923_add_user_id_to_group.rb
1
2
3
4
5
rake db:migrate
1
2
3
4
1
2
3
4
5
6
has_many :groups
7
8
extend OmniauthCallbacks
9
10
11
12
13
14
end
84
3 - Group Post
app/models/group.rb
1
2
3
4
5
def editable_by?(user)
user && user == owner
end
2
3
4
5
6
7
8
9
10
11
12
def editable_by?(user)
user && user == owner
end
end
85
3 - Group Post
Groups action
create
1
2
3
4
5
6
7
8
def create
@group = current_user.groups.build(group_params)
if @group.save
redirect_to groups_path
else
render :new
end
end
edit
1
2
3
def edit
@group = current_user.groups.find(params[:id])
end
update
1
2
def update
@group = current_user.groups.find(params[:id])
3
4
5
6
7
8
9
if @group.update(group_params)
redirect_to group_path(@group)
else
render :edit
end
end
86
3 - Group Post
destroy
1
2
def destroy
@group = current_user.groups.find(params[:id])
3
4
@group.destroy
5
6
7
redirect_to groups_path
end
87
3 - Group Post
app/views/groups/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
23
24
25
26
27
28
29
30
31
32
<div class="span12">
<div class="group">
<%= link_to("New group", new_group_path , :class => "btn btn-mini btn-primary\
pull-right")%>
</div>
<table class="table">
<thead> <tr>
<td> # </td>
<td> Title </td>
<td> Descroption </td>
<td> Owner </td>
</tr>
</thead>
<tbody>
<% @groups.each do |group| %>
<tr>
<td> # </td>
<td> <%= link_to(group.title, group_path(group)) %> </td>
<td> <%= group.description %> </td>
<td> <%= group.owner.name %> </td>
<td>
<% if current_user && group.editable_by?(current_user) %>
<%= link_to("Edit", edit_group_path(group), :class => "btn btn-mini")%>
<%= link_to("Delete", group_path(group), :class => "btn btn-mini", :metho\
d => :delete, :confirm => "Are you sure?" ) %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
88
3 - Group Post
89
@group = Group.find(params[:id])
action action
code
1
2
def edit
@group = Group.find(params[:id])
3
4
5
6
7
if @group.user != current_user
flash[:warning] = "No Permission"
redirec_to root_path
end
8
9
end
current_user.groups
1
2
3
def edit
@group = current_user.groups.find(params[:id])
end
create
1
2
3
4
5
6
7
8
9
def create
@group = Group.new(group_params)
@group.user = current_user
if @group.save
redirect_to groups_path
else
render :new
end
end
3 - Group Post
association
1
2
3
4
5
6
7
8
def create
@group = current_user.groups.build(group_params)
if @group.save
redirect_to groups_path
else
render :new
end
end
90
3 - Group Post
1
2
active_record
db/migrate/20130531153435_add_user_id_to_post.rb
1
2
3
4
5
rake db:migrate
1
2
3
4
1
2
3
4
5
6
7
has_many :groups
has_many :posts
8
9
extend OmniauthCallbacks
10
11
12
13
14
15
end
app/models/post.rb
91
3 - Group Post
1
2
3
4
5
def editable_by?(user)
user && user == author
end
2
3
4
belongs_to :group
validates :content, :presence => true
5
6
7
8
9
10
def editable_by?(user)
user && user == author
end
11
12
end
92
3 - Group Post
Posts action
create
1
def create
2
3
4
@post = @group.posts.new(post_params)
@post.author = current_user
5
6
7
8
9
10
11
if @post.save
redirect_to group_path(@group)
else
render :new
end
end
edit
1
2
3
def edit
@post = current_user.posts.find(params[:id])
end
update
1
def update
2
3
@post = current_user.posts.find(params[:id])
4
5
6
7
8
9
10
if @post.update(post_params)
redirect_to group_path(@group)
else
render :edit
end
end
93
3 - Group Post
destroy
1
def destroy
2
3
@post = current_user.posts.find(params[:id])
4
5
@post.destroy
6
7
8
redirect_to group_path(@group)
end
app/views/groups/show.html.erb
1
<div class="span12">
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<table class="table">
20
21
22
23
24
<tbody>
<% @posts.each do |post| %>
<tr>
<td>
25
26
27
28
29
</span>
<p>
<%= post.content %>
94
3 - Group Post
30
31
</p>
</td>
32
33
34
35
36
37
38
39
40
41
42
43
95
4 - User
user group /
user
has_many_belongs_to
custom routes
2
3
4
5
before_action :find_group
before_action :login_required, :only => [:new, :create, :edit,:update,:destroy]
before_action :member_required, :only => [:new, :create ]
6
7
8
9
10
def new
@post = @group.posts.build
end
11
12
13
14
def create
@post = @group.posts.new(post_params)
@post.author = current_user
15
16
17
18
19
20
21
if @post.save
redirect_to group_path(@group)
else
render :new
end
end
22
23
24
25
def edit
@post = current_user.posts.find(params[:id])
end
4 - User
26
27
28
def update
@post = current_user.posts.find(params[:id])
29
30
31
32
33
34
35
if @post.update(post_params)
redirect_to group_path(@group)
else
render :edit
end
end
36
37
38
def destroy
@post = current_user.posts.find(params[:id])
39
40
@post.destroy
41
42
43
redirect_to group_path(@group)
end
44
45
private
46
47
48
49
def post_params
params.require(:post).permit(:content)
end
50
51
52
53
def find_group
@group = Group.find(params[:group_id])
end
54
55
56
57
58
59
60
61
def member_required
if !current_user.is_member_of?(@group)
flash[:warning] = " You are not member of this group!"
redirect_to group_path(@group)
end
end
end
97
4 - User
98
Ch 4.1
2 3 Group Post
User model
1
2
has_many :group_users
has_many :participated_groups, :through => :group_users, :source => :group
2
3
4
has_many :groups
has_many :posts
5
6
7
has_many :group_users
has_many :participated_groups, :through => :group_users, :source => :group
8
9
extend OmniauthCallbacks
10
11
12
13
14
15
16
17
18
def join!(group)
participated_groups << group
end
4 - User
19
20
21
def quit!(group)
participated_groups.delete(group)
end
22
23
24
25
def is_member_of?(group)
participated_groups.include?(group)
end
26
27
end
99
4 - User
app/models/group.rb
1
2
has_many :group_users
has_many :members, :through => :group_users, :source => :group
2
3
4
5
6
7
8
9
10
11
12
13
14
def editable_by?(user)
user && user == owner
end
end
app/models/group_user.rb
1
2
3
4
Many to Many
1
2
has_many :group_users
has_many :members, :through => :group_users, :source => :user
100
4 - User
101
def join!(group)
participated_groups << group
end
4
5
6
7
def quit!(group)
participated_groups.delete(group)
end
8
9
10
11
def is_member_of?(group)
participated_groups.include?(group)
end
Group group
app/controller/groups_controller.rb create action current_user.join!(@group)
1
2
3
4
5
6
7
8
9
def create
@group = current_user.groups.build(group_params)
if @group.save
current_user.join!(@group)
redirect_to groups_path
else
render :new
end
end
ActiveRecord after_create
4 - User
1
102
2
3
4
5
6
7
has_many :group_users
has_many :members, :through => :group_users, :source => :user
8
9
10
11
12
after_create :join_owner_to_group
13
14
15
16
def editable_by?(user)
user && user == owner
end
17
18
19
20
def join_owner_to_group
members << owner
end
21
22
end
after_create
after_create ActiveRecord callbacks callbacks
before_create
before_update
after_create
after_update
4 - User
def join
@group = Group.find(params[:id])
3
4
5
6
7
8
9
10
if !current_user.is_member_of?(@group)
current_user.join!(@group)
else
flash[:warning] = "You already joined this group."
end
redirect_to group_path(@group)
end
11
12
13
def quit
@group = Group.find(params[:id])
14
15
16
17
18
19
if current_user.is_member_of?(@group)
current_user.quit!(@group)
else
flash[:warning] = "You are not member of this group."
end
20
21
redirect_to group_path(@group)
22
23
end
resources :groups do
member do
post :join
post :quit
end
resources :posts
end
app/views/groups/show.html.erb
103
4 - User
1
2
3
4
5
6
7
8
9
10
11
104
app/views/groups/show.html.erb
1
2
1
2
controller member_required
def member_required
if !current_user.is_member_of?(@group)
flash[:warning] = " You are not member of this group!"
redirect_to group_path(@group)
end
end
5 - Account
user account
user account
Group post
DESC
counter_cache count
ORM
http://railscasts.com/episodes/23-counter-cache-column
5 - Account
identical
invoke
exist
invoke
identical
invoke
identical
invoke
identical
invoke
invoke
identical
invoke
identical
app/controllers/account/groups_controller.rb
erb
app/views/account/groups
test_unit
test/controllers/account/groups_controller_test.rb
helper
app/helpers/account/groups_helper.rb
test_unit
test/helpers/account/groups_helper_test.rb
assets
coffee
app/assets/javascripts/account/groups.js.coffee
scss
app/assets/stylesheets/account/groups.css.scss
app/controllers/account/groups_controller.rb
1
2
3
4
5
6
7
def index
@groups = current_user.participated_groups
end
end
touch app/views/account/groups/index.html.erb
<div class="span12">
2
3
4
5
6
7
8
9
10
<table class="table">
<thead> <tr>
<td> # </td>
<td> Title </td>
<td> Descroption </td>
<td> Post Count </td>
106
5 - Account
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
config/routes.rb
1
2
3
namespace :account do
resources :groups
end
app/views/common/_user_nav.html.erb
<%= render_list :class => "dropdown-menu" do |li|
li << link_to("Logout",destroy_user_session_path, :method => :delete )
end %>
1
2
3
1
2
3
4
107
5 - Account
Ch 5.2 User
account/posts controllerrails g controller account/posts
create
invoke
create
invoke
create
invoke
create
invoke
create
invoke
invoke
create
invoke
create
1
2
3
4
5
6
7
8
9
10
11
12
13
14
app/controllers/account/posts_controller.rb
erb
app/views/account/posts
test_unit
test/controllers/account/posts_controller_test.rb
helper
app/helpers/account/posts_helper.rb
test_unit
test/helpers/account/posts_helper_test.rb
assets
coffee
app/assets/javascripts/account/posts.js.coffee
scss
app/assets/stylesheets/account/posts.css.scss
app/controllers/account/groups_controller.rb
1
2
3
before_action :login_required
4
5
6
7
def index
@posts = current_user.posts
end
8
9
end
108
109
5 - Account
touch app/views/account/posts/index.html.erb
1
<div class="span12">
2
3
<table class="table">
4
5
6
<thead>
<tr>
7
8
9
10
11
12
13
14
15
16
17
<tbody>
<% @posts.each do |post| %>
<tr>
<td>
<p>
<%= post.content %>
</p>
</td>
18
19
<td>
</td>
20
21
22
23
24
25
26
27
28
29
30
31
32
namespace :account do
resources :groups
resources :posts
end
5 - Account
app/common/_user_nav.html.erb
<%= render_list :class => "dropdown-menu" do |li|
li << link_to("My Group", account_groups_path)
li << link_to("Logout",destroy_user_session_path, :method => :delete )
end %>
1
2
3
4
1
2
3
4
5
110
5 - Account
111
Ch 5.3 DESC
My Post
app/controllers/account/posts_controller.rb
1
2
3
before_action :login_required
4
5
6
7
def index
@posts = current_user.posts.order("updated_at DESC")
end
8
9
end
5 - Account
112
<div class="span12">
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<tbody>
<% @groups.each do |group| %>
<tr>
<td> # </td>
<td> <%= link_to(group.title, group_path(group)) %> </td>
<td> <%= group.description %> </td>
<td> <%= group.posts.count %> </td>
<td> <%= group.updated_at %> </td>
</tr>
<% end %>
</tbody>
</table>
</div>
group.posts.count code SQL query
(0.2ms)
application count
groups table
posts_count create action posts_count +1
1
def create
2
3
4
@post = @group.posts.new(post_params)
@post.author = current_user
5
6
7
8
9
10
11
12
if @post.save
Group.increment_counter(:posts_count, @group.id)
redirect_to group_path(@group)
else
render :new
end
end
5 - Account
113
def destroy
2
3
4
@post = current_user.posts.find(params[:id])
@post.destroy
5
6
7
8
Group.decrement_counter(:posts_count, @group.id)
redirect_to group_path(@group)
end
Rails counter_cache
count posts_count
rails g migration add_posts_count_to_group
invoke
create
1
2
active_record
db/migrate/20130531183331_add_posts_count_to_group.rb
1
2
3
4
5
rake db:migrate
1
2
3
4
app/models/post.rb
1
5 - Account
114
def index
@groups = current_user.participated_groups.order("posts_count DESC")
end
6 - Refactor code
helper
partial
scope condition SQL query
6 - Refactor code
116
post.updated_at group.updated_at
date.to_s
simple_format
post.content
1
2
3
a
b
c
HTML
1
a b c
truncate
group.title
Rails truncate helper
<%= truncate(@group.title, :length => 17 ) %>
6 - Refactor code
117
Helper
HTML code View
Rails Helper
Helper
Post
1
6 - Refactor code
Helper
1
def render_post_content(post)
truncate(simple_format(post.content), :lenth => 100)
end
Partial
http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials
118
6 - Refactor code
119
Partial
long template | HTML highly duplicated | HTML
independent blocks |
nav/user_info
nav/admin_menu
vendor_js/google_analytics
vendor_js/disqus_js
global/footer
6 - Refactor code
project layout/application.html.erb
1
2
3
<div class="container">
4
5
6
7
8
9
10
11
<div class="content">
<div class="row">
<%= yield %>
<%= yield (:sidebar) %>
</div>
12
13
</div>
14
15
16
17
18
19
20
21
22
23
24
25
26
Partial
http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials
120
6 - Refactor code
121
2
3
4
5
def index
@posts = current_user.posts.order("updated_at DESC")
end
6
7
end
posts.order("updated_at DESC") View
Helper Query
2
3
4
5
def index
@posts = current_user.posts.recent
end
6
7
end
6 - Refactor code
Scope
1
2
3
4
2
3
before_action :login_required
4
5
6
7
def index
@posts = current_user.posts.published.hot
end
8
9
end
scope
http://edgeguides.rubyonrails.org/active_record_querying.html#scopes
122
7 - Rake db:seed
Rake
rake db db migration
rake Group
rake -T
task rake db:drop ; rake db:create ; rake db:migrate ; rake
db:seed
task rake dev:fake ( namespace : dev,
task fakefake Populator #
http://jasonseifer.com/2010/04/06/rake-tutorial
http://ryandaigle.com/articles/2009/5/13/what-s-new-in-edge-rails-database-seeding
7 - Rake db:seed
124
Ch 7.1 Rake
Rake Ruby MakeRuby Make Ruby Build Tool
Ruby compile Build Tool
Rake Build Tool task Ruby based
Rake Rails task
)
1
2
3
4
5
6
7
8
9
rake about
# List versions of all Rails frameworks and the environme\
nt
rake assets:clean
# Remove compiled assets
rake assets:precompile # Compile all the assets named in config.assets.precompile
rake db:create
# Create the database from config/database.yml for the cu\
rrent Rails.env (use db:create:all to create all dbs in the config)
rake db:drop
# Drops the database for the current Rails.env (use db:dr\
op:all to drop all databases)
.....
db migration
migration rake
lib/tasks/dev.rake
1
2
3
4
5
namespace :dev do
desc "Rebuild system"
task :build => ["tmp:clear", "log:clear", "db:drop", "db:create", "db:migrate"]\
task :rebuild => [ "dev:build", "db:seed" ]
end
rake dev:build
1
$ rake dev:build
rake dev:build
7 - Rake db:seed
125
rake db:seed
db/seed.rb
seed.rb rake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
post = board.posts.build(:title => "First Post", :content => "This is a demo post\
")
post.user_id = admin.id
post.save!
8 - deploy VPS
VPS Ruby on Rails production Ruby Enterprise Edition mod_rails Capistrano application
capistrano
cap deploy:setup
cap deploy
cap deploy:rollback
cap deploy:restart
rails-nginx-passenger-ubuntu
AWDR4 deploy
https://github.com/capistrano/capistrano/wiki
https://github.com/jnstq/rails-nginx-passenger-ubuntu
http://pragprog.com/titles/rails4/agile-web-development-with-rails
8 - deploy VPS
127
Ruby Ruby
Ruby RubyGemRails
RubyGem
Ruby
Rails Gem
compatible library CentOS package outdate
Ubuntu / Debian package
Best Practice
ImageMagick ( rmagick
gem) MySQL ( mysql2 gem) gem
VPS
enom.com
VPS Linode AWS EC2
micro instance
http://linode.com/
http://aws.amazon.com/ec2/
8 - deploy VPS
128
Ch 8.2 Capistrano
Capistrano 37 signals automate deploy tool Rails Developer
deploy application
Rails php
Rails Application server checkout migration
server memcached search daemon .
deploy
Capistrano Bootstrappets
recipe
config/deploy.rb
https://github.com/capistrano/capistrano/wiki
129
8 - deploy VPS
1
2
3
4
raw_config = File.read("config/config.yml")
APP_CONFIG = YAML.load(raw_config)
5
6
7
8
require "./config/boot"
require "bundler/capistrano"
require "rvm-capistrano"
9
10
default_environment["PATH"] = "/opt/ruby/bin:/usr/local/bin:/usr/bin:/bin"
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
set
set
set
set
set
set
:deploy_to, "/home/apps/#{application}"
:runner, "apps"
:deploy_via, :remote_cache
:git_shallow_clone, 1
:use_sudo, false
:rvm_ruby_string, '1.9.3'
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
set
set
set
set
:deploy_env, "production"
:rails_env, "production"
:scm_verbose, true
:use_sudo, false
8 - deploy VPS
130
43
44
45
namespace :deploy do
46
47
48
49
50
51
52
53
54
55
56
57
namespace :my_tasks do
task :symlink, :roles => [:web] do
run "mkdir -p #{deploy_to}/shared/log"
run "mkdir -p #{deploy_to}/shared/pids"
58
59
60
61
62
63
64
symlink_hash = {
"#{shared_path}/config/database.yml"
=> "#{release_path}/config/database.\
yml",
"#{shared_path}/config/s3.yml"
=> "#{release_path}/config/s3.yml",
"#{shared_path}/uploads"
=> "#{release_path}/public/uploads",
}
65
66
67
68
69
70
71
end
72
73
74
75
76
77
78
79
80
namespace :remote_rake do
desc "Run a task on remote servers, ex: cap staging rake:invoke task=cache:clea\
r"
task :invoke do
run "cd #{deploy_to}/current; RAILS_ENV=#{rails_env} bundle exec rake #{ENV['\
task']}"
end
end
81
82
8 - deploy VPS
131
Ch 8.3 Capistrano
cap deploy:setup
Capistrano Capistrano
cap deploy
Deploy
cap deploy:migrate
migration
cap deploy:rollback
deploy
cap deploy:restart
application
8 - deploy VPS
Rails 3
config/production.rb
1
2
config.serve_static_assets = false
config.assets.compile = false
Rails 4
Rails 4
1
2
3
4
5
6
config.serve_static_assets = true
config.assets.compile = true
config.assets.compress = true
config.assets.configure do |env|
env.logger = Rails.logger
end
132
Asset
Pipeline
SCSS
SCSS Asset CSS
1
2
SCSS
1
2
3
4
.content{
margin: 2em 0;
h1{font-size: 2em;}
}
CSS
Asset Pipeline
134
SCSS mixin
protyping
+
CSS
SCSS style
1
2
3
4
5
6
$border-color: #3bbfce;
$link-color: #3bbfcf'
.content{
border-color: $border-color;
a{ color: $link-color; }
}
1
2
Compass
SCSS Compass Framework mixin Developer
1
2
3
4
5
6
7
8
#border-radius {
-moz-border-radius: 25px;
-webkit-border-radius: 25px;
-o-border-radius: 25px;
-ms-border-radius: 25px;
-khtml-border-radius: 25px;
border-radius: 25px;
}
Compass
http://compass-style.org/
Asset Pipeline
1
#border-radius {
@include border-radius(25px); }
135
Asset Pipeline
136
CoffeeScript
Asset Pipeline CoffeeScriptCoffeeScript
CoffeeScript JavaScript Ruby Python
Plurk amix post CoffeeScript: The beautiful way to write
Javascript CoffeeScript
JavaScript
JavaScript
JavaScript functional language
OOP prototype-based JavaScript dynamic language Lisp
C/Java C/Java
Java Java
functional & dynamic laungaue Ruby / Python C / Java
syntax
CoffeeScript JavaScript
JavaScript
CoffeeScript JavaScript var
Protected code
CoffeeScript function JavaScript anonymous function:
function(){}(); function
JavaScript function(){}();
.
CoffeeScript JavaScript
http://jashkenas.github.com/coffee-script/
http://amix.dk/blog/post/19612
Asset Pipeline
137
syntax error
Javascript JavaScript
class
JavaScript OOP prototypefunction
Object
CoffeeScript
1
2
class Animal
constructor: (@name) ->
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
sam.move()
tom.move()
JavaScript OO
Asset Pipeline
138
Asset Pipeline
Asset Pipeline assets assets
app/assets
lib/assets
vendor/assets
assets application.css / application.js require
library
1
2
app/assets
Rails 3.1.x rails g controler posts assets/styelsheets/ assets/javascripts/ scss coffeescript app/assets
assets
lib/assets
lib library LIBRARY assets
library mixin bootstrap lib/
vendor/assets
verdor assets :
jquery.*.js
fanfanfan icons
tinymce / ckeditor
Asset Pipeline
139
framwork COPY
Asset Pipeline
140
Rails 3
Rails 3 asset gem asset group
1
2
3
4
5
6
group
gem
gem
gem
gem
end
:assets do
'sass-rails',
'~> 3.2.3'
'coffee-rails', '~> 3.2.1'
'uglifier', '>= 1.0.3'
"compass-rails"
Rails 4
Rails 4 gem asset group compass
1.1.2 gem compass
1
2
3
4
gem
gem
gem
gem
Asset Pipeline
141
rvm
pow
CRUD
RESTFUL
RESTFUL
Devise)
Scope
Helper
Partial
Capistrano
Asset Pipeline
Ruby Rails /
Learning Rails
Application
Code School Rails for Zombies Redux
Code School Rails for Zombies 2
http://www.codeschool.com/courses/try-ruby
http://www.codeschool.com/courses/try-git
http://www.codeschool.com/courses/git-real
https://peepcode.com/screencasts
https://peepcode.com/products/advanced-command-line
http://ruby.learncodethehardway.org/
http://www.codeschool.com/courses/rails-for-zombies-redux
http://www.codeschool.com/courses/rails-for-zombies-2
https://www.codeschool.com/courses/try-jquery
https://www.codeschool.com/courses/javascript-road-trip-part-1
https://www.codeschool.com/courses/javascript-road-trip-part-2
http://www.codeschool.com/courses/css-cross-country
http://www.codecademy.com/zh/tracks/javascript
Ruby on Rails
TDD
Michael Hartl Rails Turtorial
Ryan Bigg Rails in Action 4
UT on Rails is also a excellent learning material
Schneems UT on Rails
Testing
Code School Rails testing for zombies
Code School Testing with Rspec
Noel Rappin Rails Test Prescriptions: Keeping Your Application Healthy
Thougutbot Learn Test-Driven Development using RSpec and Capybara.
http://ruby.railstutorial.org/
http://www.manning.com/bigg2/
http://schneems.com/ut-rails
http://www.codeschool.com/courses/rails-testing-for-zombies
http://www.codeschool.com/courses/testing-with-rspec
http://pragprog.com/book/nrtest/rails-test-prescriptions
https://learn.thoughtbot.com/workshops/18-test-driven-rails
http://www.codeschool.com/courses/journey-into-mobile
http://www.codeschool.com/courses/anatomy-of-backbonejs
http://www.codeschool.com/courses/coffeescript
http://www.codeschool.com/courses/assembling-sass
http://www.codeschool.com/courses/assembling-sass
143
144
Ruby code
145
Rails
Jos Valim Crafting Rails Applications: Expert Practices for Everyday Rails Development
Marc-Andr Cournoyer Owning Rails: The Rails Online Master Class
Railscast Rails Initialization Walkthrough
Railscast Rails Middleware Walkthrough
Railscast Rack App from Scratch
Railscast Rails Modularity
Railscast Hacking with Arel
Railscast Authorization from Scratch Part 1
Railscast Authorization from Scratch Part 2
Railscast Action Controller Walkthrough
Railscast Action View Walkthrough
https://learn.thoughtbot.com/products/13
http://objectsonrails.com/
http://www.amazon.com/Design-Patterns-Ruby-Russ-Olsen/dp/0321490452
http://www.amazon.com/Design-Patterns-Ruby-Russ-Olsen/dp/0321490452
http://www.amazon.com/dp/0321721330
http://pragprog.com/book/jvrails/crafting-rails-applications
http://owningrails.com/
http://railscasts.com/episodes/299-rails-initialization-walkthrough
http://railscasts.com/episodes/319-rails-middleware-walkthrough
http://railscasts.com/episodes/317-rack-app-from-scratch
http://railscasts.com/episodes/349-rails-modularity
http://railscasts.com/episodes/355-hacking-with-arel
http://railscasts.com/episodes/385-authorization-from-scratch-part-1
http://railscasts.com/episodes/386-authorization-from-scratch-part-2
http://railscasts.com/episodes/395-action-controller-walkthrough
http://railscasts.com/episodes/397-action-view-walkthrough
Resources of latest Ruby
Ruby5
Ruby Weekly
Ruby Inside
RubyFlow
RubyRogues
Thoughtbot Podcast
Railscast
Confreaks
http://ruby5.envylabs.com/
http://rubyweekly.com/
http://www.rubyinside.com/
http://www.rubyflow.com/
http://rubyrogues.com/
http://learn.thoughtbot.com/podcast
http://railscasts.com/
http://www.confreaks.com/