`

Rails 数据库操作

    博客分类:
  • ruby
阅读更多

[转载]Rails 数据库操作

原文地址:Rails 数据库操作作者:浮云

http://blog.sina.com.cn/s/blog_5575d1da0100xulv.html

数据库元被影射成对象

(object-relational mapping (ORM)层)

Ruby代码

table<=>class  

row<=>object   

column<=>object attribute  

 

 

class和table的命名对应关系实例:

Ruby代码

Order<=>orders   

TaxAgency<=>tax_agencies   

Person<=>people  

 

Ruby代码

#复数形式关闭方法config/environment.rb:   

ActiveRecord::Base.pluralize_table_names = false  

#自定义表格名称方法:   

class Sheep < ActiveRecord::Base   

set_table_name "sheep"  

end  

 

 

Ruyb数据类型和SQL数据类型对应关系表:

Ruby代码

int,integer<=>Fixnum  

float,double,decimal,numeric<=>Float   

interval,date<=>Date   

datetime,time<=>Time  

char,varchar,string,clob,blob,text<=>String  

boolean<=>see text...  

 

 

访问属性(数据库列):

Ruby代码

account[:balance] #=> 返回当前值   

account[:balance] = 0.0 #=> 指定数值  

 

 

Ruby代码

#修正数据库列的取值范围的方法:   

class Account < ActiveRecord::Base   

def balance=(value)   

   raise BalanceTooLow if value < MINIMUM_LEVEL   

   self[:balance] = value   

end  

end  

 

 

访问属性(数据库列)更方便的方法:

account.balance #=> 返回当前值

account.balance = 0.0 #=> 指定数值

 

以上方式得到的数据库数据将是ruby按自身的数据类型格式化好的,如果要得到原始数据,可用以下形式代码:

account.balance_before_type_cast #=> "123.4", 字符串

account.release_date_before_type_cast #=> "20050301"

 

是非属性

在ruby中只有false或nil才被判断为false

通常用以下代码判断:

Ruby代码

user = Users.find_by_name("Dave")   

if user.superuser?   

grant_privileges   

end  

 

superuser?将以下结果判断为false:

1.数字0

2.字符"0", "f", "false", 或""(空字符)

3.nil

4.常量false

 

自定义判断原则的方法:

Ruby代码

class User < ActiveRecord::Base   

def superuser?   

   self.superuser == 'J'  

end  

# . . .   

end  

 

 

数据库主键(Primary Keys)

Ruby on Rails默认以id为主键

 

自定义主键的方法:

class BadBook < ActiveRecord::Base

set_primary_key "isbn"

end

 

数据创建,读取,更新和删除(CRUD:Create, Read, Update, Delete)

 

创建新数据

 

实例:

Ruby代码

an_order = Order.new  

an_order.name ="Dave Thomas"  

an_order.email = "dave@pragprog.com"  

an_order.address = "123 Main St"  

an_order.pay_type = "check"  

an_order.save #在save()之前所有数据只存在内存中  

 

 

用以下方式可以减少产生一个an_order变量:

Ruby代码

Order.new do |o|   

o.name = "Dave Thomas"  

# . . .   

o.save   

end  

 

 

当数据来自HTML表单时,可以考虑用以下方式:

Ruby代码

an_order = Order.new(   

:name =>"Dave Thomas",   

:email =>"dave@pragprog.com",   

:address => "123 Main St",   

:pay_type =>"check")   

an_order.save  

 

 

使用create()代换new()可直接保存到数据库,省去an_order.save:

Ruby代码

an_order = Order.create(   

:name => "Dave Thomas",   

:email =>"dave@pragprog.com",   

:address =>"123 Main St",   

:pay_type => "check")  

 

 

可以使用hash同时保存多组数据:

Ruby代码

orders = Order.create(   

   [ { :name =>"Dave Thomas",   

     :email => "dave@pragprog.com",   

     :address =>"123 Main St",   

     :pay_type =>"check"  

    },   

    { :name =>"Andy Hunt",   

     :email =>"andy@pragprog.com",   

     :address =>"456 Gentle Drive",   

     :pay_type => "po"  

    } ] )  

 

 

new()或create()也可以直接接参数:

order = Order.create(params)

 

读取数据

Ruby代码

an_order = Order.find(27) # 直接找出id = 27的数据   

# 从一个表单读取product id列表,然后计算这些商品的总价:   

product_list = params[:product_ids]   

total = 0.0   

Product.find(product_list).each {|prd| total += prd.total}  

 

 

Ruby代码

带条件的读取:   

pos = Order.find(:all,   

:conditions => "name = 'dave' and pay_type = 'po'")  

 

 

不安全的表单参数传递读取数据库:

Ruby代码

name = params[:name]   

# 此方法有被SQL注入方式入侵的风险!!!   

pos = Order.find(:all,   

:conditions =>"name = '#{name}' and pay_type = 'po'")   

#注意上面单双引号的使用及变量的传递方法  

 

更安全的方法:

Ruby代码

name = params[:name]   

pos = Order.find(:all,   

:conditions => ["name = ? and pay_type = 'po'", name])  

 

 

你也可以这样:

Ruby代码

name = params[:name]   

pay_type = params[:pay_type]   

pos = Order.find(:all,   

:conditions => ["name = :name and pay_type = :pay_type",   

{:pay_type => pay_type, :name => name}])  

 

 

终极简化版:

Ruby代码

pos = Order.find(:all,   

:conditions => ["name = :name and pay_type = :pay_type", params])  

 

 

排序和查找第3(?)至13(?)列的方法:

Ruby代码

orders = Order.find(:all,   

:conditions =>"name = 'Dave'",   

:order =>"pay_type, shipped_at DESC",   

:limit => 10   

:offset => 2)  

 

 

联合数据表的查找方法(一般用不上):

Ruby代码

LineItem.find(:all,   

:conditions => "pr.title = 'Programming Ruby'",   

:joins =>"as li inner join products as pr on li.product_id = pr.id")  

 

查找有序一列的方法:

Ruby代码

order = Order.find( :first,   

:conditions =>"name = 'Dave Thomas'",   

:order => "id DESC")  

 

 

直接使用sql语句的查询方法:

Ruby代码

items = LineItem.find_by_sql("select *, quantity*unit_price as total_price,products.title as title from line_items, products where line_items.product_id = products.id ")   

li = items[0]   

puts "#{li.title}: #{li.quantity}x#{li.unit_price} => #{li.total_price}"  

#你可以使用"as".  

 

 

在这里你也可以传递参数:

Ruby代码

Order.find_by_sql(["select * from orders where amount > ?",   

params[:amount]])  

 

 

计算行数

Ruby代码

c1 = Order.count   

c2 = Order.count(["name = ?", "Dave Thomas"])   

c3 = LineItem.count_by_sql("select count(*) from line_items, orders   where line_items.order_id = orders.id and orders.name = 'Dave Thomas' ")   

puts "Dave在#{c2}个定单里一共定了#{c3} 件商品 (目前定单总数:#{c1})"  

 

 

动态查询

Ruby代码

order = Order.find_by_name("Dave Thomas")#只查一列   

orders = Order.find_all_by_name("Dave Thomas")   

order = Order.find_all_by_email(params['email'])  

 

 

可同时查多个条件,如:

Ruby代码

user = User.find_by_name_and_password(name, pw)  

 

 

重载数据库

Ruby代码

stock = Market.find_by_ticker("RUBY")   

loop do  

puts "Price = #{stock.price}"  

sleep 60   

stock.reload   

end  

 

 

更新数据

使用save()

Ruby代码

order = Order.find(123)   

order.name = "Fred"  

order.save   

  

orders = Order.find_by_sql("select id, name, pay_type from orders where id=123")   

first = orders[0]   

first.name ="Wilma"  

first.save  

 

使用update_attribute()

Ruby代码

order = Order.find(123)   

order.update_attribute(:name,"Barney")   

order = Order.find(321)   

order.update_attributes(:name => "Barney",   

:email =>"barney@bedrock.com")  

 

 

使用更快捷的update()

Ruby代码

order = Order.update(12, :name => "Barney", :email => "barney@bedrock.com")  

 

 

使用update_all()

Ruby代码

result = Product.update_all("price = 1.1*price", "title like '%ruby%'")  

 

 

Ruby代码

save()和save!()   

save()   

if order.save   

# 成功   

else  

# 保存失败则...   

end  

 

 

Ruby代码

save!()   

begin  

order.save!   

rescue RecordInvalid => error   

# 保存失败RecordInvalid exception   

end  

 

 

数据锁(防止数据保存撞车)

加段:lock_version int default 0,

 

 

删除数据

Ruby代码

delete()删除   

Order.delete(123)   

User.delete([2,3,4,5])   

Product.delete_all(["price > ?", @expensive_price])  

 

 

destroy()冻结(在model层面)

Ruby代码

order = Order.find_by_name("Dave")   

order.destroy   

# ... order将被冻结  

 

 

 

 

 

 

 

 

 

 

Ruby on Rails,使用where方法对持久化对象进行条件查询

http://www.cnblogs.com/abbuggy/archive/2012/10/21/2732868.html

在《Ruby on Rails,使用find方法加载持久化对象》一文中,我们使用find系列方法进行对象查询。在新版本的Rails中,都推荐使用where而不是find方法进行条件查询了。

语法上和find条件查询差不多,应该说更简洁一点,比如我想找到position是2的对象。

1
2
3
4
irb(main):090:0> Subject.where("position=?","2").order("name")
=> [#<Subject id: 4, created_at: "2012-10-20 15:14:07", updated_at: "2012-10-20 15:17:46", name: "Fourth Subject", posit
ion: "2">, #<Subject id: 2, created_at: "2012-10-20 06:25:27", updated_at: "2012-10-20 15:10:36", name: "Second Subject"
, position: "2">]

与find方法不同的是,where方法返回的结果不是数组而是ActiveRelation,这意味着我们可以基于当前的查询结果继续设置条件进行查询。

1
2
irb(main):168:0* Subject.where(:position =>"2").class
=> ActiveRecord::Relation

并且,通过to_sql方法我们能看到Rails将我们的条件转换成的SQL语句以便于调试。

1
2
irb(main):169:0> Subject.where(:position =>"2").to_sql
=> "SELECT `subjects`.* FROM `subjects`  WHERE `subjects`.`position` = '2'"

比如第一步先检索出position是2的所有对象,然后再根据name降序排列等等。

1
2
3
4
irb(main):096:0> Subject.where("position=?","2").order("name desc")
=> [#<Subject id: 2, created_at: "2012-10-20 06:25:27", updated_at: "2012-10-20 15:10:36", name: "Second Subject", posit
ion: "2">, #<Subject id: 4, created_at: "2012-10-20 15:14:07", updated_at: "2012-10-20 15:17:46", name: "Fourth Subject"
, position: "2">]

与find的另一点不同是,where是懒加载的。也就可以理解为通过where方法返回对象只是一个壳子,里面什么都没有,直到我们需要从这个对象中取得属性值这一刻才会真的查询数据库。如果想要关闭懒加载特性,在where调用之后增加.all即可。

下面说说where方法中的条件参数格式。

第一种是String,相当于直接传入SQL语句,为了防止SQL注入的风险,最好只用于硬编码或变量全部由我们自己控制的SQL语句,千万不要将用户输入的变量值直接放在语句里。

1
2
3
irb(main):160:0> Subject.where("position = '2' AND name='Second Subject'")
=> [#<Subject id: 2, created_at: "2012-10-20 06:25:27", updated_at: "2012-10-20 15:10:36", name: "Second Subject", posit
ion: "2">]

第二种是Array,第一个参数和需要写的SQL语句格式完全一样,字段值的地方用?问号代替。后面的参数按照顺序提供条件值。

1
2
3
irb(main):161:0> Subject.where("position = ? AND name=?" ,"2","Second Subject")
=> [#<Subject id: 2, created_at: "2012-10-20 06:25:27", updated_at: "2012-10-20 15:10:36", name: "Second Subject", posit
ion: "2">]

第三种是Hash,每个参数都是一套值对。这种方式非常简单直观,不过有点局限就是表现力有点差,只能表示AND,无法表示OR。

1
2
3
irb(main):165:0> Subject.where(:position =>"2" ,:name=>"Second Subject")
=> [#<Subject id: 2, created_at: "2012-10-20 06:25:27", updated_at: "2012-10-20 15:10:36", name: "Second Subject", posit
ion: "2">]

所以选择用哪种条件表达式方式就得根据实际情况而定了,一般来说简单的查询使用Hash方式,当复杂性无法满足的时候使用Array型。至于String方式直接写SQL语句的最好还是别用了。

查询返回的结果可以当做一个Array使用,如果什么都没查到,返回的长度为0。

1
2
irb(main):172:0> Subject.where(:position =>"3")
=> []

 

 

 

 

 

 

 

 

 

 

http://blog.csdn.net/remote_roamer/article/details/23918303

rails 中 不利用 model 来进行动态 sql 运行的几种方法。

 

一.  依然利用任意一个model 的 find_by_sql() 来执行。

@result = Testmodels.findby('select  ....') .

结果可以进行 json 化. @result.to_josn

 

二. 利用ActiveRecord::Base.connection.execute 来执行,获取sql语句返回的metadata

@result = ActiveRecord::Base.connection.execute ‘select...."

 

三. 利用

 ActiveRecord::Base.connection.select_all ’sql_string。。。。‘ 的方法来获得metadata和结果集数组的 对象

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics