RailsCasts

1.caching with instance variables
2.dynamic find_by methods
3.find through association
4.move find into mode
5.using with_scope
6.Shortcut Blocks with Symbol to_proc
7.All About Layouts
8.Layouts and content_for
9.Filtering Sensitive Logs
10.Refactoring User Name Part 1
11.Refactoring User Name Part 2
12.Refactoring User Name Part 3
13.Dangers of Model in Session
14.Performing Calculations on Models
15.Fun with Find Conditions
16.Virtual Attributes
17.HABTM Checkboxes
18.Looping Through Flash
19.Where Administration Goes
20.Restricting Access
21.Super Simple Authentication
22.Eager Loading
23.Counter Cache Column
24.The Stack Trace
25.SQL Injection
26.Hackers Love Mass Assignment
27.Cross Site Scripting
28.in_groups_of
29.group_by Month
30.Pretty Page Title
31.Formatting Time
32.Time in Text Field[未实现]
33.Making a Plugin
34.Named Routes
35.Custom REST Actions
36.Subversion on Rails
37.Simple Search Form
38.Multibutton Form
39.Customize Field Error
40.Blocks in View
41.Conditional Validations
42.with_options

46.Catch-all Route
47.Two Many-to-Many
48.Console Tricks【有更新】
49.Reading the API
50.Contributing to Rails
51.will_paginate
52.Update through Checkboxes
53.Handling Exceptions(未实现)
54.Debugging Ruby
55.Cleaning Up the View
56.The Logger
57.Create Model Through Text Field
58.How to Make a Generator(未实现)
59.Optimistic Locking
60.Testing without Fixtures
61.Sending Email

64.Custom Helper Modules

67.restful_authentication

70.Custom Routes

72.Adding an Environment

78.Generating PDF Documents

80.Simplify Views with Rails 2.0
81.Fixtures in Rails 2.0
82.HTTP Basic Authentication
83.Migrations in Rails 2.0

85.YAML Configuration

89.Page Caching
90.Fragment Caching

96.Git on Rails
97.Analyzing the Production Log

109.Tracking Attribute Changes

111.Advanced Search Form

113.Contributing to Rails with Git

116.Selenium

120.Thinking Sphinx

126.Populating a Database

134.Paperclip

139.Nested Resources

155.Beginning with Cucumber
156.Webrat

158.Factories not Fixtures
159.More on Cucumber
160.Authlogic

169.Dynamic Page Caching

179.Seed Data
180.Finding Unused CSS

182.Cropping Images

187.Testing Exceptions
188.Declarative Authorization
189.Embedded Association
190.Screen Scraping with Nokogiri
191.Mechanize

200.Rails 3 Beta and RVM
201.Bundler
202.Active Record Queries in Rails 3
203.Routing in Rails 3
204.XSS Protection in Rails 3

206.Action Mailer in Rails 3
207.Syntax Highlighting

209.Devise
210.Customizing Devise

225.Upgrading to Rails 3 Part 1
226.Upgrading to Rails 3 Part 2
227.Upgrading to Rails 3 Part 3

231.Routing Walkthrough Part 1
232.Routing Walkthrough Part 2

234.SimpleForm

239.ActiveRecord::Relation Walkthrough

244.Gravatar

250.Authentication from Scratch

253.CarrierWave File Uploads
254.Pagination with Kaminari

257.Request Specs and Capybara

264.Guard

270.Authentication in Rails 3.1

272.Markdown with Redcarpet

274.Remember Me & Reset Password
275.How I Test

278.Search with Sunspot

282.Upgrading to Rails 3.1
283.Authentication with Sorcery

285.Spork

299.Rails Initialization Walkthrough

305.Authentication with Warden

308.Oh My ZSH

314.Pretty URLs with FriendlyId

318.Upgrading to Rails 3.2
319.Rails Middleware Walkthrough

328.Twitter Bootstrap Basics

368.MiniProfiler

372.Bullet

374.Image Manipulation

382.Tagging

385.Authorization from Scratch Part 1
386.Authorization from Scratch Part 2

395.Action Controller Walkthrough

397.Action View Walkthrough

411.Performance Testing
412.Fast Rails Commands
413.Fast Tests

415.Upgrading to Rails 4

417.Foundation

1. caching with instance variables

实现的代码如下所示:

class ApplicationController < ActionController::Base 
  def current_user
    @current_user ||= User.find(session[:user_id]) 
  end
end

如果按照如下的代码:

class ApplicationController < ActionController::Base 
  def current_user
    User.find(session[:user_id]) 
  end
end

每次查询用户的时候都需要调用数据库,为了避免每次都调用数据库的行为,进行如下的优化:

@current_user ||= User.find(session[:user_id]) 

上面的代码等于于

@current_user = @current_user || User.find(session[:user_id]) 

当首次使用current_user方法的时候,@current_user的值为nil,则进行数据库调用,User.find(session[:user_id])会赋值给@current_user,当第二次调用current_user方法的时候,不会使用User.find(session[:user_id])方法,即不会调用数据库,直接使用被赋值后的@current_user。
注意:用户退出的时候设置@current_user=nil

2. dynamic find_by methods
这里的find_by无效,如果要获得数组数据,需要使用where方法

#建立模型
rails g model Task complete:string uncomplete:string
rails destroy model Task  #取消建模

Task.find(complete: "false") #该方法会报错,因为find方法里面只能出现id的值
Task.find_by(complete: "false")#该方法只有一个返回值,见api所示,因此在这个结果调用each方法则会报错,因为该对象没有each方法
Task.where("complete = ?", "false"),该方法返回全部为false值的数组对象,因此该结果可以调用each方法,而上面Taks.find_by方法只返回满足条件的第一个值。

3. find through association
在project中有很多的tasks,进行关联查询:

class Project < ActiveRecord::Base 
  has_many :tasks
end

class Task < ActiveRecord::Base
  belongs_to :project
end

对于存在association的model中,如果查询某个project中的task,使用下面的语句和代码:

class ProjectsController < ApplicationController 
  def show 
    @project = Project.find(params[:id]) 
    @tasks = @project.tasks.where("complete = ?", "false")
  end
end

4. move find into model
将查询方法置于model中,在controller中可以被多次调用,避免代码重复,代码如下所示:

class Task < ActiveRecord::Base
  def self.uncomplete
    where(complete: "false")
  end
end

class TaskController < ApplicationController
  def index
    @tasks = Task.uncomplete
  end
end

5. using with_scope
with_scope方法在最新api文档里面已经找不到了,相同功能的方法叫做scope,详细的用法在自己的一篇关于tag的文章中也有阐述,大概的使用功能及代码可以见下面所示,即是使用scope创建自定义的方法:

rails g scaffold Article name:string content:text

#model/article.rb
class Article < AcriveRecord::Base
  scope :test, lambda{|name| where("name = ? ", name)}
end

#rails console
Article.test("demo")

6. Shortcut Blocks with Symbol to_proc
在如下代码中:

class Project < ActiveRecord::Base
  def self.all_names
    all.collect(&:name) 
  end
end

#终端查询
Project.all_names #返回所有的Project表中的name值

#下面的等价形式是rails对ruby的扩充
all.collect(&:name)
all.collect{|p| p.name} #这是等价代码,只返回只有name的值

#ruby形式的(&:name)
array.uniq(&:first).sort_by(&:last)
array.uniq{|a|.a.first}.sort_by{|x|x.last}
#就是按照数据的第一个元素去重,然后按照数组的第二个元素排序

#作用:实现链式调用
all.collect(&:name).collect(&:upcase)

#除了collect,也可以应用在其他地方
#对每一个值进行遍历,并对其进行求值valid?,如果其中任何一个返回为true,则整个值返回为true
#valid?是rails方法,通过validate方法则说明有效
projects.all?(&:valid?)
projects.any?(&:valid?)

#同collect,进行遍历
projects.each(&:save!)

7. All About Layouts
介绍各种布局形式
1.默认布局
默认的布局形式在views/layouts/application.html.erb文件中
2.自定义布局,针对某个资源有效
建立views/layouts/admin.html.erb文件

#articles_controller.rb文件
class ArticlesController < ApplicationController
  #使用admin布局
  layout "admin"
end

3.自定义布局,针对某个具体的action有效
如果只是针对某个action生效,可以在controller文件中写入如下的代码:

render layout: 'admin'

4.消除布局

render layout: false

5.动态布局

class ProjectsController < ApplicationController 
  layout :user_layout 
  
  def index 
    @projects = Project.find(:all) 
  end 
  
  protected 
  def user_layout 
    if current_user.admin? 
      "admin" 
    else 
      "application" 
    end 
  end
end

8. Layouts and content_for
使用content_for方法对单个的页面进行样式重置,实用性不太,因为基本的单个页面的布局已经可以通过layouts布局进行实现,遇到content_for案例再进行细究。
疑问:下面的案例提供引用两个css文件没有必要,因为rails4.2所有的css文件最终都变成一个css文件被导入。

#需要重置样式的页面,比如index.html.erb文件中
<% content_for :head do %> 
  <%= stylesheet_link_tag 'projects' %>
<% end %>

#在application.html.erb文件中写入如下代码
<head>
  <%= yield :head %>
</head>

<body>
  <%= yield %>
</body>

结合rails的api可以看出content_for方法是将一个block储存起来,以备未来使用,当执行到index,html.erb文件中中时,出现如下的代码呈现形式:

<head>
  <%= stylesheet_link_tag 'projects' %>
</head>

9. Filtering Sensitive Logs
按照railscast中的说明,对于敏感字段password而言,应该在下面的代码中进行设置:

class ApplicationController < ActionController::Base
  filter_parameter_logging "password" 
end

但是在rails4.2的项目中,filter_parameter_logging方法会报undefined method错误,应该是rails4.2中,对这个方法进行了舍弃,参考此文,进行如下设置:

#config/initializers/filter_parameter_logging.rb
Rails.application.config.filter_parameters += [:password] #其实是rails的默认设置

按照上面的设置,在log/development.log文件中,password字段显示的值为[FILTERED]

10. Refactoring User Name Part 1
对前端页面进行优化的方式,是将方法设置在model中,然后在view层进行调用,比如在model中建立full_name方法:

#first_name,middle_name,last_name是Uers的三个属性
class User < ActiveRecord::Base 
  def full_name
    name = first_name + ' ' 
    name += "#{middle_initial}. " unless middle_initial.nil? 
    name += last_name 
    name
  end
end

11. Refactoring User Name Part 2
对full_name方法还可以进行优化,代码如下所示:

def full_name 
  [first_name, middle_initial_with_period,last_name].compact.join(' ')
end

def middle_initial_with_period
   "#{middle_initial}." unless middle_initial.blank?
end

12. Refactoring User Name Part 3
对测试进行优化,代码如下所示:

require 'test_helper'
class UserTest < ActiveSupport::TestCase 
  test "full name" do 
    #其中“nil middle initial”如果出错会显示这条语句
    assert_equal "John Smith", full_name('John', nil, 'Smith'), 'nil middle initial' 
    assert_equal 'Paul P. Hughes', full_name('Paul', 'P', 'Hughes'), 'P middle initial' 
    assert_equal "John Jones", full_name('John', '', 'Jones'), 'blank middle initial' 
  end 

  def full_name(first, middle, last) 
    User.new(:first_name => first, :middle_initial => middle, :last_name => last).full_name 
  end
end

13. Dangers of Model in Session
这部分知识阐述的是不要将数据存储在session中,容易造成数据的不同步现象,合理的方式是讲在session中存储id值,代码如下所示:

class UserController < ApplicationController
  def prepare
    session[:user_id] = User.find(:first).id
    redirect_to :action => :'show' 
  end 
  
  def show 
    @user = User.find(session[:user_id]) 
  end 
  
  def update 
    @user = User.find(session[:user_id]) 
    @user.name = 'Foo' 
    redirect_to :action => 'show' 
  end 
end

14. Performing Calculations on Models
在ActiveRecord中预制了对数据进行统计的方法,如下所示:

rails scaffold Calculation priority:integer
Calculation.first.priority #查第一个数值
Calculation.sum(:priority)  #查平均数值
Calculation.minimum(:priority)  #查最小数值
Calculation.maximum(:priority) #查最大数值
Calculation.average(:priority).to_f #查平均数值

15. Fun with Find Conditions
使用ActiveRecord的条件查询,代码如下所示:

User.where(["name = ? and email = ?", "Joe", "joe@example.com"])
User.where(["name = :name and email = :email", { name: "Joe", email: "joe@example.com" }])

16. Virtual Attributes
一般情况下,在rails中,model中的属性要和数据库中的字段相对应,如果model中的属性没有和数据库的字段相对应,则这个属性就被称为虚拟属性,通用版本如下:

#字段如下:
create_table "users", :force => true do |t| 
  t.string "first_name" 
  t.string "last_name" 
  t.string "password" 
end

#表单如下:
<h1>Register</h1> 
<% form_for @user do |form| %> 
  <ol class="formList"> 
    <li> <%= form.label :full_name, 'Full Name' %> <%= form.text_field :full_name %> </li> 
    <li> <%= form.label :password, 'Password' %> <%= form.password_field :password %> </li> 
  </ol> 
<% end %>

#model如下:
class User < ActiveRecord::Base 
# Getter  
  def full_name 
    [first_name, last_name].join(' ') 
  end 
# Setter  
  def full_name=(name) 
    split = name.split(' ', 2) 
    self.first_name = split.first 
    self.last_name = split.last 
  end 
end

更新后的版本如下:

for example

17. HABTM Checkboxes
场景是为一个model添加多个可选tag

rails g scaffold product name:string content:text
rails g scaffold category name:string
rails g scaffold categorization product_id:integer category_id:integer 
#model
class Product < ActiveRecord::Base
  has_many :categorizations
  has_many :categories, through: :categorizations
end

class Category < ActiveRecord::Base
  has_many :categorizations
  has_many :products, through: :categorizations
end

class Categorization < ActiveRecord::Base
  belongs_to :product
  belongs_to :category
end

#controller
def product_params
  #需要添加强参{category_ids:[]}
  params.require(:product).permit(:name, :content, {category_ids: []})
end

#view
<div class = "field">
  #如果不添加hidden_field_tag参数,则勾选已经有的tag,则该tag不会删除
  <%= hidden_field_tag "product[category_ids][]", nil %>
  <% Category.all.each do |category| %>
   #下面product[category_ids][]的依据可以参考rails guides的内容
  <%= check_box_tag "product[category_ids][]", category.id, @product.category_ids.include?(category.id) %>
  <%= category.name %></br>
  <% end %>
</div>

18. Looping Through Flash
一般在使用flash的时候都会迭代显示里面的信息,自己在实践的过程中按照如下代码进行设置和呈现:

#在controller文件中
def create
  if @user.save
    flash[:success] = "congratulation"
    .....
  end
end

#在application.html.erb文件中,进行如下的代码呈现
<% flash.each do |key, value| %>
  <%= key %>:<%= value%>
<% end %>

在本文的呈现中,flash在前端页面的呈现如下所示:

#关注api中content_tag的使用
<% flash.each do |key,msg| %> 
  <%= content_tag :p, msg, :id => key %>
<% end %>

**19. Where Administration Goes **

20. Restricting Access

21. Super Simple Authentication
以上这三个章节是介绍权限管理系统,我认为里面的提到很多方法和实际的rails4.2版本已经过时,但是思想是一致的,建立admin方法,对前端页面的展示进行过滤和分别呈现,现在比较合适的解决方案在ruby on rails tutorial第三版中能找到。

22. Eager Loading
eager loading的意思是贪婪加载,使用的场景出现在“1+N”的情形中,解决的方式是通过joins和includes方法对两个mode进行关联
joins 在数据库中表示: left outer join
includes 在数据库中表示: innner outer join
代码参考guides中的代码:

#从includes中的单复数判断,category has many articles, article has many comments
Article.includes(:category, :comments)

#出现嵌套形式
#category has many articles
#artilce has many comments and tags
#guest has many comments
Category.includes(articles: [{ comments: :guest},:tags])

#关联之后指定条件,下面两条内容一致
#使用hash形式
Article.includes(:comments).where(comments: { visible: true })
#使用string形式必须指定references
Article.includes(:comments).where("comments.visible = true").references(:comments)

#进行排序order
#tag has many articles
Article.joins(:tag).order("articles.name")
Article.joins(:tag).order("tags.name")

23. Counter Cache Column
出现的场景如下所示:

Class Article < ActiveRecord::Base
  has_many :comments
end

Class Comment <ActiveRecord::Base
  belongs_to :article
end

在一篇文章中,有很多的评论,如果每一篇文章的评论数量,在执行下面的语句的过程中会有进行大量的数据库查询:

<% @articles.each do |article| %> 
  <li><%= article.name %> (<%= article.comments.size %)</li> 
<% end %>

解决的方式如下所示:
参考此文

#增加
rails g migration add_comments_count_to_article comments_count:integer

#修改表格
class AddCommentsCountToArticle < ActiveRecord::Migration
  def change  
    add_column :articles, :comments_count, :integer, :default => 0
    #如果不执行下面的语句,则article.comments.size的值都是增加了该字段之后的数据
    Article.pluck(:id).each do |i|
      Article.reset_counters(i, :articles) # 全部重算一次
    end
  end
end

#添加counter_cache=>true值
class Comment < ActiveRecord::Base
  belongs_to :article, :counter_cache => true
end

使用@article.comments.size,就会自动变成使用@article.comments_count
log/development.log文件中出现下面语句:

#只调用了一次数据库而已
Article Load (0.1ms)  SELECT "articles".* FROM "articles"

24. The Stack Trace

25. SQL Injection
参考
经过实践下面的代码:

@articles = Article.where("name like '#{params[:search]}%'")

如果在输入框中输入

';drop table demo;

这样子会报错误,但是其实drop table demo的语句是不会执行的,这样子的错误也就是SQL注入错误。解决的方式是通过Array或者Hash的形式:

Article.where( { :name => params[:search] } )
# or
Article.where( ["name = ?", params[:search] ] )

在执行下面的查询方法的过程中,都需要使用上面的形式来规避SQL注入问题:

find_by_sql
execute
where 用字串参数
group
order

26. Hackers Love Mass Assignment
在之前版本的rails系统中其实有mass assignment,这个功能很方便,但是用户可以从url中操作而恶意改变数据库中的数据,因此为了继续使用mass assignment同时规避恶意窜改数据,而使用strong paramete方式,比如User这个model中有三个字段,包括name,age,admin,其中admin是敏感字段,因此将name,age两个字段放入mass assignment中,具体代码实现如下,admin字段通过其他方式实现数据输入。

def user_params
  params.require(:user).permit(:name,:age)
end

27. Cross Site Scripting
这个问题主要是用户在提交内容的时候提交了可以运行的脚本文件,在rails3之后对这写脚本文件进行了禁止,因为在最新的rails项目上其实这个问题已经不存在了,因为默认对XSS(脚本跨站攻击),如果显示用户提交的脚本内容并且进行呈现,有下面的几种方式:

#第一种:使用raw
raw("<p>safe</p>")
#第二种:使用html_safe
"<p>safe</p>".html_safe
#第三种:使用sanitize,一般情况下显示脚本使用这个方法
这个方法是应用白名单(认为有些参数是安全的,有限进行应用)的功能

28. in_groups_of
这个场景主要应用在数据多列展示,在传统的数据展示中,是按照单列进行数据展示,但是应用了这个方法可以对数据进行多列展示,如下代码:

 <% @articles.in_groups_of(3) do |articles|%>
   <tr>
     <% articles.each do |article| %>
       <td><%= article.name %></td>
     <% end %>
  </tr>
 <% end %>
#上面的代码显示的是按照3列进行数据排列,但是如果如果出现空缺的话,会出现undefined method for NilClass错误,避免这个错误,可以添加可选参数
#当选择false作为可选参数时,则空项为空显示
<% @articles.in_groups_of(3, false) do |articles| %>
#也可以选择其他参数,其他参数作为填充使用,出现空项,则填充该数据
<% @articles.in_groups_of(3, "demo") do |article|%>

rails console
(1..10).to_a.in_groups_of(3, "demo") #显示列如下:
[1,2,3]
[4,5,6]
[7,demo, demo]
#注意,经过实际演示,结果与api中演示不一致,说明api中数据陈列方式有误

29. group_by Month
railscast中的这篇东西比较烦,原理和例子可以参考这篇

>> a=(1..20).to_a=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
>> a.group_by{|num| num/5}=> {0=>[1, 2, 3, 4], 1=>[5, 6, 7, 8, 9], 2=>[10, 11, 12, 13, 14], 3=>[15, 16, 17, 18, 19], 4=>[20]}>> 

从上面的代码可以得知,通过一个block提出的条件将一个数组转化为一个hash。hash的key是数组元素执行block之后得到的结果,value是原数组中执行block得到key的元素组成的数组。
应用代码如下所示:

#controller文件中
@students=Student.find(:all)
@student_groups=@students.group_by{|s| s.gender}

#view文件中
<% @student_groups.each do |gender,students| %>
  <%= gender %>
  <ul>    
    <% students.each do |student| %>
    <li>
      <%= student.name%>
    </li>
    <% end %>
  </ul>
<% end %>

#执行结果如下所示:
female
 .lucy
 .jessi

malejack
 .jim
 .mike

30. Pretty Page Title
应用场景:对显示的每一篇文章,浏览器的显示标题栏应该是文章的题目,具体的代码演示如下:

rails g scaffold Article name:string content:text

#使用episode8中使用的content_for方法,保存块以备后用
module ApplicationHelper
  def title_name(title_name)
    content_for(:title){title_name}
  end
end

#在application.html.erb文件中写入如下代码
<head>
  <title>
    <% yield(:title)%>
  </title>
</head>

#articles/show.html.erb文件中写入如下代码
<% title_name(@article.name)%>

31. Formatting Time
两种方式来对资源中的时间进行格式化,具体代码如下:

#第一种:直接在view层写如下代码
article.created_at.strftime(“%F %T”)
#第二种:在config/environment.rb文件中添加配置信息
Time::DATE_FORMATS[:time] = "%F %T"
view中调用该方法
article.created_at.to_s(:time)

32. Time in Text Field
这个片段的是出现在编辑时间字段的时候,将时间字段集中在一个字符框中进行,而不是在多个选框中进行。
出现时间选框的代码如下:

rails g scaffold Article name:string time:datetime

33. Making a Plugin
使用最新的文档进行plugin的代码演示,然后回过头来看这边的代码,关于plugin制作的格式可以参考最新的,但是这个片段中的代码的一些方法可以参考如何使用。

34. Named Routes
视频中信息陈旧,可以参考rails guides中的内容,具体代码如下所示:

#url打开/test,获得welcome#index的值
get 'test', to: 'welcome#index', as: :demo
#url代开 welcome/index,也会返回welcome#index的值
get  'welcome/index', as: :demo

上述的两个route的值,可以生成两个命名路由,分别是demo_path,和demo_url,前者可以生成当前路径,后者会生成全路径。

35. Custom REST Actions
视频信息陈旧,主要讲的是通过一般情况下如下的代码其实可以实现一般的路由设置,代码如下所示:

resources :articles

但是这个资源只能实现index,show,edit,new,update,destroy,create这七个action,对于如果要在资源中设置其他的action需要自己设定,代码如下:

#在controller中进行设置
class ArticlesController < ApplicationController
  def search
  end
end
#在route.rb中进行设置
resources :photos do
  collection do
    get 'search'
  end
end
#或者如下形式:
resources :photos do
  get 'search', on: :collection
end
#上面的代码会形成如下的语句:
/photos/search
search_photos_url
#在views中建立test.html.erb文件

36. Subversion on Rails

37. Simple Search Form
这个章节的内容主要做一个简单的全文检索,然后我自己在此基础上扩展功能,从单字段的检索发展到多字段的检索。
简单的全文检索代码如下所示:

#projects/index.html.erb
#和form_for不同,form_for需要model,而form_tag不需要#model,因此对于需要
#model的form_for,若或许参数是通过params[:session][:email],
#而对于不需要model的form_tag,获取参数只需要params[:search]
<%= form_tag projects_path, :method => 'get' do %>
  <p>
    <%= text_field_tag :search%>
    <%= submit_tag "Search" %>
  </p>
<% end %>

#projects_controller.rb

def index
  @projects = Project.search(params[:search])
end

#models/project.rb

def self.search(search)
    #这是针对name这个单字段的检索
    where (["name LIKE ?", "#{search}%"])
    #下面是针对name和content两个字段的检索
    where(["name like ? or content like ?", "#{search}%", "#{search}%"])
end

38. Multibutton Form
这个场景主要出现在对文章进行预览,代码如下所示:

#终端执行下面的代码
rails g scaffold Article name:string content:text

#在controller中改写如下代码
def create
  @article = Article.new(article_params)
  #如果params[:preview_button]存在,则后面的!@article.save不执行,如果params[:preview_button]不存在,则执行后面的语句
  if params[:preview_button] || !@article.save
    render 'new'
  else
    flash[:notice] = "successfully created project"
    redirect_to @article
  end
end

#在new.html.erb中改写如下代码:
<% if params[:preview_button]%>
  <%= @article.content%>
<% end %>

#在form表单中添加预览表单
<%= submit_tag "Preview", name: "preview_button" %>

39. Customize Field Error
这个章节的内容应用场景是当对某个字段进行validates的时候,这个字段在内容显示的时候自动被下面的样式所包围:

<div class="field_with_errors">
  <label for="article_name">
    Name
  </label>
</div>

为了改变这个scaffold自动生成的样式,可以进行如下的调整:
两篇参考分别是参考一参考二

#config/environment.rb添加如下代码:
#下面的代码会将class= "field_with_errors"这个class进行去除
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| 
  "#{html_tag}".html_safe
end
#如果要编程其他样式的话,比如将class设置为field_error,见如下代码:
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| 
  "<span class='field_error'>#{html_tag}</span>".html_safe
end

按照参考一内容,也可以通过下面的形式设置:

.field_with_errors {display: inline;}

40. Blocks in View

41. Conditional Validations
这个场景出现选择某个情景进行验证的情况下,具体代码呈现如下:

rails g scaffold Article name:string content:text

#article.rb文件中
class Article < ActiveRecord::Base
  #下面这条语句在进行@article.save的过程中就会执行
  validates :name, presence:true
  #下面这条语句只有在方法is_test?为真的情况下才会执行
  validates :content, presence:true, if: :is_test?

  def is_test?
    false
  end
end

42. with_options
这个功能主要是为了避免代码重复,演示代码如下所示:

#article.rb文件中
class Article < ActiveRecord::Base
  validates :name, presence:true, if: :is_test?
  validates :content, presence:true, if: :is_test?

  def is_test?
    false
  end
end

使用with_options减少重复代码:

class Article < ActiveRecord::Base
  with_options if: :is_test? do |user|
    user.validates :name, presence:true
    user.validates :content, presence:true
  end

  def is_test?
    false
  end
end

46. Catch-all Route
这个应用场景是使用类似正则表达式的方式匹配路由,对于任何满足正则表达式的路由,都匹配该路径。代码如下所示:

#route.rb文件中
get "demos/*other", to: "demos#unknow"

#controller文件中
def unknow
end

#建立unknow.html.erb文件

47. Two Many-to-Many
讲述两种方式,在自己的博客tag文中有详细讲述,这里就不展开,核心代码如下:

has_and_belongs_to_many
belongs_to
has_many through

48. Console Tricks
有更新
49. Reading the API

50. Contributing to Rails
视频不用看,已经陈旧。
最新的文档

51. will_paginate
自己比较喜欢bootstrap这个js框架,所以做开发的时候一般前端产品都用这个。使用will_paginate这个gem的详细代码如下所示:
下面的代码因为涉及到配置文件,需要重启才能有效。

#添加gem 
gem 'will_paginate-bootstrap'

#controller中添加如下代码
@blogs = current_user.blogs.paginate(:page => params[:page], :per_page => 5)

#view中进行代码显示
<%= will_paginate @blogs %>

#定制
在config/initializers中生成will_paginate.rb文件,写入下代码
WillPaginate::ViewHelpers.pagination_options[:previous_label ] = "前一页" 
WillPaginate::ViewHelpers.pagination_options[:next_label ] = "后一页"

52. Update through Checkboxes
场景:应用在批量对属性进行更新
具体代码如下:

#终端执行
rails g scaffold Task name:string success:boolean

#根据success的情况将task分为complete和uncomplete
#controller中
@completes = Task.where("success = ?", true)
@uncompletes = Task.where("success= ?" false)

#接下来批量对success为false的task进行更新
#routes.rb文件中
routes :tasks do
  patch "complete", on: :collection
end

#在view文件中
<%= form_tag complete_tasks_path, method: :patch do %>
  <ul>
    <% @uncompletes.each do |uncomplete| %>
      <li>
        <%= check_box_tag "uncomplete_ids[]", uncomplete.id %>
        <%= uncomplete.name %>
     </li>
   <% end %>
 </ul>
<%= submit_tag "mark as complete" %>

#controller文件中
def complete
  Task.where(id: params[:uncomplete_ids]).update_all(success: true)
  redirect_to tasks_path
end



53. Handling Exceptions
54. Debugging Ruby
这个章节主要是如何进行调试,在ruby2.0以前,使用的是debugger这个gem,在ruby2.0以后,使用的是byebug这个gem,该代码是示例和使用方式如下:

rails g scaffold Task name:string due_at:datetime

#建立controller文件
class TasksController < ApplicationController 
  def index 
    debugger
    @today_tasks = Task.due_on(Date.today) 
    @tomorrow_tasks = Task.due_on(Date.tomorrow) 
  end
end

#建立model文件
class Task < ActiveRecord::Base 
  def self.due_on(date) 
    range = date.to_time...(date+1).to_time 
    where(due_at: range) 
  end
end

#进行调试
在想要进行调试的地方增加下面的语句
debugger

help # 查看哪些方法
next # 执行需要调试的下一条语句
pp @today_tasks #打印这条值
step #进入该方法中的内部方法,如果不是自己想要的,可以执行next,可以跳到该方法中的另外一个方法
irb  #可以在平台中执行该语句puts where(due_at: range).to_sql

byebug的其他用法可以见API
55. Cleaning Up the View
这个章节的内容主要讲的是消除前端的臃肿,把逻辑代码放在controller或者是model中。具体的代码案例来自于agile development with rails.

56. The Logger
在log文件中查看程序中的执行情况,代码如下:

def index 
  @articles = Article.all 
  logger.debug "Articles Count: #{Article.count}"
end

设置log等级,大于或者等于这个等级的log才能被载入:

#/config/environments/development.rb
config.log_level = :warn
#等级依次为:debug, :info, :warn, :error, :fatal, and :unknown

给log设置标签

#/config/environments/development.rb
Blog::Application.configure do 
  config.log_tags = ["Hello World"] 
  #或者如下
  config.log_tags = [:uuid, :remote_ip]
  #也可以添加块
  config.log_tags = [:uuid, :remote_ip, lambda { |req| Time.now }]
end

格式化输入标签内容

#/config/initializers/log_formatter.rb
class Logger::SimpleFormatter 
  def call(severity, time, progname, msg) 
    "[#{severity}] #{msg}\n"
  end
end

不要输入asset的内容

#去除asset pipeline
gem 'quiet_assets', group: :development
#去除warning messages.
gem 'thin', group: :development
#使用thin服务器开启web服务
rails s thin

57. Create Model Through Text Field
这个章节实现两个功能,分别是通过选择框添加tag和通过输入框添加tag,详细的代码演示如下:

#终端执行下面代码
rails g scaffold category name:string
rails g scaffold product name:string content:text category:references

#model中
class Product < ActiveRecord::Base
  belongs_to :category
  attr_accessor :new_category_name
  before_save :create_category_from_name

  def create_category_from_name
    create_category(name: new_category_name) unless new_category_name.blank?
  end
end

#controller中
def create
  @product = Product.new(product_params)
  if @product.save
    redirect_to product_path(@product)
  else
    render 'new'
  end
end

#这段代码在进行第一次模仿的时候遗漏了,因此new_category_name参数会被遗漏,不能从view传递到model
def product_params
  params.require(:product).permit(:name, :content, :category_id, :new_category_name)
end

#view中
<div class="field">
  #注意下面选择框的格式
  <%= f.collection_select(:category_id, Category.all, :id, :name, prompt: "请选择")%>
  <%= f.text_field :new_category_name %>
</div>

58. How to Make a Generator
59. Optimistic Locking
应用场景,当用户对一个字段进行编辑时,另外一个用户刚好更新过了这个字段,然后就会报错,这里介绍两种解决方式。
第一种,使用乐观锁字段lock_version

rails g scaffold product name:string price:float

rails g migration add_lock_version_to_products
#生成下面的形式
class AddLockVersionToProducts < ActiveRecord::Migration 
  #默认值必须为0
  def change add_column :products, :lock_version, :integer, default: 0, null: false 
  end
end

#/app/views/products/_form.html.erb
<%= f.hidden_field :lock_version %>

#在strong parameter 添加lock_version这个参数

#product.rb这个model中添加下面的方法
#/app/models/products.rb
def update_with_conflict_validation(*args)
  update_attributes(*args)
rescue ActiveRecord::StaleObjectError 
  #了解乐观锁的原理
  self.lock_version = lock_version_was 
  errors.add :base, "This record changed while you were editing it." 
  changes.except("updated_at").each do |name, values| 
    errors.add name, "was #{values.first}" 
  end 
  false 
end

#/app/controllers/products_controller.rb
def update 
  @product = Product.find(params[:id]) 
  if @product.update_with_conflict_validation(params[:product]) 
    redirect_to @product, notice: "Updated product." 
  else 
    render :edit 
  end
end

第二种方法:不适用锁机制。上面的这种方法功能已经比较完善,第二种方法不理解,下次遇到再说。

**60. Testing without Fixtures **
看不懂,完整懂了测试章节再看。

61. Sending Email

64. Custom Helper Modules
定制一个helper方法,对所有的controller都有用

#在app/helpers中建立如下文件
category_helper.rb

#在controllers/application_controller.rb中写入如下语句
helper :category  #将category_helper.rb中代码应用到所有controller中
helper :all  #所有在app/helpers中的文件应用到controller中

67. restful_authentication
一种用户登录的方案,感觉已经过时,替代方案是devise
70.Custom Routes
定制routes,见最新的guides

72. Adding an Environment
rails默认有三个环境,分别是development,production,test,其实可以自己定制属于自己的环境,具体代码如下:

#建立如下的文件
config/environments/staging.rb
#可以将production.rb文件中的内容复制到该文件中
#开始这个系统的代码如下:
rails s -e staging
#到这个环境的console平台中
rails c staging
RAILS_ENV=staging rails s #和上面的功能类似
#如果设置默认的环境为staging,则可以有如下的表示方式
export RAILS_ENV=staging
#可以在gem文件中添加专门给staging的gem
group :staging do 
  gem 'ruby-prof'
end
#在/config/application.rb文件中设置专门针对某个group的gem
#下面这段代码不是很懂,下次遇到问题再说
if defined?(Bundler) 
  Bundler.require(*Rails.groups(:assets => %w(development test), :profiling => %w[staging development])) 

78. Generating PDF Documents
pdf-writer 这个gem已经被prawn取代。

80.Simplify Views with Rails 2.0
这个场景就是前端模块化,默认在使用scaffold的过程中,表格是会被提取出来单独使用的,比如_form.html.erb,这个章节将的是讲资源的单个内容抽取出来,并在show.html.erb和index.html.erb文件中进行使用:

rails g scaffold Article name:string

#views/articles建立article.html.erb
<%= link_to article.name, article%>

#views/articles中修改show.html.erb内容
<%= render partial: @article %>

#views/articles中修改index.html.erb内容
<%= render partial: @articles%>

81. Fixtures in Rails 2.0
就是进行测试的时候放在test/fixtrues文件夹下面的固件,好处在于不用和ActiveRecord进行交互,但是其实有其他替代方法。视频内容略。

82. HTTP Basic Authentication
场景应用在对某个action实现进行过滤,实现的代码如下:

#controller中
before_filter :authenticate, only: :show
protected
  def authenticate 
    authenticate_or_request_with_http_basic do |username, password| username == "foo" && password == "bar" 
  end
end

类似的代码:
http_basic_authenticate_with

83. Migrations in Rails 2.0
这个章节的内容在guides中都都可以找到,主要是讲migration的命令以及建立删除数据库或者字段的语句,容易遗漏的地点,建立的数据库的语句如下:

rake db:create

因为通常情况下默认是sqlite数据库,默认已经建立,所以这条语句可以省略,如果换做是其他数据库的话,需要使用这条语句。

85. YAML Configuration
应用场景:将一些隐私的信息写在配置文件里面,不要出现在MVC架构中,详细代码如下所示:

#controller文件
http_basic_authenticate_with name: ENV["BLOG_USERNAME"], password: ENV["BLOG_PASSWORD"]

#config文件中
#建立application.yml文件,写入如下内容
BLOG_USERNAEM: "jayzen"
BLOG_PASSWORD: "111111"

#在application.rb文件中添加如下内容
#每次文件进行加载的时候都会这个application.yml文件进行载入
ENV.update YAML.load(File.read(File.expand_path('../application.yml', __FILE__)))

89.Page Caching
参考guides,page caching已经被单独成为一个gem,但是这个gem不能被rails5使用,以后遇到再说,可能这个gem已经被更新。

90.Fragment Caching
参考guides,guides中内容不能在log文件中找到对应的显示,log中没有显示caching内容。

96. Git on Rails

109. Tracking Attribute Changes
场景主要应用在追踪最近更新的数据变化,代码显示操作如下所示:

rails g scaffold Task name:string

#预存了一段内容,其中name为jayzen
rails console
p = Task.first
p.changed? #false
p.changes #{}
p.name = "jay"
p.changed? true
p.changes #{"name"=>["jayzen","jay"]}

111. Advanced Search Form
这个片段体现了下面的几个场景:1.实现了高级查询,其实就是多条件查询 2.对用户的查询习惯进行保存 3.用户自行建立task任务
代码如下所示:

#使用collection_select改写下面的两段代码
rails g scaffold category name:string
rails g scaffold product name:string price:decimal category:references

#建立第三个资源find
rails g scaffold search keywords:string min_price:decimal max_price:decimal category:references

#model
class Search < ActiveRecord::Base
  def products 
    @products ||= find_products 
  end 

  private 
  def find_products 
    products = Product.where("name like ?", "%#{keywords}%") if keywords.present? 
    products = products.where(category_id: category_id) if category_id.present? 
    products = products.where("price >= ?", min_price) if min_price.present? 
    products = products.where("price <= ?", max_price) if max_price.present? 
    products 
  end
end

#controller
class SearchesController < ApplicationController 
  def new 
    @search = Search.new 
  end 

  def create 
    @search = Search.create!(params[:search]) 
    redirect_to @search 
  end 

  def show 
    @search = Search.find(params[:id]) 
  end
end

#new.html.erb
<h1>Advanced Search</h1>
<%= form_for @search do |f| %> 
  <div class="field"> 
    <%= f.label :keywords %><br /> 
    <%= f.text_field :keywords %> 
  </div> 
  <div class="field"> 
    <%= f.label :category_id %><br /> 
    <%= f.collection_select :category_id, Category.order(:name), :id, :name, include_blank: true %> 
  </div> 
  <div class="field"> 
    <%= f.label :min_price, "Price Range" %><br /> 
    <%= f.text_field :min_price, size: 10 %> - <%= f.text_field :max_price, size: 10 %> 
   </div> 
   <div class="actions">
     <%= f.submit "Search" %>
   </div>
<% end %>

#show.html.erb
<h1>Search Results</h1>
<%= render @search.products %>

#使用task方法对保存的查询记录进行删除
#lib/tasks/searches.rake

desc "Remove searches older than a month"
#如果要与数据库进行交互,必须使用指明:environment
task :remove_old_searches => :environment do
  Search.delete_all ["created_at < ?", 1.month.ago]
end

#执行上面的代码rake task names
#rake remove_old_searches

**113.Contributing to Rails with Git **
内容略
116.Selenium
内容略,讲述的是在浏览器端对内容进行测试。

120. Thinking Sphinx
Sphinx没有安装成功

126. Populating a Database
populator没有支持rails3,更没有支持rails4,不过可以从这里学习到在lib/tasks/文件夹下面,建立task后缀文件,终端执行rake db:taskname文件

139.Nested Resources
嵌套路由,见最新的guides

155.Beginning with Cucumber
cucumber是一个测试框架,内容略。
156. Webrat
测试框架,内容略。

158.Factories not Fixtures
讲述测试内容fixture,内容略。

159.More on Cucumber
内容略,讲述关于测试框架cucumber的更多内容。

160. Authlogic
一种authentication solution,建议直接使用和熟悉devise

169.Dynamic Page Caching
参考最新的rails guides和episode 89 page caching

179. Seed Data
使用seed方式生成数据库数据,下面介绍两种:

#第一种从网络上抓取数据
rails g model country code:string name:string

require 'open-uri'
open("http://openconcept.ca/sites/openconcept.ca/files/country_code_drupal_0.txt") do |countries| 
  countries.read.each_line do |country| 
    code, name = country.chomp.split("|")
    Country.create!(:name => name, :code => code) 
  end 
end

#第二种从fixtrue中获取
rails g model operating name:string

require 'active_record/fixtures' 
ActiveRecord::Fixtures.create_fixtures("#{Rails.root}/test/fixtures", "operatings")

180.Finding Unused CSS
在系统中发现一些未被使用的CSS。

182. Cropping Images
应用场景:用户对上传的图片进行个性定制

187.Testing Exceptions
进行测试,内容略。
188.Declarative Authorization
内容略,用户的权限管理机制,推荐简单的处理方式,比如使用在user中增加admin字段。
189.Embedded Association
内容略,权限管理机制,推荐使用cancancan

190. Screen Scraping with Nokogiri
实现案例:获取某个网页下面的某个链接内容,进入该链接,获取该链接下面的内容

require "nokogiri"
require "open-uri"

url = "http://www.xixizhan.com/forum-39-2.html"
doc = Nokogiri::HTML(open(url))
doc.css(".xst").each do |item|
  doc_one = Nokogiri::HTML(open(item[:href]))
  if doc_one.at_css(".t_f span a").nil?
    puts "#{item.text}该节点为空"
  else
    puts doc_one.at_css(".t_f span a")[:href]
  end
end

常用方法

#生成nokogiri对象
doc = Nokogiri::HTML(open(url))
#获取多个元素
doc.css(".xst")
#获取单个元素
doc_one.at_css(".t_f span a")
result = @doc.css("name").first
#获取其中的文本内容
doc_one.at_css(".t_f span a").text
#对获取的文本内容记性匹配
doc_one.at_css(".t_f span a").text[/\$[0-9\.]+/]
#获取其中的链接
doc_one.at_css(".t_f span a")[:href]

191. Mechanize
从人人上面获得用户的名字

require "mechanize" #引入Mechanize
require "nokogiri"

agent = Mechanize.new #新建一个Mechanize对象
login_page = agent.get "http://www.renren.com/SysHome.do" #获取登录页面

login_form = login_page.forms[0] #获取该页面第一个表单
email_field = login_form.field_with(:name => "email") #获取name为email的输入框
username_field.value = "email名称" 
password_field = login_form.field_with(:name => "password")
password_field.value = "密码值"

result_page = agent.submit login_form
puts "loading..."

result = result_page.at_css(".hd-name")
puts result.content #值为郑佳俊

在rails/lib/tasks建立demo.task,格式如下所示

#内容格式
desc "Fetch product prices" 
task :fetch_prices => :environment do 
#db/seed.rb内容一致
end

#执行这里面的代码
rake demo.task

200.Rails 3 Beta and RVM
内容都已经清楚,略。

201.Bundler
内容略,但是在这里发现了在rake db:migrate的时候经常出现的一个问题,出现的问题显示为gemfile.lock中rake版本太低,而rails项目已经出发了最新的版本,我一般的解决方法是在gemfile.lock中将rake的版本按照提示提高,但是本文的介绍的两外一种方法:

bundle exec rake db:migrate

这条语句意思是按照gemfile.lock中rake版本执行rake,就不会出现上面的错误。
202. Active Record Queries in Rails 3
查询的内容查看guides内容,下面具体说下使用scope
scope的两种形式

#使用macro-style形式
class Article < ApplicationRecord
  scope :visible, -> { where("hidden=?", true) }
  #必须使用块对象的形式,下面的格式产生同样作用
  scope :view, -> {where("hidden=?", true)}
end

#使用类方法进行定义
class Article < ApplicationRecord
  def self.published
    where("published=?", true)
  end
end

默认scope的形式:

class Article < ApplicationRecord
  #default_scope使用块,而不使用块对象
  default_scope { where("published=?", true) }
end

#也可以参考上面的形式,使用类方法定义,这里省略

scope定义的方法可以使用链式调用

Article.visible.view

203. Routing in Rails 3
内容已经陈旧,看最新的guides内容

204.XSS Protection in Rails 3
参看上面的episode27内容,默认情况下rail3以及以后对用户提交的html进行了转义,防止xss攻击,如果要显示html标签内容,可以参考episode27中内容,一般使用sanitize方法会认为是安全的,另外两个方法会存在安全漏洞,在并不是很了解的rails安全措施的情况下。

206. Action Mailer in Rails 3
内容略,已经过时。
207. Syntax Highlighting
场景:实现语法高亮和markdown

使用gem:pygments.rb对整个属性实现代码高亮

#添加gem
gem "pygments.rb"

#show.html.erb
<%= raw Pygments.highlight(@article.content) %>

#/app/assets/stylesheets/pygments.css.erb
#在上面这个文件夹中添加pygments.css.erb这个文件,内容如下
<%= Pygments.css %>

使用simple_format方法也可以对整条语句显示格式

<%= simple_format @article.content %>
#如果里面添加诸如<strong></strong>的标签会文字进行属性miao

使用redcarpet进行markdown,结合pygment进行highlight

#添加gem
gem 'redcarpet'

#show.html.erb
<%= markdown @article.content %>

#application_helper.rb
def block_code(code, language) 
  sha = Digest::SHA1.hexdigest(code) 
  #caching highlighted code
  Rails.cache.fetch ["code", language, sha].join('-') do
    Pygments.highlight(code, lexer:language) 
  end 
end

def markdown(text) 
  renderer = HTMLwithPygments.new(hard_wrap: true, filter_html: true) 
  options = { 
    autolink: true, 
    no_intra_emphasis: true, 
    fenced_code_blocks: true, 
    lax_html_blocks: true, 
    strikethrough: true, 
    superscript: true } 
  Redcarpet::Markdown.new(renderer, options).render(text).html_safe 
end

209. Devise
参考这篇文章
210.Customizing Devise
参考上面的文章,遇到问题再讨论。

225.Upgrading to Rails 3 Part 1

226.Upgrading to Rails 3 Part 2

227.Upgrading to Rails 3 Part 3

231.Routing Walkthrough Part 1
研究routing的源码
232.Routing Walkthrough Part 2
研究routing的源码
234.SimpleForm
该片段是通过simple_form来简化rails默认的form_for,下面先通过默认的form_for的形式来书写一篇代码,然后给出相应的simple_for形式。

下面介绍rails的数据类型和sql数据类型

:benlean #=>TINYINT(1),1个字节,表示0~255的整数
:date #=>DATE
:time #=>TIME
:datetime #=>DATETIME
:timestamp #=>DATETIME
:float #=>FLOAT
:decimal #=>DECIMAL,decimal和foat的精度不同
:integer #=>INT
:string #=>VARCHAR

该episode中的数据结构如下

#model
product publisher tag 
product belongs_to publisher
publisher has_many products
product has_and_belongs_to_many tags
tag has_and_belongs_to_many products

#scaffold
rails g scaffold publisher name
rails g scaffold product name price:decimal release_on:date discontinued:boolean rating:integer publisher:references
rails g scaffold category name

#migration
def change
  create_join_table :products, :categories do |f|
    f.index : product_id
    f.index : category_id
  end
end

在form_for表单中的数据呈现如下:

#_form.html.erb
<%= form_for(product) do |f| %>
  <div class="field">
    <%= f.label :name %>
    <%= f.text_field :name %>
  </div>

  <div class="field">
    <%= f.label :price %>
    <%= f.text_field :price %>
  </div>

  <div class="field">
    <%= f.label :release_on %>
    <%= f.date_select :release_on %>
  </div>

  <div class="field">
    <%= f.label :discontinued %>
    <%= f.check_box :discontinued %>
  </div>

  <div class="field">
    <%= f.label :rating %>
    <%= f.radio_button :rating, 1 %> 1
    <%= f.radio_button :rating, 2 %> 2
    <%= f.radio_button :rating, 3 %> 3
    <%= f.radio_button :rating, 4 %> 4
    <%= f.radio_button :rating, 5 %> 5
  </div>

  <div class="field">
    <%= f.label :publisher %>
    <%= f.collection_select :publisher_id, Publisher.all, :id, :name, prompt: true %>
  </div>

  <div class="field">
    <%= hidden_field_tag "product[category_ids][]", nil %>
    <% Category.all.each do |category| %>
      <%= check_box_tag "product[category_ids][]", category.id, @product.category_ids.include?(category.id), id: dom_id(category) %>
      <%= label_tag dom_id(category), category.name %><br />
    <% end %>
  </div>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

#show.html.erb
<%= @product.categories.all.map(&:name).join(",") %>

#product_controller.rb
def product_params
  params.require(:product).permit(:name, :price, :release_on, :discontinued, :rat    ing, :publisher_id, {category_ids: []})
end

239.ActiveRecord::Relation Walkthrough
源码解析

244.Gravatar
给邮件名称建立统一标识图像,具体见tutorial。

250. Authentication from Scratch
一个权限系统,详细见tutorial教程

253. CarrierWave File Uploads
实现场景包括:文件(包括图片)上传,文件下载(包括图片展示)

#添加carrierwave
gem 'carrierwave'

#添加资源
rails g scaffold Resume name:string attachment:string

#建立upload
rails g uploader attachment

#在model中标记那个属性值需要上传
class Resume < ActiveRecord::Base
   mount_uploader :attachment, AttachmentUploader 
end

#上传附件表单new.html.erb,适合多个资源提交
<%= form_for(@resume) do |f|%>
  <%= f.label :name%>
  <%= f.text_field :name %>
  <%= f.label :attachment %>
  <%= f.file_field :attachment %> #注意是file_field,而不是text_field
  <%= f.submit "save" %>
<% end %>

#适合单个资源提交,场景还未遇到,遇到了再分析
<%= form_tag({action: :upload}, multipart: true) do %>
  <%= file_field_tag 'picture' %>
<% end %>


#显示附件下载和图片显示index.html.erb
<% @resumes.each do |resume| %>
  <%= resume.name %>
  #文件下载
  <%= link_to "download", resume.attachment_url %>
  #图片呈现
  <%= image_tag resume.attachment_url %>
<% end %>

#编辑上传文件
class AttachmentUploader < CarrierWave::Uploader::Base
  storage :file 
  
  def store_dir 
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" 
  end 

  #建立白名单,名单之外的不能上传  
  def extension_white_list 
    %w(pdf doc htm html docx) 
  end
end

#使用链接上传
<%= f.text_field :remote_avatar_url %>

254.Pagination with Kaminari
场景:使用kaminari进行分页

gem 'kaminari'

#controller
def index
  @artilces = Article.page(params[:page]).per(10)
end

#view
<%= paginate @articles %>

257.Request Specs and Capybara
测试,内容略。

264.Guard
自动测试时使用,内容略
270. Authentication in Rails 3.1
介绍3.1中关于权限的三个feature

1.http_basci_authenticate_with
2.has_secure_password/password_digest
3.force_ssl

272 Markdown with Redcarpet
已经过时,见207 Syntax Highlighting

274. Remember Me & Reset Password
记住和密码重置,详见tutorial代码

275.How I Test
内容略,讲述测试内容。

278. Search with Sunspot
搜素的解决方案,这里只介绍安装和一般用法,具体内容可以重新看wikiasciicast,具体代码参见如下:

#需要安装Java环境
#两个model
rails g scaffold Article name:stirng content:string
rails g scaffold Comment content:string articles:references

#添加两个gem
gem 'sunspot_rails'
gem 'sunspot_solr'

#model
searchable do 
  #boost是提高权重
  text :name, :boost => 5 
  text :content
  #关联comment
  text :comments do 
    comments.map(&:content) 
  end 
end

#controller
def index 
  @search = Article.search do 
    fulltext params[:search]
    #对搜索结果进行分页
    paginate :page => params[:page] || 1, :per_page => 5 
  end 
  @articles = @search.results
end

#view
<%= form_tag articles_path, :method => :get do %> 
<p> <%= text_field_tag :search, params[:search] %> 
<%= submit_tag "Search", :name => nil %>
<% end %>

#安装和启动语句
rails g sunspot_rails:install
rake sunspot:solr:start
rake sunspot:reindex

282.Upgrading to Rails 3.1

283.Authentication with Sorcery
一种authentication solution,建议熟悉和使用devise
285. Spork
内容略,作用为加快测试的启动时间。

299.Rails Initialization Walkthrough
源码解析。
305.Authentication with Warden
一种权限验证系统,现在流行devise,建议直接使用和熟悉devise.
308.Oh My ZSH
内容略,在自己的简书的工具篇中已经有介绍。

314. Pretty URLs with FriendlyId
应用场景,在url中根据model的name进行访问,而不是根据id进行访问,下面是具体的代码:
没有解决的问题有两个:history(不能访问历史记录)&internationalization(访问中文出现问题)

rails g scaffold Article name:string content:text

#第一种方式是在model中重写to_param方法
def to_param
  "#{id}#{name}".parameterize
  #或者使用类方法to_param
  #to_param :name
end
上面的方法可以实现/articles/1name方法对article进行访问,同时articles/1也是可以实现访问

#第二种方法通过使用friendlyid方法实现
gem 'friendly_id'

class Article < ActiveRecord::Base 
  extend FriendlyId 
  friendly_id :name
end

class ArticlesController < ApplicationController
  private
    def set_article
      @article = Article.friendly.find(params[:id])
    end
end
上面的方法可以有/article/id和/article/name两种实现方法来访问article,但是问题是如果name中出现有空格或者是标点符号则会在url中出现转义字符,为了解决这个问题,下面给出解决方案

#article.rb
class Article < ActiveRecord::Base 
  extend FriendlyId 
  friendly_id :name, use: :slugged
end

rails g migration add_slug_to_articles slug:string:uniq

class AddSlugToArticles < ActiveRecord::Migration 
  def change 
    add_column :articles, :slug, :string 
    add_index :articles, :slug, unique: true
    #设置了slug,slug的索引值为true,使用相同的name时候会使用不同的后缀
  end
end

#取消sha

#若对name进行了修改,但是在url中slug是不会被修改的,这次采取的方式是修改默认的方法。
#article.rb
class Article < ActiveRecord::Base 
  extend FriendlyId 
  friendly_id :name, use: :slugged

  #修改默认的方法,则每次name变动,那么slug值也会变动
  def should_generate_new_friendly_id?
    name_changed? 
  end
end

#如果slug是之后进行migration的,需要进行如下操作,更新每个slug的值
Article.find_each(&:save) #因为是新创建的字段,这条语句进行字段赋值



318.Upgrading to Rails 3.2

319.Rails Middleware Walkthrough
源码解析

328.Twitter Bootstrap Basics
略,前端框架

368.MiniProfiler
默认在开发环境下加入下面的gem,就能在视图界面看到具体的消耗时间

gem 'rack-mini-profiler'

下面介绍在开发环境下面显示MiniProfiler
启动开发环境:

rails assets:precompile
rails db:setup RAILS_ENV=production
rails s -e production

在开发环境中没有启动成功该插件,遇到的时候再讨论。

372.Bullet
在development环境下添加gem,用于检测两个内容,是否存在1+N问题和是否缺少counter cache column.自己未实现,遇到情况再讨论。

#gemfile
gem 'bullet', group: :development

#/config/initializers/bullet.rb
if defined? Bullet 
  Bullet.enable = true 
  Bullet.alert = true
end

374. Image Manipulation
略,功能介绍:通过使用rmagic这个工具在程序端实现改变照片的颜色,rmagic可以在终端通过命令行改变照片的一些属性。
382. Tagging
讲述通过两种方法制作标签,一种通过gem,一种通过自己制作
第一种通过gem

#添加gem
gem 'acts-as-taggable-on'

#执行终端
rake acts_as_taggable_on_engine:install:migrations #针对最新版本
rake db:migrate
#避免mysql的特殊字符错误
rake acts_as_taggable_on_engine:tag_names:collate_bin

#user.rb中添加
class Article < ActiveRecord::Base
  acts_as_taggable
end

#添加强参数
class ArticlesController < ApplicationController 
  def user_params 
    params.require(:user).permit(:name, :content, :tag_list) 
  end
end

#view中添加字段
<div class="field"> 
  <%= f.label :tag_list, "Tags (separated by commas)" %><br />   
  <%= f.text_field :tag_list %>
</div>

#view中显示字段
Tags: <%= article.tag_list.map { |t| link_to t, tag_path(t) }.join(', ') %>

#config/routes.rb
get 'tags/:tag', to: 'articles#index', as: :tag

#点击标签获得相应标签的文章:articles_controller.rb
def index 
  if params[:tag] 
    @articles = Article.tagged_with(params[:tag]) 
  else 
    @articles = Article.all 
  end
end

#添加标签云
<div id="tag_cloud"> 
  <% tag_cloud Article.tag_counts, %w{s m l} do |tag, css_class| %> 
  <%= link_to tag.name, tag_path(tag.name), class: css_class %> 
  <% end %>
</div>

#修饰标签云
#tag_cloud { 
  width: 400px; 
  line-height: 1.6em; 
  .s { font-size: 0.8em; }
  .m { font-size: 1.2em; }
  .l { font-size: 1.8em; }
}

385.Authorization from Scratch Part 1
案例是登录用户是否有权限,具体案例见tutorial
386.Authorization from Scratch Part 2
案例是登录用户是否有权限,具体案例见tutorial
Action Controller Walkthrough
源码解析。
397.Action View Walkthrough
源码解析。
**411.Performance Testing **
查看程序的瓶颈,类似miniprofile
412.Fast Rails Commands
加快程序运行的三种方式,分别是command,spring和zeus
413.Fast Tests
通过各种方式加快测试,内容略。

415.Upgrading to Rails 4

417. Foundation
略,是一个前端框架,类似bootstrap。

推荐阅读更多精彩内容