啟動(dòng)項(xiàng)目:
ruby script/server -e development(默認(rèn))
ruby script/server -e test
ruby script/server -e production
在編寫ruby代碼時(shí),如果要引用另一個(gè)文件中的類和模塊,需要使用require關(guān)鍵字,但是當(dāng)我們?cè)趓ails中引用另一個(gè)文件中的類和模塊時(shí),rails會(huì)自動(dòng)把類名稱根據(jù)命名約定改為文件名,然后在同一目錄下加載該文件。
按模塊組織控制器:
ruby script/generate controller Admin::Book action1 action2
admin模塊下的book_controller控制器
Rails給Enumerable類擴(kuò)展的方法
1》 group_by: 將一個(gè)對(duì)象集合分組,針對(duì)每個(gè)對(duì)象調(diào)用塊,然后根據(jù)代碼塊的返回值作為分組的鍵,值是所有擁有同一個(gè)鍵的對(duì)象組成的數(shù)組。
eg:
User.all.group_by{|user| user.sex}
User.all.group_by(&:name)
2》 sum: 對(duì)集合進(jìn)行加總,把每個(gè)元素傳遞給一個(gè)代碼塊,并對(duì)代碼塊返回的值進(jìn)行累加。
User.all.sum(&:id) 返回所有user對(duì)象的id的和
3》 in_groups_of(arg1, arg2)? 將某一個(gè)數(shù)組分為子元素由arg1個(gè)元素組合的數(shù)組元素組成的數(shù)組,出現(xiàn)無(wú)法填充的值由arg2填補(bǔ)。
eg:
[1,2,3,4,5].in_groups_of(2,"blank")???? =>?????
[[1,2],[3,4],[5,"blank"]]
字符串?dāng)U展
str[0] 第一個(gè)字符的Ascill碼。
str[2..3] 返回字符串的第三個(gè)字符開(kāi)始的3個(gè)字符組成的字符串。
str.at(0) 第一個(gè)字符
str.to(4) 前5個(gè)字符組成的字符串
str.from(4) 最后5個(gè)字符組成的字符串
str.first
str.last
str.starts_with?(字符串)
str.ends_with?(字符串)
str.each_char{|char| char.upcase}
str.pluralize 復(fù)數(shù)形式
str.singularize? 單數(shù)形式
str.humanize
str.titleize
對(duì)數(shù)值的擴(kuò)展:
figure.ordinalize?? 返回?cái)?shù)字的序數(shù)形式
figure.bytes、kilobytes、megabytes、gigabytes、terabytes、
perabytes、exabyte? 數(shù)據(jù)大小
figure.seconds、minutes、hours、days、weeks、fortnights、months、years? 時(shí)間
注意:? ago、 until、 from_now、 since
eg:?
1.day.ago
1.day.ago(Time.now)
時(shí)間和日期的擴(kuò)展
now = Time.now
now.to_s(:short)、to_s(:db)、to_s(:long)、to_s(:rfc822)
now.ago(2.days)、since(2.days)
change(:hour => 12)? 改變?nèi)掌诘膆our為12
advance(:hour => 12)? 推遲日期的12hour
to_date、to_time
at_beginning_of_week、at_beginning_of_month、at_beginning_of_quarter(季)、at_beginning_of_year
ruby符號(hào)的擴(kuò)展:
posts.group_by{|post| post.author_id}
posts.group_by(&:author_id)
with_options的使用:
Rails里有些方法使用一個(gè)Hash作為最后一個(gè)可選的參數(shù),如果對(duì)多個(gè)方法有同樣的選項(xiàng),我們可以使用with_options來(lái)減少冗余:
eg:
with_options :if => :should_validate_password? do |user|?
? user.validates_presence_of :password?
? user.validates_confirmation_for :password?
? user.validates_format_of :password, :with => /^[^\s]+$/
end
遷移任務(wù):
create_table??
:force => true? 如果表存在,強(qiáng)制刪除,然后再創(chuàng)建表
:temporary => true? 創(chuàng)建一張臨時(shí)表,程序與數(shù)據(jù)庫(kù)斷開(kāi)鏈接,則表被刪除。
:options => "xxxx"? 指定針對(duì)于底層數(shù)據(jù)庫(kù)的選項(xiàng),這些選項(xiàng)會(huì)被加到create table語(yǔ)句的后面
:primary_key 主鍵
:id => false? 沒(méi)有主鍵的表
如果遷移任務(wù) 提供的方法 不夠滿足你 的需要,也 可以使用數(shù) 據(jù)庫(kù)專有的 功能:使用execute() 方法就可以運(yùn)行原生 SQL 語(yǔ)句。例如:給表加上外鍵
class CreateLineItems < ActiveRecord::Migration
??? def self.up
????? create_table :line_items do |t|
??????? t.column :product_id, :integer
??????? t.column
rder_id,???? :integer
????? end
????? execute "alter table line_items
????????? add constraint fk_line_item_products
????????? foreign key (product_id) references products(id)"
??? end
???? def self.down
????? drop_table :line_items
???? end
end
ActiveRecord::Base
column_names? 屬性組成的數(shù)組
columns_hash["屬性名稱"]? 屬性名稱信息
屬性_before_type_cast? 讀取屬性時(shí),ActiveRecod會(huì)盡量將得到的值轉(zhuǎn)型成適當(dāng)?shù)膔uby類型,如果我們希望的到屬性的原始值,可以在屬性名稱后面加上before_type_cast。
eg:User.first.created_at??? =>?? 2010-06-24 09:41:17
連接數(shù)據(jù)庫(kù):? ActiveRecord::Base.establish_connection(:adapter => "mysql", :host => "localhost", :database => "rails", :username => "root", :password => "1234")
防止惡意注入:
1> 問(wèn)號(hào)占位符:?? User.find(:all, :conditions => ["id > ?", 3]
2> 命名占位符:?? User.find(:all, :conditions => ["id > :id", {:id => 3}])
注意:
命名占位符的語(yǔ)句可以轉(zhuǎn)換為
User.find(:all, :conditions => ["id > :id", params[:user]])
獲取字段統(tǒng)計(jì)信息:
average:?
maximum:
minimum:
sum? :
count? :
以上方法的參數(shù):?
:conditions、:joins、:limit、:order、:having、:select、 :distinct
eg:
Order.maximum :amount, :group => "state", :limit => 3,
rder => "max(amount) desc"
擁有訂單最大的三個(gè)州
更新操作:
update_attribute、update_attributes、update、update_all
創(chuàng)建操作:
create、create!、save、save!
刪除數(shù)據(jù):
delete、delete_all、destroy、destroy_all
delete繞過(guò)了ActiveRecord的回調(diào)和驗(yàn)證,destory沒(méi)有繞過(guò)回調(diào)和驗(yàn)證
序列化數(shù)據(jù):
serialize :屬性
序列化的屬性可以直接存入Array和hash類型的數(shù)據(jù),也可以直接讀出來(lái)使用
缺點(diǎn):
ruby應(yīng)用之外的應(yīng)用訪問(wèn)序列化的數(shù)據(jù)時(shí),除非它能夠理解yaml格式,否則無(wú)法獲取這個(gè)字段的信息。
彌補(bǔ)這種缺點(diǎn)的方式是用對(duì)象聚合的方式來(lái)實(shí)現(xiàn)類似的效果
聚合/組合:
聚合可以把一個(gè)或多個(gè)屬性封裝為一個(gè)類,然后這個(gè)類里可以添加操作屬性的方法,這樣我們就可以實(shí)現(xiàn)序列化所要實(shí)現(xiàn)的目的了,而且可以避免序列化的缺點(diǎn)。
composed_of :attr_name, :class_name => 類名稱, :mapping => [字段與屬性組成的數(shù)組]
eg:
class Xingxi < ActiveRecord::Base
? composed_of :inf, :class_name => "Inf", :mapping => [[:name, :name], [:phone, :phone]]
end
class Inf
??? attr_reader :name, :phone
??? def initialize(name, phone)
??????? @name = name
??????? @phone = phone
??? end
??? def to_s
????? [@name, @phone].compact.join(" ")
??? end
end
inf = Inf.new("zcy",? "12344454")
Xingxi.create(:inf => inf)
注意:
教程上指出? :class_name對(duì)應(yīng)的“類名稱”可以是類常量,也可以是包含類常量的字符串,但實(shí)際上只能是包含類常量的字符串,如果類名恰好是屬性名的混合大寫形式,那么class_name可以省略,但是實(shí)際上不可以,包括:mapping也不可以。
關(guān)聯(lián):
class Line < ActiveRecord::Base
? belongs_to :product
end
belongs_to :product? 會(huì)產(chǎn)生以下方法
1>:product(force_reload=false) 返回關(guān)聯(lián)的product對(duì)象,默認(rèn)情況下product對(duì)象會(huì)被緩存,當(dāng)force_reload=true時(shí),將重新查詢數(shù)據(jù)庫(kù)。
2>:product=: line對(duì)象和product對(duì)象關(guān)聯(lián)起來(lái),將line記錄的外鍵值設(shè)為product的主鍵值,如果product沒(méi)有保存,line保存的時(shí)候會(huì)保存product,包括外鍵。
3>:build_product(attributes={}) 新建一個(gè)product對(duì)象,用指定的屬性對(duì)其初始化,相當(dāng)于product=Product.new(attributes)。
4>:build_create(attributes={}) 創(chuàng)建一個(gè)product對(duì)象,與line關(guān)聯(lián),保存product對(duì)象。
order:? has_one中也有order,主要用于例如最后一個(gè)***,此時(shí)便可以用order指定排序。
:dependent?? :destroy(true)、:nullify、 false
??? :destroy?? 刪除記錄的同時(shí)也刪除子記錄
??? :nullify?? 刪除記錄的同時(shí)刪除子記錄的外鍵
??? false????? 只刪除記錄
has_many :lines
class Product < ActiveRecord::Base
? has_many :lines
end
has_many :lines? 會(huì)產(chǎn)生以下方法
lines(force_reload=false)? 同上
lines.build(attributes = {})
lines.create(attributes = {})
lines << line? 將當(dāng)前l(fā)ine對(duì)象添加到lines對(duì)象數(shù)組里
lines.push(line對(duì)象) line對(duì)象添加到lines
lines.delete(line,...) 刪除一個(gè)或多個(gè)line對(duì)象,如果關(guān)聯(lián)為:destroy => :destroy,子對(duì)象被刪除,否則只是刪除子對(duì)象的外鍵,打斷與父對(duì)象的關(guān)聯(lián)。
lines.delete_all? 調(diào)用所有子對(duì)象的delete方法
lines.destroy_all?? 調(diào)用所有子對(duì)象的destroy方法
lines.clear? 和delete一樣,不同的是clear針對(duì)的是所有的子對(duì)象。
lines.find(options)
lines.count(options)
lines.size
lines.length? 強(qiáng)制加載所有子對(duì)象,返回對(duì)象的集合。
lines.empty?
lines.replace(line對(duì)象數(shù)組)? line對(duì)象數(shù)組替換原先的lines
lines.sum(options) 不便利內(nèi)存中的子對(duì)象集合,直接在數(shù)據(jù)庫(kù)端操作
lines.uniq? 返回一個(gè)數(shù)組,包含所有具備獨(dú)立id的子對(duì)象
1> finder_sql: 重新定義了統(tǒng)計(jì)子記錄的sql語(yǔ)句
?? counter_sql: 重新定義了統(tǒng)計(jì)子記錄的數(shù)目
注意: 如果指定了finder_sql而沒(méi)有指定counter_sql,finder_sql中的子句會(huì)被替換為select count(*),然后記錄子記錄的數(shù)量。
eg:
has_many
ingxis, :finder_sql => "select x.* from xingxis x, infos i where x.info_id = i.id and x.id > 4"
作用: 當(dāng):conditions無(wú)法滿足時(shí),:finder_sql顯的非常重要。
:order : 以特定的順序排列
:conditions : 返回符合條件的子記錄
:dependent?? :destroy、:nullify、 false
??? :destroy?? 刪除記錄的同時(shí)也刪除子記錄
??? :nullify?? 刪除記錄的同時(shí)刪除子記錄的外鍵
??? false????? 只刪除記錄
多對(duì)多的關(guān)聯(lián)有兩種
1: 利用默認(rèn)的關(guān)聯(lián)表
2:自己創(chuàng)建關(guān)聯(lián)表,利用關(guān)聯(lián)中的:through
:through?? 告訴rails通過(guò)guanlians表來(lái)導(dǎo)航關(guān)聯(lián)
:source? 用來(lái)指定關(guān)聯(lián)在那個(gè)屬性上
:uniq => true? 去掉重復(fù)的對(duì)象 等同于 :select => "distinct books.*"
eg:
class Kind < ActiveRecord::Base
??? has_many :guanlians
??? has_many :readers, :through => :guanlians, :source => :book
end
注意:
has_many :reader1s,:conditions => "guanlians.cishu > 0"
當(dāng)使用conditions不能很好的表達(dá)時(shí),無(wú)法提供參數(shù),可以考慮以下格式,而且當(dāng)同樣的方法被多次調(diào)用時(shí),可以將方法寫在模塊中,然后在關(guān)聯(lián)中:extend => "模塊名稱" 來(lái)調(diào)用。
has_many :readers do
??? def reader(limit = 3)
??????? find(:all, :limit => limit)
??? end
end
單表繼承:?
優(yōu)點(diǎn):? 這樣做的好處是提高讀取表的速度,因?yàn)闆](méi)有關(guān)聯(lián),只有一個(gè)表。
缺點(diǎn):? 當(dāng)各個(gè)子類的相似的地方很少的時(shí)候,會(huì)導(dǎo)致表中有很多屬性,這樣處理這個(gè)問(wèn)題的方法是用多態(tài)關(guān)聯(lián)。
多態(tài)關(guān)聯(lián):
types表中的多態(tài)外鍵如果是duotai,那么表的屬性是duotai_id, duotai_type,一個(gè)記錄鍵值,一個(gè)記錄類名。
class Article < ActiveRecord::Base
??? has_one :type, :as => :duotai
end
class Image < ActiveRecord::Base
??? has_one :type, :as => :duotai
end
class Type < ActiveRecord::Base
??? belongs_to :duotai, :polymorphic => true
end
自引用的連接:
class Employee < ActiveRecord::Base
? belongs_to :boss, :class_name => "Employee", :foreign_key => :employee_id
end
預(yù)先讀取子記錄
以下實(shí)例如果沒(méi)有:include => :people, infos為n, 那么他將執(zhí)行2n+1次,如果指定了:include,將預(yù)加載與info有關(guān)的people記錄,此時(shí)將提高效率,但是如果預(yù)加載了數(shù)據(jù),但沒(méi)有用這些數(shù)據(jù),反而會(huì)降低效率。
Benchmark.bm() do |x|
??? x.report{
??????? infos = Info.find(:all, :include => :people)
??????? infos.each do |info|
??????????? info.people.name
??????? end
??? }
end
如果一個(gè)對(duì)象剛剛創(chuàng)建出來(lái),還沒(méi)有與數(shù)據(jù)庫(kù)記錄建立映射,我們稱它為新對(duì)象(new records)。調(diào)用new_records?
模型驗(yàn)證:
validate、 validate_on_create、 validate_on_update
ActiveRecord::Errors
[]? info.errors[:email]
on? info.errors.on(:email)
add(:屬性, 信息)
size、length、count
each、each_error? 迭代錯(cuò)誤屬性和錯(cuò)誤屬性對(duì)應(yīng)的信息
each_full? 迭代錯(cuò)誤信息
full_messages? 錯(cuò)誤信息組成的數(shù)組
invalid?(屬性)? 如果屬性無(wú)效,則返回true
to_xml
empty?
ActiveRecord::Errors.default_error_messages? 這個(gè)返回所有的默認(rèn)信息,如果修改默認(rèn)信息的話,可以從這里修改。
回調(diào):
創(chuàng)建方式
1:直接在回調(diào)中寫代碼。
2:聲明回調(diào)處理器,處理器可以是一個(gè)代碼塊也可以是一個(gè)方法,如果用方法作為一個(gè)處理器,應(yīng)該被聲明為private或protected。
eg
def before_save
? ...
end
before_save :check
private
def check
end
注意:以下方法將跳過(guò)回調(diào)
??? * decrement
??? * decrement_counter
??? * delete
??? * delete_all
??? * find_by_sql
??? * increment
??? * increment_counter
??? * toggle
??? * update_all
??? * update_counters
ActiveRecord::Base
column_names:? 所有列名組成的數(shù)組
columns:? 所有包含列信息的對(duì)象組成的數(shù)組。
columns_hash:?? 列名與列對(duì)象組成的hash數(shù)組。
實(shí)例方法:
attributes:? 所有屬性和屬性值組成的hash數(shù)組。
attributes=
attribute_names:? 所有屬性組成的數(shù)組。
attribute_present?(屬性名稱) 如果屬性名稱存在,則返回true,反之亦然。
事務(wù): 要么全部執(zhí)行,要么全部不執(zhí)行。
模型類.transaction do
end
begin ... rescue ...end
eg:
class Info < ActiveRecord::Base
? def validate
??? errors.add(:age, "age is not less than 0") if age < 0
? end
? def jian(i)
??? self.money = self.money - i
??? self.save!
? end
end
info = Info.create!(:money => 100)
begin
Info.transaction do; info.jian(200); end
rescue
end
puts info.money?? =》 -100
該實(shí)例中要求money不能小于0,而我們也做到了,表中的數(shù)據(jù)不會(huì)被改,但是info.money 返回的值是-100,模型對(duì)象的值被該變了,這是因?yàn)锳ctiveRecord沒(méi)有跟綜對(duì)象在事務(wù)前后的狀態(tài),我們可以指定事務(wù)跟蹤哪些模型對(duì)象。
Info.transaction(info) do; .... end,此時(shí)輸出的值就是100了。
路由:
map.connect 重要參數(shù)
:requirements => {:name => /regexp/}? 要求url中特定的組成部分與指定的正則表達(dá)式一一匹配。
:defaults => {:name => "value", ...}? 設(shè)定各組成部分的默認(rèn)值
:conditions => {:name => /regexp/orstring,...}? 設(shè)定路由的條件
:name => value? 設(shè)定:name參數(shù)的默認(rèn)值
eg:
map.connect 'infos/:year', :controller => "infos", :action => "hello", :defaults => {:year => 2008},:requirements => {:year => /(19|20)\d\d/}, :conditions => {:method => :get}
注意:
map.connect "*aa", :controller => "", :action => ""
符合任何的url格式,但是一定要注意的是要放在最后,否則其他的路由都無(wú)法匹配了。
有名路由
map.hello "hello/:id", :controller => "infos", :action => "index"
1>? hello_url(:id => 1)或hello_url :controller => "infos", :action => "index"
可以訪問(wèn)這個(gè)url。
注意: 以上url可以用path替代。
2>? 地址欄中可以輸入hello訪問(wèn)這個(gè)url。
資源路由:
map.resources :articles, :collection => {:recent => :get}, :member => {:release => :put}, :new => {:hello => :get}
增加以下規(guī)則:
recent_articles_path
release_article_path(:id => 1)
hello_new_article_path
map.resources :articles do |article|
? article.resources :comments
end
articles/99/comments/4
控制器環(huán)境(可以在action中直接引用)
controller_name:? controller名稱
action_name:? action名稱
session: session
cookies: cookie
params: 存放著參數(shù)的hash對(duì)象
rsponse
request: 進(jìn)入控制器的請(qǐng)求對(duì)象,包含屬性。
? domain: 請(qǐng)求地址域名部分的最后兩端。
? remote_ip: 客戶端的ip地址。
? env: 返回請(qǐng)求的環(huán)境。
? get?、post?、put?、delete?、head?
? method:? 返回客戶端訪問(wèn)所使用的請(qǐng)求方法。
? xhr?或xml_http_request?? 如果請(qǐng)求來(lái)自AJAX的輔助方法,則返回true,否則返回false。
控制器應(yīng)答:
1:渲染一個(gè)模板,最常見(jiàn)的(.html、 .rxml、 .rjs)。
2:返回一個(gè)字符串給瀏覽器,主要用于發(fā)送錯(cuò)誤提示。
3:發(fā)送html以外的數(shù)據(jù),這種方式通常用于提供下載。
控制器每次只響應(yīng)一個(gè)請(qǐng)求:
render、 redirect_to、 send_xxx
1> render :action
2> render :template
3> render :file
4> render :partial? 調(diào)用局部模板
:object 指定傳遞給局部模板的對(duì)象。
5> render
ml
6> render :nothing
7> render :inline
8> render :text
9> render(:update) do |page| ... end
重要參數(shù):
:locals => {},指定模板要使用的局部變量。
:layout => false|nil|true|模板名稱。
render_to_string 可以當(dāng)作render使用,不過(guò)它不會(huì)跳轉(zhuǎn),只會(huì)把整個(gè)的內(nèi)容作為字符串返回。
method_missing:調(diào)用指定的action名稱無(wú)效時(shí),method_missing會(huì)渲染一個(gè)內(nèi)聯(lián)的模板,將action的名稱和請(qǐng)求參數(shù)顯示出來(lái)。
eg:
? def method_missing(name, *args)
??? render(:inline => %{<h2> Unknown action: #{name}</h2>
??? Here are the request parameters:<br/>
??? <%= debug(params) %>})
? end
send_data(data, options)? 發(fā)送一個(gè)數(shù)據(jù)流給客戶端。
參數(shù):
:filename、 disposition(inline|attachment)、status、type
send_file(path, options)? 發(fā)送一個(gè)文件給客戶端
參數(shù):
:filename、 :disposition、 :status、 :type、 buffer_size、 stream
重定向:
redirect_to(:action => "")
redirect_to(path)
redirect_to(:back)? 返回上一頁(yè),注意:如果redirect_to(:back)寫在了index的action中,并且訪問(wèn)index的時(shí)候能夠直接運(yùn)行redirect_to(:back),則不能直接訪問(wèn)index的action,因?yàn)樗麜?huì)跳轉(zhuǎn)上一頁(yè),但是沒(méi)有上一頁(yè)。
過(guò)濾器:
prepend_before_filter
before_filter、append_before_filter
prepend_after_filter
after_filter、append_before_filter
參數(shù):
:only、 :except
定義過(guò)濾器的方式:
1:
before_filter do
? ...
end
2:
before_filter :hello,
nly => [:show, :index]
skip_filter、 skip_before_filter、skip_after_filter
參數(shù):
:only、 :except
緩存:
片段緩存、 頁(yè)面緩存、 action緩存
caches_page、 caches_action、 cache do .... end
默認(rèn)配置下,cache只有在產(chǎn)品環(huán)境下才生效,如果要在開(kāi)發(fā)環(huán)境下生效,要配置以下信息中的一條。(config/environments/development.rb)
ActionController::Base.perform_caching = true|false
config.action_controller.perform_caching = true
解除緩存:
expire_action、 expire_page、 expire_fragment :controller => "...", :action => "..."
1》默認(rèn):緩存片段的名字取決于渲染該頁(yè)面的控制器名稱和action名稱,所以使用expire_fragment指定控制器名稱和action名稱來(lái)是對(duì)應(yīng)的片段緩存失效。
2》指定緩存名稱(等同于url_for的參數(shù))
緩存存儲(chǔ)機(jī)制的全局設(shè)置(environment.rb設(shè)置):
緩存目錄:
config.action_controller.page_cache_directory = RAILS_ROOT + "/public/caches"
緩存類型:
config.action_controller.page_cache_extension = ".html"
缺點(diǎn):導(dǎo)致大量的數(shù)據(jù)從網(wǎng)絡(luò)驅(qū)動(dòng)器傳輸?shù)侥骋慌_(tái)具體的web服務(wù)器,然后將這些數(shù)據(jù)發(fā)送給用戶,所以,如果在高吐量的網(wǎng)站中使用這種存儲(chǔ)機(jī)制,服務(wù)器之間的網(wǎng)絡(luò)寬帶應(yīng)該非常寬。
緩存存儲(chǔ)體系只對(duì)action緩存和片段有效,全頁(yè)面緩存必須以文件的形式放在public目錄下。
頁(yè)面緩存是最快速的一種緩存應(yīng)用。那么應(yīng)該在什么時(shí)候使用他呢?
1、對(duì)于所有用戶都相同的頁(yè)面
2、公開(kāi)的頁(yè)面,沒(méi)有用戶認(rèn)證的頁(yè)面
緩存分頁(yè):
因?yàn)轫?yè)面緩存的時(shí)候會(huì)忽略掉像/blog /list?page=2這樣的參數(shù),所以你需要使用/blog/list/2這樣的地址形式,而原來(lái)我們使用的是id保存參數(shù)值,現(xiàn)在我們需要用 page來(lái)保存參數(shù)值。
下面我們修改 /config/routes.rb文件
map.connect 'blog/list/:page',
??? :controller => 'blog',
??? :action => 'list',
??? :requirements => { :page => /\d+/},
??? :page => nil
使用了新的routes定義,我們的連接也應(yīng)該改成
<%= link_to "Next Page", :controller => 'blog', :action => 'list', :page => 2 %>
最終的連接結(jié)果是"/blog/list/2",當(dāng)我們點(diǎn)這個(gè)連接的時(shí)候,后臺(tái)會(huì)處理兩件事情
1、應(yīng)用將2放入page這個(gè)參數(shù)中,而不是原來(lái)id這個(gè)參數(shù)
2、緩存將生成 /public/blog/list/2.html 這個(gè)頁(yè)面
所以,緩存分頁(yè),就要將頁(yè)面參數(shù)變成頁(yè)面的一部分,而不要使用地址參數(shù)的形式,他是會(huì)被忽略的。
解決危險(xiǎn)鏈接的方式:
1:使用表單和按鈕(button_to)
2:使用確認(rèn)頁(yè)面
link_to、link_to_if、link_to_unless、button_to
stylesheet_link_tag
javascript_include_tag:?? 假設(shè)文件在public/javascripts目錄
對(duì)象調(diào)用屬性:
eg: info.name 或 info["name"]
form_for、 form_tag
form_for(:info, @info, :url => {:action => "create"}, :html => {:method => "post"}
:info?? 告訴rails正在操作哪個(gè)模型類的對(duì)象
@info?? 通過(guò)哪個(gè)實(shí)例變量獲得該對(duì)象
:url??? 訪問(wèn)的action地址
:html?? 定義訪問(wèn)的方法,可以定義:multipart => true,上傳。
select標(biāo)簽:
1>collection_select(:post, :author_id, Author.all, :id, :name_with_initial, {:prompt => true})
2>select、select_tag "people", "<option>David</option>"
3>options_from_collection_for_select(@people, 'id', 'name')
4>options_for_select({ "Basic" => "$20", "Plus" => "$40" }, "$40")
子表單:
<% fields_for :name, @info.name do |field| %>
? Name: <%= field.text_field :name %>
<% end %>
卸載layout頁(yè)面中:
<% content_for :head do %>
? <ul><li>a</li><li>b</li></ul>
<% end %>
<%= yield :head %>
發(fā)送郵件:
config.action_mailer.delivery_method = :smtp|:sendmail|:test
開(kāi)發(fā)環(huán)境下默認(rèn)的設(shè)置是:smtp。
:smtp、:sendmail 可以讓ActionMailer發(fā)送郵件。
:test 可以用于單元測(cè)試和功能測(cè)試,電子郵件不會(huì)發(fā)送出去,而是被放入一個(gè)數(shù)組。
禁止開(kāi)發(fā)環(huán)境下發(fā)送郵件:
config/environments/development.rb中設(shè)置config.action_mailer.delivery_method = :test
config.action_mailer.perform_deliveries = true|false
perform_deliveries為true,郵件被正常發(fā)送,否則不發(fā)送,用于測(cè)試。
config.action_mailer.raise_delivery_errors = true|false
設(shè)置郵件發(fā)送過(guò)程中的異常是否拋還給應(yīng)用程序。false為忽略,true為拋還。
config.action_mailer.default_charset = "utf-8"
設(shè)置發(fā)送郵件的字符集。
ActionMailer::Base.smtp_settings = {
??? :address => "smtp.163.com",:port => 25,:domain => ".com",??? :authentication => :login,:user_name => "zhangcaiyan0123@163.com",:password => "zhangcaiyan",}
設(shè)置smtp服務(wù)器(其中domain是域名稱)
ruby script/generate mailer OrderMailer confirm sent
模型中定義方法:
? def confirm(sent_at = Time.now)
??? subject??? '標(biāo)題'
??? recipients "zhangcaiyanbeyond@gmail.com"
??? from?????? 'zhangcaiyan0123@163.com'
??? sent_on??? sent_at
??? body?????? "郵件正文"
? end
bcc????????? 暗送
cc?????????? 抄送
charset??????? 默認(rèn)為smtp_settings中的default_charset屬性
subject??????? 標(biāo)題
from??????? 發(fā)件人的郵箱
recipients???? 收件人的郵箱
body??????? 正文
send_on???? 發(fā)送時(shí)間
headers??????? 指定郵件的頭信息
attachment(上傳插件) :filename => 文件名稱, :body => 文件內(nèi)容(file.read), :content_type => "內(nèi)容類型"
OrderMailer.deliver_confirm?? 發(fā)送郵件
email = OrderMailer.create_confirm??? 創(chuàng)建郵件對(duì)象(TMail::Mail對(duì)象)
OrderMailer.deliver(email)
注意:? OrderMailer是模型類,create_confirm中的create是表示要?jiǎng)?chuàng)建對(duì)象,confirm是表示模型類中的方法,deliver表示要發(fā)送郵件。
保護(hù)rails應(yīng)用:
防御sql注入攻擊:
eg:這個(gè)實(shí)例就是惡意注入的例子,其中1為true,他會(huì)查處表中的所有數(shù)據(jù)。
Core::User.find(:all, :conditions => "id > '' or 1")
防止惡意注入:
絕對(duì)不要用ruby的#{...}機(jī)制直接把字符串插入到sql語(yǔ)句中,而應(yīng)該用Rails提供的變量綁定。
eg:
Core::User.find(:all, :conditions => ["id > ?", 3])
Core::User.find(:all, :conditions => ["id > :id", {:id => 3}])
用參數(shù)直接創(chuàng)建記錄:
User.create(params[:user])
為了防止用戶模擬一些屬性提交,我們可以將某些屬性保護(hù)起來(lái)。
attr_protected? :屬性1, :屬性2? 列出被保護(hù)的屬性
attr_accessible :屬性1, :屬性2? 列出允許自動(dòng)賦值的屬性,也就是說(shuō)除此之外的都是被保護(hù)的屬性
被保護(hù)的屬性也就是不能通過(guò)create(params[:user])直接保存,而是需要通過(guò)賦值才可以。eg:
user = User.new
user.role = params[:role]
user.save
不要相信ID參數(shù):
當(dāng)我們通過(guò)id查找出數(shù)據(jù),然后對(duì)數(shù)據(jù)進(jìn)行操作時(shí),我們要注意某些情況:例如當(dāng)我們?yōu)g覽(/show/id)某個(gè)用戶的數(shù)據(jù)時(shí),可以利用url瀏覽其他用戶的數(shù)據(jù),為了防止這樣的事發(fā)生,可以這樣:
eg:
1》 order = Order.find(params[:id], :conditions => ["user_id = ?", user_id])
2》 order = @user.orders.find(id)
3》 order = @user.orders.find(id).destroy
防御XSS攻擊:
攻擊者把自己編寫的javascript腳本放進(jìn)網(wǎng)頁(yè),來(lái)獲得他們想要的cookie,我們可以通過(guò)rails提供的h(string)輔助方法(實(shí)際上是html_escape()方法的別名)
生成rails項(xiàng)目的HTML文檔
rake doc:app
ActiveRecord::Errors.default_error_messages = hash
修改默認(rèn)錯(cuò)誤顯示信息
named_scope的使用:
named_scope :quanbu, :conditions => ["name=zcy"]
named_scope
ianzhi, :lambda{|limit|{:limit = limit}}
Shili.quanbu.xianzhi(3)
顯示錯(cuò)誤頁(yè)面:? 當(dāng)指定的異常發(fā)生時(shí),將顯示特定的頁(yè)面,這個(gè)最好放到application_controller中
rescue_from? 異常, :with => :action
eg:
rescue_from Exception, :with => :error
def error
? render :file => "novel/infos/error", :layout => "novel"
end
對(duì)于boolean類型的數(shù)據(jù),應(yīng)該省略前面的is_,ActiveRecord會(huì)自動(dòng)加個(gè)?號(hào),映射成actived? ,不是boolean型的數(shù)據(jù)也會(huì)也會(huì)擴(kuò)展?
_form下的共享表單,區(qū)間的情況
1:map.namespace :doctor do |doctor|
??? doctor.resources :patients
end
["doctor", @patient ]
2:map.resources :doctor do |doctor|
??? doctor.resources :patients
end
[@doctor, @patient ]
ruby script/server -e development(默認(rèn))
ruby script/server -e test
ruby script/server -e production
在編寫ruby代碼時(shí),如果要引用另一個(gè)文件中的類和模塊,需要使用require關(guān)鍵字,但是當(dāng)我們?cè)趓ails中引用另一個(gè)文件中的類和模塊時(shí),rails會(huì)自動(dòng)把類名稱根據(jù)命名約定改為文件名,然后在同一目錄下加載該文件。
按模塊組織控制器:
ruby script/generate controller Admin::Book action1 action2
admin模塊下的book_controller控制器
Rails給Enumerable類擴(kuò)展的方法
1》 group_by: 將一個(gè)對(duì)象集合分組,針對(duì)每個(gè)對(duì)象調(diào)用塊,然后根據(jù)代碼塊的返回值作為分組的鍵,值是所有擁有同一個(gè)鍵的對(duì)象組成的數(shù)組。
eg:
User.all.group_by{|user| user.sex}
User.all.group_by(&:name)
2》 sum: 對(duì)集合進(jìn)行加總,把每個(gè)元素傳遞給一個(gè)代碼塊,并對(duì)代碼塊返回的值進(jìn)行累加。
User.all.sum(&:id) 返回所有user對(duì)象的id的和
3》 in_groups_of(arg1, arg2)? 將某一個(gè)數(shù)組分為子元素由arg1個(gè)元素組合的數(shù)組元素組成的數(shù)組,出現(xiàn)無(wú)法填充的值由arg2填補(bǔ)。
eg:
[1,2,3,4,5].in_groups_of(2,"blank")???? =>?????
[[1,2],[3,4],[5,"blank"]]
字符串?dāng)U展
str[0] 第一個(gè)字符的Ascill碼。
str[2..3] 返回字符串的第三個(gè)字符開(kāi)始的3個(gè)字符組成的字符串。
str.at(0) 第一個(gè)字符
str.to(4) 前5個(gè)字符組成的字符串
str.from(4) 最后5個(gè)字符組成的字符串
str.first
str.last
str.starts_with?(字符串)
str.ends_with?(字符串)
str.each_char{|char| char.upcase}
str.pluralize 復(fù)數(shù)形式
str.singularize? 單數(shù)形式
str.humanize
str.titleize
對(duì)數(shù)值的擴(kuò)展:
figure.ordinalize?? 返回?cái)?shù)字的序數(shù)形式
figure.bytes、kilobytes、megabytes、gigabytes、terabytes、
perabytes、exabyte? 數(shù)據(jù)大小
figure.seconds、minutes、hours、days、weeks、fortnights、months、years? 時(shí)間
注意:? ago、 until、 from_now、 since
eg:?
1.day.ago
1.day.ago(Time.now)
時(shí)間和日期的擴(kuò)展
now = Time.now
now.to_s(:short)、to_s(:db)、to_s(:long)、to_s(:rfc822)
now.ago(2.days)、since(2.days)
change(:hour => 12)? 改變?nèi)掌诘膆our為12
advance(:hour => 12)? 推遲日期的12hour
to_date、to_time
at_beginning_of_week、at_beginning_of_month、at_beginning_of_quarter(季)、at_beginning_of_year
ruby符號(hào)的擴(kuò)展:
posts.group_by{|post| post.author_id}
posts.group_by(&:author_id)
with_options的使用:
Rails里有些方法使用一個(gè)Hash作為最后一個(gè)可選的參數(shù),如果對(duì)多個(gè)方法有同樣的選項(xiàng),我們可以使用with_options來(lái)減少冗余:
eg:
with_options :if => :should_validate_password? do |user|?
? user.validates_presence_of :password?
? user.validates_confirmation_for :password?
? user.validates_format_of :password, :with => /^[^\s]+$/
end
遷移任務(wù):
create_table??
:force => true? 如果表存在,強(qiáng)制刪除,然后再創(chuàng)建表
:temporary => true? 創(chuàng)建一張臨時(shí)表,程序與數(shù)據(jù)庫(kù)斷開(kāi)鏈接,則表被刪除。
:options => "xxxx"? 指定針對(duì)于底層數(shù)據(jù)庫(kù)的選項(xiàng),這些選項(xiàng)會(huì)被加到create table語(yǔ)句的后面
:primary_key 主鍵
:id => false? 沒(méi)有主鍵的表
如果遷移任務(wù) 提供的方法 不夠滿足你 的需要,也 可以使用數(shù) 據(jù)庫(kù)專有的 功能:使用execute() 方法就可以運(yùn)行原生 SQL 語(yǔ)句。例如:給表加上外鍵
class CreateLineItems < ActiveRecord::Migration
??? def self.up
????? create_table :line_items do |t|
??????? t.column :product_id, :integer
??????? t.column

????? end
????? execute "alter table line_items
????????? add constraint fk_line_item_products
????????? foreign key (product_id) references products(id)"
??? end
???? def self.down
????? drop_table :line_items
???? end
end
ActiveRecord::Base
column_names? 屬性組成的數(shù)組
columns_hash["屬性名稱"]? 屬性名稱信息
屬性_before_type_cast? 讀取屬性時(shí),ActiveRecod會(huì)盡量將得到的值轉(zhuǎn)型成適當(dāng)?shù)膔uby類型,如果我們希望的到屬性的原始值,可以在屬性名稱后面加上before_type_cast。
eg:User.first.created_at??? =>?? 2010-06-24 09:41:17
連接數(shù)據(jù)庫(kù):? ActiveRecord::Base.establish_connection(:adapter => "mysql", :host => "localhost", :database => "rails", :username => "root", :password => "1234")
防止惡意注入:
1> 問(wèn)號(hào)占位符:?? User.find(:all, :conditions => ["id > ?", 3]
2> 命名占位符:?? User.find(:all, :conditions => ["id > :id", {:id => 3}])
注意:
命名占位符的語(yǔ)句可以轉(zhuǎn)換為
User.find(:all, :conditions => ["id > :id", params[:user]])
獲取字段統(tǒng)計(jì)信息:
average:?
maximum:
minimum:
sum? :
count? :
以上方法的參數(shù):?
:conditions、:joins、:limit、:order、:having、:select、 :distinct
eg:
Order.maximum :amount, :group => "state", :limit => 3,

擁有訂單最大的三個(gè)州
更新操作:
update_attribute、update_attributes、update、update_all
創(chuàng)建操作:
create、create!、save、save!
刪除數(shù)據(jù):
delete、delete_all、destroy、destroy_all
delete繞過(guò)了ActiveRecord的回調(diào)和驗(yàn)證,destory沒(méi)有繞過(guò)回調(diào)和驗(yàn)證
序列化數(shù)據(jù):
serialize :屬性
序列化的屬性可以直接存入Array和hash類型的數(shù)據(jù),也可以直接讀出來(lái)使用
缺點(diǎn):
ruby應(yīng)用之外的應(yīng)用訪問(wèn)序列化的數(shù)據(jù)時(shí),除非它能夠理解yaml格式,否則無(wú)法獲取這個(gè)字段的信息。
彌補(bǔ)這種缺點(diǎn)的方式是用對(duì)象聚合的方式來(lái)實(shí)現(xiàn)類似的效果
聚合/組合:
聚合可以把一個(gè)或多個(gè)屬性封裝為一個(gè)類,然后這個(gè)類里可以添加操作屬性的方法,這樣我們就可以實(shí)現(xiàn)序列化所要實(shí)現(xiàn)的目的了,而且可以避免序列化的缺點(diǎn)。
composed_of :attr_name, :class_name => 類名稱, :mapping => [字段與屬性組成的數(shù)組]
eg:
class Xingxi < ActiveRecord::Base
? composed_of :inf, :class_name => "Inf", :mapping => [[:name, :name], [:phone, :phone]]
end
class Inf
??? attr_reader :name, :phone
??? def initialize(name, phone)
??????? @name = name
??????? @phone = phone
??? end
??? def to_s
????? [@name, @phone].compact.join(" ")
??? end
end
inf = Inf.new("zcy",? "12344454")
Xingxi.create(:inf => inf)
注意:
教程上指出? :class_name對(duì)應(yīng)的“類名稱”可以是類常量,也可以是包含類常量的字符串,但實(shí)際上只能是包含類常量的字符串,如果類名恰好是屬性名的混合大寫形式,那么class_name可以省略,但是實(shí)際上不可以,包括:mapping也不可以。
關(guān)聯(lián):
class Line < ActiveRecord::Base
? belongs_to :product
end
belongs_to :product? 會(huì)產(chǎn)生以下方法
1>:product(force_reload=false) 返回關(guān)聯(lián)的product對(duì)象,默認(rèn)情況下product對(duì)象會(huì)被緩存,當(dāng)force_reload=true時(shí),將重新查詢數(shù)據(jù)庫(kù)。
2>:product=: line對(duì)象和product對(duì)象關(guān)聯(lián)起來(lái),將line記錄的外鍵值設(shè)為product的主鍵值,如果product沒(méi)有保存,line保存的時(shí)候會(huì)保存product,包括外鍵。
3>:build_product(attributes={}) 新建一個(gè)product對(duì)象,用指定的屬性對(duì)其初始化,相當(dāng)于product=Product.new(attributes)。
4>:build_create(attributes={}) 創(chuàng)建一個(gè)product對(duì)象,與line關(guān)聯(lián),保存product對(duì)象。
order:? has_one中也有order,主要用于例如最后一個(gè)***,此時(shí)便可以用order指定排序。
:dependent?? :destroy(true)、:nullify、 false
??? :destroy?? 刪除記錄的同時(shí)也刪除子記錄
??? :nullify?? 刪除記錄的同時(shí)刪除子記錄的外鍵
??? false????? 只刪除記錄
has_many :lines
class Product < ActiveRecord::Base
? has_many :lines
end
has_many :lines? 會(huì)產(chǎn)生以下方法
lines(force_reload=false)? 同上
lines.build(attributes = {})
lines.create(attributes = {})
lines << line? 將當(dāng)前l(fā)ine對(duì)象添加到lines對(duì)象數(shù)組里
lines.push(line對(duì)象) line對(duì)象添加到lines
lines.delete(line,...) 刪除一個(gè)或多個(gè)line對(duì)象,如果關(guān)聯(lián)為:destroy => :destroy,子對(duì)象被刪除,否則只是刪除子對(duì)象的外鍵,打斷與父對(duì)象的關(guān)聯(lián)。
lines.delete_all? 調(diào)用所有子對(duì)象的delete方法
lines.destroy_all?? 調(diào)用所有子對(duì)象的destroy方法
lines.clear? 和delete一樣,不同的是clear針對(duì)的是所有的子對(duì)象。
lines.find(options)
lines.count(options)
lines.size
lines.length? 強(qiáng)制加載所有子對(duì)象,返回對(duì)象的集合。
lines.empty?
lines.replace(line對(duì)象數(shù)組)? line對(duì)象數(shù)組替換原先的lines
lines.sum(options) 不便利內(nèi)存中的子對(duì)象集合,直接在數(shù)據(jù)庫(kù)端操作
lines.uniq? 返回一個(gè)數(shù)組,包含所有具備獨(dú)立id的子對(duì)象
1> finder_sql: 重新定義了統(tǒng)計(jì)子記錄的sql語(yǔ)句
?? counter_sql: 重新定義了統(tǒng)計(jì)子記錄的數(shù)目
注意: 如果指定了finder_sql而沒(méi)有指定counter_sql,finder_sql中的子句會(huì)被替換為select count(*),然后記錄子記錄的數(shù)量。
eg:
has_many

作用: 當(dāng):conditions無(wú)法滿足時(shí),:finder_sql顯的非常重要。
:order : 以特定的順序排列
:conditions : 返回符合條件的子記錄
:dependent?? :destroy、:nullify、 false
??? :destroy?? 刪除記錄的同時(shí)也刪除子記錄
??? :nullify?? 刪除記錄的同時(shí)刪除子記錄的外鍵
??? false????? 只刪除記錄
多對(duì)多的關(guān)聯(lián)有兩種
1: 利用默認(rèn)的關(guān)聯(lián)表
2:自己創(chuàng)建關(guān)聯(lián)表,利用關(guān)聯(lián)中的:through
:through?? 告訴rails通過(guò)guanlians表來(lái)導(dǎo)航關(guān)聯(lián)
:source? 用來(lái)指定關(guān)聯(lián)在那個(gè)屬性上
:uniq => true? 去掉重復(fù)的對(duì)象 等同于 :select => "distinct books.*"
eg:
class Kind < ActiveRecord::Base
??? has_many :guanlians
??? has_many :readers, :through => :guanlians, :source => :book
end
注意:
has_many :reader1s,:conditions => "guanlians.cishu > 0"
當(dāng)使用conditions不能很好的表達(dá)時(shí),無(wú)法提供參數(shù),可以考慮以下格式,而且當(dāng)同樣的方法被多次調(diào)用時(shí),可以將方法寫在模塊中,然后在關(guān)聯(lián)中:extend => "模塊名稱" 來(lái)調(diào)用。
has_many :readers do
??? def reader(limit = 3)
??????? find(:all, :limit => limit)
??? end
end
單表繼承:?
優(yōu)點(diǎn):? 這樣做的好處是提高讀取表的速度,因?yàn)闆](méi)有關(guān)聯(lián),只有一個(gè)表。
缺點(diǎn):? 當(dāng)各個(gè)子類的相似的地方很少的時(shí)候,會(huì)導(dǎo)致表中有很多屬性,這樣處理這個(gè)問(wèn)題的方法是用多態(tài)關(guān)聯(lián)。
多態(tài)關(guān)聯(lián):
types表中的多態(tài)外鍵如果是duotai,那么表的屬性是duotai_id, duotai_type,一個(gè)記錄鍵值,一個(gè)記錄類名。
class Article < ActiveRecord::Base
??? has_one :type, :as => :duotai
end
class Image < ActiveRecord::Base
??? has_one :type, :as => :duotai
end
class Type < ActiveRecord::Base
??? belongs_to :duotai, :polymorphic => true
end
自引用的連接:
class Employee < ActiveRecord::Base
? belongs_to :boss, :class_name => "Employee", :foreign_key => :employee_id
end
預(yù)先讀取子記錄
以下實(shí)例如果沒(méi)有:include => :people, infos為n, 那么他將執(zhí)行2n+1次,如果指定了:include,將預(yù)加載與info有關(guān)的people記錄,此時(shí)將提高效率,但是如果預(yù)加載了數(shù)據(jù),但沒(méi)有用這些數(shù)據(jù),反而會(huì)降低效率。
Benchmark.bm() do |x|
??? x.report{
??????? infos = Info.find(:all, :include => :people)
??????? infos.each do |info|
??????????? info.people.name
??????? end
??? }
end
如果一個(gè)對(duì)象剛剛創(chuàng)建出來(lái),還沒(méi)有與數(shù)據(jù)庫(kù)記錄建立映射,我們稱它為新對(duì)象(new records)。調(diào)用new_records?
模型驗(yàn)證:
validate、 validate_on_create、 validate_on_update
ActiveRecord::Errors
[]? info.errors[:email]
on? info.errors.on(:email)
add(:屬性, 信息)
size、length、count
each、each_error? 迭代錯(cuò)誤屬性和錯(cuò)誤屬性對(duì)應(yīng)的信息
each_full? 迭代錯(cuò)誤信息
full_messages? 錯(cuò)誤信息組成的數(shù)組
invalid?(屬性)? 如果屬性無(wú)效,則返回true
to_xml
empty?
ActiveRecord::Errors.default_error_messages? 這個(gè)返回所有的默認(rèn)信息,如果修改默認(rèn)信息的話,可以從這里修改。
回調(diào):
創(chuàng)建方式
1:直接在回調(diào)中寫代碼。
2:聲明回調(diào)處理器,處理器可以是一個(gè)代碼塊也可以是一個(gè)方法,如果用方法作為一個(gè)處理器,應(yīng)該被聲明為private或protected。
eg
def before_save
? ...
end
before_save :check
private
def check
end
注意:以下方法將跳過(guò)回調(diào)
??? * decrement
??? * decrement_counter
??? * delete
??? * delete_all
??? * find_by_sql
??? * increment
??? * increment_counter
??? * toggle
??? * update_all
??? * update_counters
ActiveRecord::Base
column_names:? 所有列名組成的數(shù)組
columns:? 所有包含列信息的對(duì)象組成的數(shù)組。
columns_hash:?? 列名與列對(duì)象組成的hash數(shù)組。
實(shí)例方法:
attributes:? 所有屬性和屬性值組成的hash數(shù)組。
attributes=
attribute_names:? 所有屬性組成的數(shù)組。
attribute_present?(屬性名稱) 如果屬性名稱存在,則返回true,反之亦然。
事務(wù): 要么全部執(zhí)行,要么全部不執(zhí)行。
模型類.transaction do
end
begin ... rescue ...end
eg:
class Info < ActiveRecord::Base
? def validate
??? errors.add(:age, "age is not less than 0") if age < 0
? end
? def jian(i)
??? self.money = self.money - i
??? self.save!
? end
end
info = Info.create!(:money => 100)
begin
Info.transaction do; info.jian(200); end
rescue
end
puts info.money?? =》 -100
該實(shí)例中要求money不能小于0,而我們也做到了,表中的數(shù)據(jù)不會(huì)被改,但是info.money 返回的值是-100,模型對(duì)象的值被該變了,這是因?yàn)锳ctiveRecord沒(méi)有跟綜對(duì)象在事務(wù)前后的狀態(tài),我們可以指定事務(wù)跟蹤哪些模型對(duì)象。
Info.transaction(info) do; .... end,此時(shí)輸出的值就是100了。
路由:
map.connect 重要參數(shù)
:requirements => {:name => /regexp/}? 要求url中特定的組成部分與指定的正則表達(dá)式一一匹配。
:defaults => {:name => "value", ...}? 設(shè)定各組成部分的默認(rèn)值
:conditions => {:name => /regexp/orstring,...}? 設(shè)定路由的條件
:name => value? 設(shè)定:name參數(shù)的默認(rèn)值
eg:
map.connect 'infos/:year', :controller => "infos", :action => "hello", :defaults => {:year => 2008},:requirements => {:year => /(19|20)\d\d/}, :conditions => {:method => :get}
注意:
map.connect "*aa", :controller => "", :action => ""
符合任何的url格式,但是一定要注意的是要放在最后,否則其他的路由都無(wú)法匹配了。
有名路由
map.hello "hello/:id", :controller => "infos", :action => "index"
1>? hello_url(:id => 1)或hello_url :controller => "infos", :action => "index"
可以訪問(wèn)這個(gè)url。
注意: 以上url可以用path替代。
2>? 地址欄中可以輸入hello訪問(wèn)這個(gè)url。
資源路由:
map.resources :articles, :collection => {:recent => :get}, :member => {:release => :put}, :new => {:hello => :get}
增加以下規(guī)則:
recent_articles_path
release_article_path(:id => 1)
hello_new_article_path
map.resources :articles do |article|
? article.resources :comments
end
articles/99/comments/4
控制器環(huán)境(可以在action中直接引用)
controller_name:? controller名稱
action_name:? action名稱
session: session
cookies: cookie
params: 存放著參數(shù)的hash對(duì)象
rsponse
request: 進(jìn)入控制器的請(qǐng)求對(duì)象,包含屬性。
? domain: 請(qǐng)求地址域名部分的最后兩端。
? remote_ip: 客戶端的ip地址。
? env: 返回請(qǐng)求的環(huán)境。
? get?、post?、put?、delete?、head?
? method:? 返回客戶端訪問(wèn)所使用的請(qǐng)求方法。
? xhr?或xml_http_request?? 如果請(qǐng)求來(lái)自AJAX的輔助方法,則返回true,否則返回false。
控制器應(yīng)答:
1:渲染一個(gè)模板,最常見(jiàn)的(.html、 .rxml、 .rjs)。
2:返回一個(gè)字符串給瀏覽器,主要用于發(fā)送錯(cuò)誤提示。
3:發(fā)送html以外的數(shù)據(jù),這種方式通常用于提供下載。
控制器每次只響應(yīng)一個(gè)請(qǐng)求:
render、 redirect_to、 send_xxx
1> render :action
2> render :template
3> render :file
4> render :partial? 調(diào)用局部模板
:object 指定傳遞給局部模板的對(duì)象。
5> render

6> render :nothing
7> render :inline
8> render :text
9> render(:update) do |page| ... end
重要參數(shù):
:locals => {},指定模板要使用的局部變量。
:layout => false|nil|true|模板名稱。
render_to_string 可以當(dāng)作render使用,不過(guò)它不會(huì)跳轉(zhuǎn),只會(huì)把整個(gè)的內(nèi)容作為字符串返回。
method_missing:調(diào)用指定的action名稱無(wú)效時(shí),method_missing會(huì)渲染一個(gè)內(nèi)聯(lián)的模板,將action的名稱和請(qǐng)求參數(shù)顯示出來(lái)。
eg:
? def method_missing(name, *args)
??? render(:inline => %{<h2> Unknown action: #{name}</h2>
??? Here are the request parameters:<br/>
??? <%= debug(params) %>})
? end
send_data(data, options)? 發(fā)送一個(gè)數(shù)據(jù)流給客戶端。
參數(shù):
:filename、 disposition(inline|attachment)、status、type
send_file(path, options)? 發(fā)送一個(gè)文件給客戶端
參數(shù):
:filename、 :disposition、 :status、 :type、 buffer_size、 stream
重定向:
redirect_to(:action => "")
redirect_to(path)
redirect_to(:back)? 返回上一頁(yè),注意:如果redirect_to(:back)寫在了index的action中,并且訪問(wèn)index的時(shí)候能夠直接運(yùn)行redirect_to(:back),則不能直接訪問(wèn)index的action,因?yàn)樗麜?huì)跳轉(zhuǎn)上一頁(yè),但是沒(méi)有上一頁(yè)。
過(guò)濾器:
prepend_before_filter
before_filter、append_before_filter
prepend_after_filter
after_filter、append_before_filter
參數(shù):
:only、 :except
定義過(guò)濾器的方式:
1:
before_filter do
? ...
end
2:
before_filter :hello,

skip_filter、 skip_before_filter、skip_after_filter
參數(shù):
:only、 :except
緩存:
片段緩存、 頁(yè)面緩存、 action緩存
caches_page、 caches_action、 cache do .... end
默認(rèn)配置下,cache只有在產(chǎn)品環(huán)境下才生效,如果要在開(kāi)發(fā)環(huán)境下生效,要配置以下信息中的一條。(config/environments/development.rb)
ActionController::Base.perform_caching = true|false
config.action_controller.perform_caching = true
解除緩存:
expire_action、 expire_page、 expire_fragment :controller => "...", :action => "..."
1》默認(rèn):緩存片段的名字取決于渲染該頁(yè)面的控制器名稱和action名稱,所以使用expire_fragment指定控制器名稱和action名稱來(lái)是對(duì)應(yīng)的片段緩存失效。
2》指定緩存名稱(等同于url_for的參數(shù))
緩存存儲(chǔ)機(jī)制的全局設(shè)置(environment.rb設(shè)置):
緩存目錄:
config.action_controller.page_cache_directory = RAILS_ROOT + "/public/caches"
緩存類型:
config.action_controller.page_cache_extension = ".html"
缺點(diǎn):導(dǎo)致大量的數(shù)據(jù)從網(wǎng)絡(luò)驅(qū)動(dòng)器傳輸?shù)侥骋慌_(tái)具體的web服務(wù)器,然后將這些數(shù)據(jù)發(fā)送給用戶,所以,如果在高吐量的網(wǎng)站中使用這種存儲(chǔ)機(jī)制,服務(wù)器之間的網(wǎng)絡(luò)寬帶應(yīng)該非常寬。
緩存存儲(chǔ)體系只對(duì)action緩存和片段有效,全頁(yè)面緩存必須以文件的形式放在public目錄下。
頁(yè)面緩存是最快速的一種緩存應(yīng)用。那么應(yīng)該在什么時(shí)候使用他呢?
1、對(duì)于所有用戶都相同的頁(yè)面
2、公開(kāi)的頁(yè)面,沒(méi)有用戶認(rèn)證的頁(yè)面
緩存分頁(yè):
因?yàn)轫?yè)面緩存的時(shí)候會(huì)忽略掉像/blog /list?page=2這樣的參數(shù),所以你需要使用/blog/list/2這樣的地址形式,而原來(lái)我們使用的是id保存參數(shù)值,現(xiàn)在我們需要用 page來(lái)保存參數(shù)值。
下面我們修改 /config/routes.rb文件
map.connect 'blog/list/:page',
??? :controller => 'blog',
??? :action => 'list',
??? :requirements => { :page => /\d+/},
??? :page => nil
使用了新的routes定義,我們的連接也應(yīng)該改成
<%= link_to "Next Page", :controller => 'blog', :action => 'list', :page => 2 %>
最終的連接結(jié)果是"/blog/list/2",當(dāng)我們點(diǎn)這個(gè)連接的時(shí)候,后臺(tái)會(huì)處理兩件事情
1、應(yīng)用將2放入page這個(gè)參數(shù)中,而不是原來(lái)id這個(gè)參數(shù)
2、緩存將生成 /public/blog/list/2.html 這個(gè)頁(yè)面
所以,緩存分頁(yè),就要將頁(yè)面參數(shù)變成頁(yè)面的一部分,而不要使用地址參數(shù)的形式,他是會(huì)被忽略的。
解決危險(xiǎn)鏈接的方式:
1:使用表單和按鈕(button_to)
2:使用確認(rèn)頁(yè)面
link_to、link_to_if、link_to_unless、button_to
stylesheet_link_tag
javascript_include_tag:?? 假設(shè)文件在public/javascripts目錄
對(duì)象調(diào)用屬性:
eg: info.name 或 info["name"]
form_for、 form_tag
form_for(:info, @info, :url => {:action => "create"}, :html => {:method => "post"}
:info?? 告訴rails正在操作哪個(gè)模型類的對(duì)象
@info?? 通過(guò)哪個(gè)實(shí)例變量獲得該對(duì)象
:url??? 訪問(wèn)的action地址
:html?? 定義訪問(wèn)的方法,可以定義:multipart => true,上傳。
select標(biāo)簽:
1>collection_select(:post, :author_id, Author.all, :id, :name_with_initial, {:prompt => true})
2>select、select_tag "people", "<option>David</option>"
3>options_from_collection_for_select(@people, 'id', 'name')
4>options_for_select({ "Basic" => "$20", "Plus" => "$40" }, "$40")
子表單:
<% fields_for :name, @info.name do |field| %>
? Name: <%= field.text_field :name %>
<% end %>
卸載layout頁(yè)面中:
<% content_for :head do %>
? <ul><li>a</li><li>b</li></ul>
<% end %>
<%= yield :head %>
發(fā)送郵件:
config.action_mailer.delivery_method = :smtp|:sendmail|:test
開(kāi)發(fā)環(huán)境下默認(rèn)的設(shè)置是:smtp。
:smtp、:sendmail 可以讓ActionMailer發(fā)送郵件。
:test 可以用于單元測(cè)試和功能測(cè)試,電子郵件不會(huì)發(fā)送出去,而是被放入一個(gè)數(shù)組。
禁止開(kāi)發(fā)環(huán)境下發(fā)送郵件:
config/environments/development.rb中設(shè)置config.action_mailer.delivery_method = :test
config.action_mailer.perform_deliveries = true|false
perform_deliveries為true,郵件被正常發(fā)送,否則不發(fā)送,用于測(cè)試。
config.action_mailer.raise_delivery_errors = true|false
設(shè)置郵件發(fā)送過(guò)程中的異常是否拋還給應(yīng)用程序。false為忽略,true為拋還。
config.action_mailer.default_charset = "utf-8"
設(shè)置發(fā)送郵件的字符集。
ActionMailer::Base.smtp_settings = {
??? :address => "smtp.163.com",:port => 25,:domain => ".com",??? :authentication => :login,:user_name => "zhangcaiyan0123@163.com",:password => "zhangcaiyan",}
設(shè)置smtp服務(wù)器(其中domain是域名稱)
ruby script/generate mailer OrderMailer confirm sent
模型中定義方法:
? def confirm(sent_at = Time.now)
??? subject??? '標(biāo)題'
??? recipients "zhangcaiyanbeyond@gmail.com"
??? from?????? 'zhangcaiyan0123@163.com'
??? sent_on??? sent_at
??? body?????? "郵件正文"
? end
bcc????????? 暗送
cc?????????? 抄送
charset??????? 默認(rèn)為smtp_settings中的default_charset屬性
subject??????? 標(biāo)題
from??????? 發(fā)件人的郵箱
recipients???? 收件人的郵箱
body??????? 正文
send_on???? 發(fā)送時(shí)間
headers??????? 指定郵件的頭信息
attachment(上傳插件) :filename => 文件名稱, :body => 文件內(nèi)容(file.read), :content_type => "內(nèi)容類型"
OrderMailer.deliver_confirm?? 發(fā)送郵件
email = OrderMailer.create_confirm??? 創(chuàng)建郵件對(duì)象(TMail::Mail對(duì)象)
OrderMailer.deliver(email)
注意:? OrderMailer是模型類,create_confirm中的create是表示要?jiǎng)?chuàng)建對(duì)象,confirm是表示模型類中的方法,deliver表示要發(fā)送郵件。
保護(hù)rails應(yīng)用:
防御sql注入攻擊:
eg:這個(gè)實(shí)例就是惡意注入的例子,其中1為true,他會(huì)查處表中的所有數(shù)據(jù)。
Core::User.find(:all, :conditions => "id > '' or 1")
防止惡意注入:
絕對(duì)不要用ruby的#{...}機(jī)制直接把字符串插入到sql語(yǔ)句中,而應(yīng)該用Rails提供的變量綁定。
eg:
Core::User.find(:all, :conditions => ["id > ?", 3])
Core::User.find(:all, :conditions => ["id > :id", {:id => 3}])
用參數(shù)直接創(chuàng)建記錄:
User.create(params[:user])
為了防止用戶模擬一些屬性提交,我們可以將某些屬性保護(hù)起來(lái)。
attr_protected? :屬性1, :屬性2? 列出被保護(hù)的屬性
attr_accessible :屬性1, :屬性2? 列出允許自動(dòng)賦值的屬性,也就是說(shuō)除此之外的都是被保護(hù)的屬性
被保護(hù)的屬性也就是不能通過(guò)create(params[:user])直接保存,而是需要通過(guò)賦值才可以。eg:
user = User.new
user.role = params[:role]
user.save
不要相信ID參數(shù):
當(dāng)我們通過(guò)id查找出數(shù)據(jù),然后對(duì)數(shù)據(jù)進(jìn)行操作時(shí),我們要注意某些情況:例如當(dāng)我們?yōu)g覽(/show/id)某個(gè)用戶的數(shù)據(jù)時(shí),可以利用url瀏覽其他用戶的數(shù)據(jù),為了防止這樣的事發(fā)生,可以這樣:
eg:
1》 order = Order.find(params[:id], :conditions => ["user_id = ?", user_id])
2》 order = @user.orders.find(id)
3》 order = @user.orders.find(id).destroy
防御XSS攻擊:
攻擊者把自己編寫的javascript腳本放進(jìn)網(wǎng)頁(yè),來(lái)獲得他們想要的cookie,我們可以通過(guò)rails提供的h(string)輔助方法(實(shí)際上是html_escape()方法的別名)
生成rails項(xiàng)目的HTML文檔
rake doc:app
ActiveRecord::Errors.default_error_messages = hash
修改默認(rèn)錯(cuò)誤顯示信息
named_scope的使用:
named_scope :quanbu, :conditions => ["name=zcy"]
named_scope

Shili.quanbu.xianzhi(3)
顯示錯(cuò)誤頁(yè)面:? 當(dāng)指定的異常發(fā)生時(shí),將顯示特定的頁(yè)面,這個(gè)最好放到application_controller中
rescue_from? 異常, :with => :action
eg:
rescue_from Exception, :with => :error
def error
? render :file => "novel/infos/error", :layout => "novel"
end
對(duì)于boolean類型的數(shù)據(jù),應(yīng)該省略前面的is_,ActiveRecord會(huì)自動(dòng)加個(gè)?號(hào),映射成actived? ,不是boolean型的數(shù)據(jù)也會(huì)也會(huì)擴(kuò)展?
_form下的共享表單,區(qū)間的情況
1:map.namespace :doctor do |doctor|
??? doctor.resources :patients
end
["doctor", @patient ]
2:map.resources :doctor do |doctor|
??? doctor.resources :patients
end
[@doctor, @patient ]
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
