Create & Save
創建 & 保存
order = Order.new order.name = "virusswb" order.email = "[email protected]" order.save
調用save方法之後就可以保存到數據庫了。
還可以用block來創建並保存。
Order.new do |order| order.name = "virusswb" order.email = "[email protected]" order.save end
還可以使用hash的方式創建並保存。
order = Order.new( :name => "virus", :email => "[email protected]" ) order.save
默認id主鍵不用賦值,是integer的自增列。
上面的方法都需要調用save方法才 能保存到數據庫,用create方法可以合二為一,創建同時保存到數據庫。
order = Order.create( :name => "virus", :email => "[email protected]" )
還可以一次保存多個,只要給create傳遞一個數組就可以實現。
orders = Order.create( [{ :name => "virus1", :email => "[email protected]" }, { :name => "swb2", :email => "[email protected]" }] )
返回也是一個數組。
從form放入參數中直接創建一個model對象。
@order = Order.new(params[:order])
Order.find(1)可以用來獲取id=1的model,但是如果數據表中不存在 id=1的model,就會拋出RecordNotFound異常。
如果使用Order.where(:id => 1).first,是告訴數 據庫“我需要id=1的記錄”,如果不存在這樣的記錄,不會拋出異常,返回的是nil。
Reading Existing Rows
讀取
an_order = Order.find(27)
返回一條記錄,如果沒有,會拋出 RecordNotFound異常。
product_list = params[:product_ids]
total = Product.find (product_list).sum(&:price)
給find傳入array,可以實現多條記錄的查詢,但是如果其中一個 id不存在的話,還是會拋出RecordNotFound異常 。
Dynamic Finders
動態查詢
有時候 我們會針對model的一列進行查詢,在rails中不用寫sql就可以實現。
order = Order.find_by_name ("virus")
orders = Order.find_all_by_name("virus")
orders = Order.find_all_by_email(params['email'])
order = Order.find_by_name ("virus")
和
order = Order.where(:name => "virus").first
效果是一樣的。
還有find_all_by_xxx和find_last_by_xxx這樣的查詢。
如果在find_by_方法 後面加上一個!,就會在找不到記錄的情況下拋出RecordNotFound異常。
order = Order.find_by_name!("virus")
還可以多列查詢。
order = Order.find_by_name_and_password(name,pw)
和
order = Order.where(:name => name, :password => pw).first
是一樣的效果。
有些情況下,你想要確保有model,如果在數據 庫中不存在,就創建一個,動態的finders就可以實現這個需求。find_or_initialize_by_或者 find_or_create_by_可以實現沒有滿足條件的記錄,就返回nil,就會創建或者直接保存記錄。
cart = Cart.find_or_initialize_by_user_id(user.id)
cart.items << new_item
cart.save
SQL and ActiveRecord
在AcriveRecord中使用SQL
用model的where方法可以實現sql語 句的where子句。
pos = Order.where("name = 'virus' and emal = '[email protected]'")
接收外部傳過來的name的值。
name = params[:name]
pos = Order.where("name = '#{name}' and email = '[email protected]'")
上面拼接sql語句的方式,會受到sql注入攻擊。
安全的方式是讓ActiveRecord來處理,參數化 。
name = params[:name]
pos = Order.where(["name = ? and email ='sd'", name])
name = params[:name]
email = params[:email]
pos = Order.where("name = :name and email = :email",
{ :name => name, :email => email})
因為params已經 是hash了,可以簡潔一些。
pos = Order.where("name = :name and email = :email",
params[:order])
還可以更 簡潔一些。
pos = Order.where(params[:order])
要小心上面的寫法,它使用了所有的參數 ,通過下面的寫法,你可以指定使用哪些參數。
pos = Order.where( :name => params[:name], :email => params[:email])
Using like Clauses
使用like子句
User.where ("name like ?", params[:name] + "%")
Subsetting the Recods Returned
返回部分數據
order排序
orders = Order.where(:name => params [:name])
.order("name, email desc")
limit限制返回的條數
orders = Order.where(:name => params[:name])
.order("name, email desc")
.limit(10)
offset跳過行
offset相當於mysql中的skip。
def Order.find_on_page(page_num, page_size) orders = Order.where(:name => params[:name]) .order("name, email desc") .limit(page_size) .offset(page_num*page_size) end
select選擇列
默認選擇所有的列,可以通過select來查詢需要的列。
orders = Order.where(:name => params[:name]) .order("name, email desc") .select("name, email")
joins連接
LineItem.select('li.quantity') .where("pr.title = 'programming in ruby'") .joins("as li inner join products pr on li.product_id=pr.id")
readonly只讀
使用 readonly方法獲取的記錄,不能再保存回數據庫。
如果使用joins或者是select方法,返回的對象自動 標記為readonly。
group分組
會產生group by子句。
summary = LineItem.select (select = > "sku, sum(amount) as amount")
.group("sku")
lock鎖
lock方法的參數是一個字符串,告訴數據庫使用指定類型的鎖。
在mysql中共享鎖返回最新的 數據行,並且確保沒有人可以在鎖期間修改這條記錄。
Account.transaction do ac = Account.where(:id => id).lock("LOCK IN SHARE MODE").first ac.balance -= amount if ac.balance > amount ac.save end
Getting Column Statistics
聚合統計
average = Order.average(:amount) max = Order.maximun(:amount) min = Order.minimun(:amount) total = Order.sum(:amount) number = Order.count
上面的這些聚合函數都是數據庫無關的。
也可以聯合其他方法一起使 用。
Order.where("amount > 20").minimun(:amount)
通常情況,這些聚合函 數返回的是一個值。如果包含group方法,返回的就是每一組的聚合結果,也就是返回一系列值。
result = Order.maximun(:amount).group(:state)
puts result #=> [["TX", 123456], ["NX", 3456]]
Scopes
范圍查詢
class Order < ActiveRecord::Base scope :last_n_days, lambda do |days| where("updated < ?", days) end end orders= Order.last_n_days(7) class Order < ActiveRecord::Base scope :checks, where(:pay_type => :check) end orders = Order.checks.last_n_days(7) in_house = Order.where('email like "%@pragprog.com"') in_house.checks.last_n_days(7)
Writing Our Own SQL
執行查詢SQL
orders = LineItem.find_by_sql("select line_items.* from line_items, orders where order_id = orders.id and orders.name = 'virus'"
orders = Order.find_by_sql("select name, pay_type from orders") first = orders[0] p first.attributes #=>{"name" => "shi", "pay_type" => "check"} p first.attribute_names #=>["name", "pay_type"] p first.attribute_present?("address") #=>false
Reloading Data
重新加載數據
我們的應用會被多個用戶訪問,有的時候,之前取出來的數據已經被其他用戶修改,這時候你又需要 最新的數據,可以調用model的reload方法來實現。
loop do puts "Price = #{stock.price}" sleep 60 stock.reload end
Updating Existing Rows
更新數據
調用model的save方法就可以實現更新,通過 id來匹配數據,如果存在數據,就是更新,如果不存在數據,就插入一條。
order = Order.find (10) order.name = "swb" order.save orders = Order.find_by_sql("select id, name, email from orders where id = 12") first = orders[0] first.name = "newname" first.save order = Order.find(12) order.update_attribute(:name, "newname") order = Order.find(12) order.update_attributes(:name => "newname", :email => "newmail") def save_after_edit order = Order.find(params[:id]) if order.update_attributes(params[:order]) redirect_to :action => :index else render :action => :edit end end order = Order.update(12, :name => "newname", :email => "newmail") result = Order.update_all("price = 1.1*price", "title like '%java%'")
save, save!, create, create!
save,保存成功返回true,否則返回nil。
save!,保存成功返回true,否則拋出 異常。
create,無論保存成功與否,都會返回model對象。你需要通過檢查validation errros來確定保存 是否成功。
create!,保存成功返回true,否則拋出異常。
if order.save # all ok else # validation fail end begin order.save! rescue RecordInvalid => error # validation fail end
Deleting Rows
刪除數據
類級別的delete方法
Order.delete(10)
User.delete([2,3,4,5])
Product.delete_all(["price > ?", @expensize_price])
delete方法通過id或者id集合刪除數據,delete_all通過條件刪除數據,返回值是受影響的行數,沒 有符合條件的數據也不會拋出異常。
對象級別的destroy方法
order = Order.find(10)
order.destroy
調用對象的destroy方法之後,就會鎖定對象,防止對他進行修改。
Order.destroy_all(["price > ?", @expensize_price])
delete方法會忽略驗 證功能,destroy方法會確保它們被執行。通常來說,如果你想要確保你的數據符合業務規則,最好使用 destroy方法。