以背景做网站视频为辽宁建设科技信息网网站
web/
2025/10/8 9:08:10/
文章来源:
以背景做网站视频为,辽宁建设科技信息网网站,聊天不付费的交友软件,电子商务网站用户行为分析及服务推荐(一、ActiveRecord基础) ActiveRecord是Rails提供的一个对象关系映射(ORM)层#xff0c;从这篇开始#xff0c;我们来了解Active Record的一些基础内容#xff0c;连接数据库#xff0c;映射表#xff0c;访问数据等。 Active Record使用基本的ORM模式#xff1a;表映… (一、ActiveRecord基础) ActiveRecord是Rails提供的一个对象关系映射(ORM)层从这篇开始我们来了解Active Record的一些基础内容连接数据库映射表访问数据等。 Active Record使用基本的ORM模式表映射成类行映射成为对象列映射成对象的属性。与很多大量使用配置的ORM库不同Active Record最小化了配置。想象一下有一个使用Active Record的程序把Mysql数据库中的orders表转换到类通过制定的ID查找到order设定order的名称然后保存回数据库 require rubygems require_gem activerecord ActiveRecord::Base.establish_connection(:adapter mysql, :host localhost, :database railsdb) class Order ActiveRecord::Base end order Order.find(123) order.name Dave Thomas order.save 在上面的例子里不需要任何配置Active Record为我们做了这些事情下面我们来看看ActiveRecord是怎样工作的。 表和类 当你创建了一个ActiveRecord::Base类的子类Active Record假定表名是复数的而类名是单数的当类名包括多个单词时表名被假定为单词间带有下划线复数形式不规则例如 类名 表名 类名 表名 Order orders LineItem line_items TaxAgency tax_agencies Person people Diagnosis diagnoses Quantity quantities Batch batches Datum data 默认的Active Record的表名是复数的类名是单数的如果你不太习惯可以通过设置一个全局标记来禁用它在config目录的environment.rb文件中设置 ActiveRecord::Base.pluralize_table_names false 单复数规则可以对付大部分情况对于一些特殊情况Active Record允许我们覆盖默认的生成的表名使用set_table_name命令例如 class Sheep ActiveRecord::Base set_table_name sheep # Not sheeps end class Order ActiveRecord::Base set_table_name ord_rev99_x # Wrap a legacy table... end 二、列和属性 ActiveRecord中的一个对象相当于数据库中表的一行对象的属性对应于表的列也许你会注意到我们的Order类没有提及关于 orders表的任何东西这是因为ActiveRecord在运行时来确定这些对应关系Active Record将数据库中的模式反应到类中。 我们的orders表可能使用下面的sql来创建 create table orders ( id int not null auto_increment, name varchar(100) not null, email varchar(255) not null, address text not null, pay_type char(10) not null, shipped_at datetime null, primary key (id) ); 我们可以创建一个类来转换这个表 require rubygems require_gem activerecord # Connection code omitted... class Order ActiveRecord::Base end 当我们创建了Order类就可以访问它的属性来获取信息下面的代码使用columns()方法来返回一个Columns对象的数组在这里我们显示了orders表中的每个列并且显示指定字段的详细信息。 require pp pp Order.columns.map { |col| col.name } pp Order.columns_hash[shipped_at] 运行代码会得到下面的输出 [id, name, email, address, pay_type, shipped_at] #ActiveRecord::ConnectionAdapters::Column:0x10e4a50 defaultnil, limitnil, nameshipped_at, type:datetime 注意Active Record决定了每个列的类型在这个例子里将shipped_at列作为datetime类型该列的值被保存在一个ruby的Time类型的对象中我们可以写些代码来验证该列的类型及其内容 order Order.new order.shipped_at 2005-03-04 12:34 pp order.shipped_at.class pp order.shipped_at 输出为 Time Fri Mar 04 12:34:00 CST 2005 下面的列表展示了sql和ruby间的数据类型对应关系 SQLType Ruby Class SQLType Ruby Class int, integer Fixnum float, double Float decimal, numeric Float char, varchar, string String clob, blob, text String datetime, time Time interval, date Date Boolean 后面详细介绍 有一个潜在的可能是关于decimal的在数据库里使用decimal的列来存储number和fix number型Active Record将decimal映射成Float类的对象尽管这样可以应用于大多数应用浮点数是不精确的在对这一类型的属性进行一系列操作的时候可 能会发生舍入的错误你也许可以使用integer类型来作为替代方案例如存储货币型的时候可以将元角分分别存入不同的字段。做为一种选择你 可以使用聚合aggregations使用多个分开的字段来构建货币类型。 (三、Boolean属性) 一些数据库支持boolean类型而另一些则不支持这使得Active Record要抽象boolean类型变得困难。例如如果数据库不支持boolean类型有的开发者使用char(1)来替代而内容使用“t”和 “f”来表示true和false而另外一些开发者使用integer类型0是false1是true。即使数据库支持boolean类型在内部 也许还是使用0和1来存储。 在Ruby里在条件判断中数字0和字符f都被认为是true值这就意味着如果你直接使用属性的值你的代码会被认为该列的值是true而不是你认为的false例如 # 不要这样使用 user Users.find_by_name(Dave) if user.superuser grant_privileges end 当在查询条件中使用属性时你必须在列名后添加一个问号 # 这样是正确的 user Users.find_by_name(Dave) if user.superuser? grant_privileges end 当使用访问操作符来获取属性的值时当值为数字0或者字符“0”“f”,“false”或“”空字符串或nil或一个常量false时都被认为是false否则就会被认为是true。 如果你在一个遗留系统上或者非英语系统上开发上面对true的定义也许会无法工作在这种情况下你可以override内建的谓词方法的定义例如荷兰语情况下字段也许包含J或者N这种情况下你可以像下面这样 class User ActiveRecord::Base def superuser? self.superuser J end # . . . end (四、存储结构化数据) 有时能够在某个属性中直接存储任意的ruby对象是很方便的一种办法就是Active Record支持序列化将一个ruby对象变为一个YMAL字符串并且将这个字符串存储到属性对应的数据库字段中。在数据库定义中这个字段必须为text类型。 因为Active Record将数据库中的Char型和text型映射为ruby的string型所以如果我们需要告诉Active Record使用序列化功能例如我们想知道某个客户进行的最后的5次消费我们创建一个含有text类型字段的表来保存信息 create table purchases ( id int not null auto_increment, name varchar(100) not null, last_five text, primary key (id) ); 在转换这个表的Active Record类中我们要使用serialize()声明来告诉Active Record要排列对象 class Purchase ActiveRecord::Base serialize :last_five # ... end 当我们创建了一个新的Purchase对象我们可以给last_five列赋任何值在这个例子里我们给last_five列设置一个字符串数组 purchase Purchase.new purchase.name Dave Thomas purchase.last_five [ shoes, shirt, socks, ski mask, shorts ] purchase.save 当我们读入它的时候这个属性已经被设置为数组 purchase Purchase.find_by_name(Dave Thomas) pp purchase.last_five pp purchase.last_five[3] 代码的输出为 [shoes, shirt, socks, ski mask, shorts] ski mask 尽管这个功能是很强大且便利的但是只有当你不打算在ruby以外的项目中使用这些序列化的信息除非那个程序也能够使用YMAL格式。特别 是这些信息很难被SQL查询所利用你也许会考虑使用聚合aggregation来替代在后面我们会介绍这种办法来达到相同的效果。 (五主键和ID) 也许你已经注意到了,在我们前面的代码中数据库定义里都使用了一个integer型的字段id作为主键这是Active Record的一个约定。 或许你要问为什么不用订单编号或者某个有意义的列来作为主键呢使用id作为主键有一个很重要的原因就是如果使用具有内在格式的主键的 话随着时间推移有可能其中的规则也会变化。例如使用ISBN号码来给book表做主键毕竟ISBN号码是唯一的但是有可能当一本书写完后美 国的出版业已经发展了并且在所有的ISBN号码后又附加了一位数字。 如果我们使用了ISBN作为book表的主键我们就要更新所有book表的记录来反映这个变化而且还有一个问题还有其他表引用了book表的主键我们就要更新所有的引用这还牵涉到要删除外键所有的这一切都是非常痛苦的。 如果使用有意义的值作为主键那么我们将收到外界业务规则的影响如果使用id我们可以自己完全控制而且如果象ISBN等一些东西改变的话将不会影响到数据库结构。 如果你从一个新的数据库结构开始可能会遵循约定给所有的表都使用id作为主键但是当你使用的是一个既存的数据库开始的时候Active Record提供了简单的方法来让你重新给表指定主键例如 class BadBook ActiveRecord::Base set_primary_key isbn end 通常Active Record会注意给新创建的记录生成主键值-使用自增长的整数。不管怎样当你override表的主键名字的时候你就需要自己负责给新建记录一个唯 一的主键值。也许有些让人惊讶你还是设置一个id的属性来完成这件事因为Active Record所关心的是主键的设置永远都使用名为id属性set_primary_key的声明只是设置了使用的列名下面的例子我们使用ISBN 作为主键。 book BadBook.new book.id 0-12345-6789 book.title My Great American Novel book.save # ... book BadBook.find(0-12345-6789) puts book.title # My Great American Novel p book.attributes # {isbn 0-12345-6789, titleMy Great American Novel} 也就是说在设置主键的时候使用id属性其他时候使用真实的列名。 (六、连接数据库) Active Record抽象了数据库连接的概念帮助应用程序来处理底层的数据库链接的细节作为替代Active Record使用通用的调用将细节委托给一组数据库适配器。 可以使用establish_connection( )方法来制定连接下面的例子创建了一个mysql数据库连接数据库的名字是railsdb,服务器的Host名为dbserver.com用户名为railsuser密码为railspw。 ActiveRecord::Base.establish_connection( :adapter mysql, :host dbserver.com, :database railsdb, :username railsuser, :password railspw ) Active Record支持DB2MySqlOraclePostgresSqlServer以及SqlLite每一种数据库适配器在链接的参数上都有一些细小的差别下表列出了常用的参数 注意Oracle适配器的名字为oci。 数据库连接和Model类是关联的每个类都从父类那里继承了链接ActiveRecord::Base作为所有的Active Record类的父类设置这里的数据库连接就给所有的活动记录类设置了链接当然如果需要的话你也可以复写override链接配置。 下面的例子里我们的大多数表都在MySql数据库中库名为online由于一些历史原因customers表在名为backend的数据库中 ActiveRecord::Base.establish_connection( :adapter mysql, :host dbserver.com, :database online, :username groucho, :password swordfish) class LineItem ActiveRecord::Base # ... end class Order ActiveRecord::Base # ... end class Product ActiveRecord::Base # ... end class Customer ActiveRecord::Base # ... end Customer.establish_connection( :adapter mysql, :host dbserver.com, :database backend, :username chicho, :password piano) 在我们前面所写的depot程序中我们没有使用establish_connection方法而是在 config/database.yaml文件中指定了数据库连接的参数信息对于大多数rails程序来说这是首选的方式不仅因为将配置信息和代码 分离而且在测试和部署时也能带来方便上面的表格里列出的参数都可以应用在YAML文件中这一点我们在前面的配置文件一节已经有介绍。 最后如果你通过一个标记访问establish_connection(),Rails会在database.yaml文件中查找名字对应的配置节来获取链接的参数这样就可以将所有的数据库连接配置从代码中分离出来。 (七、创建记录) Active Record使得实现CRUD的数据库基本操作变得简单在下面的几节里我们使用Mysql数据库中的orders表来进行CRUD的操作这次先看创建Create。 我们假想有一个Model名为Order class Order ActiveRecord::Base end 在面向对象的模型里表对应类表中的行对应类的对象。我们可以通过创建一个类的对象来创建一条记录。对orders表我们可以使用 Order.New()方法来创建一个Order的对象也就对应了orders表的一条记录然后我们给该对象的每个属性赋值最后我们调用对象的 save()方法将数据写回数据库如果不调用save()的话那么这个对象仅仅在内存中存在而不是数据库。 an_order Order.new an_order.name Dave Thomas an_order.email davepragprog.com an_order.address 123 Main St an_order.pay_type check an_order.save Active Record的构造器有一个可选的块(block),这个块可以将创建的Order对象做为参数这样就不需要再创建一个Order类的对象的变量了 Order.new do |o| o.name Dave Thomas # . . . o.save end Active Record也可以接收一组哈希(Hash)参数的值来作为可选参数由属性的名字和相对应的值组成 an_order Order.new( :name Dave Thomas, :email davepragprog.com, :address 123 Main St , :pay_type check) an_order.save 注意到现在为止我们还没有任何关于id的设置这是因为我们使用Active Record的默认约定将orders表的主键为一个integer类型的列。在存入数据库的时候Active Record自动给新建的对象生成一个唯一的值并且设置到id属性上我们可以在save()之后查询id的值 an_order Order.new an_order.name Dave Thomas # ... an_order.save puts The ID of this order is #{an_order.id} new()构造函数在内存中创建了一个Order类的对象你需要在某个时候调用save()方法来保存到数据库。Active Record还有一个约定的方法create()下面的例子说明这个方法的用法同时展示了创建对象和存储到数据库 an_order Order.create( :name Dave Thomas, :email davepragprog.com, :address 123 Main St , :pay_type check) 也可以给create()方法传递哈希(hash)的数组在数据库中创建多条记录并且返回对应的对象数组。 orders Order.create( [ { :name Dave Thomas, :email davepragprog.com, :address 123 Main St , :pay_type check }, { :name Andy Hunt, :email andypragprog.com, :address 456 Gentle Drive , :pay_type po } ] ) 方法new()和create()的真正目的就是让我们可以通过一组参数就能够创建Model对象 order Order.create(params) (八、读取记录) 读取记录包括指定那些特定的数据是你感兴趣的你给Active Record指定标准Active Record再返回给你一些对象其中包含了符合条件的记录的数据。 在一个表中检索数据的最简单的办法就是指定主键任何一个Model都支持find()方法该方法支持一个或多个主键值如果只指定了一个 主键将会返回对应的对象如果指定了多个主键给find方法该方法一组相应的对象。注意当没有任何符合条件的数据的时候将会抛出一个 RecordNotFound异常所以如果find方法没有抛出这个异常的话返回的数组中的对象个数就等于给find方法指定的id数目。 an_order Order.find(27) # find the order with id 27 # Get a list of order ids from a form, then # sum the total value order_list params[:order_ids] orders Order.find(order_list) count orders.size 通常在查询的时候都要用到除过id以外的值Active Record提供了一组设置来执行这些查询我们会介绍find使用方法从基本的查询再到高阶些的动态查询。 到现在我们只是了解了find方法的最基本的内容通过指定id来获取一个或一组对象。另外我们还可以使用一些标记比如:first:all来作为find方法的参数。 :first将返回符合条件的第一条记录:all将返回所有符合条件的记录下一篇我们来看看Active Record是如何处理sql的。 注find在3.1版中建议不使用改用where。by--biyeah (九、行数和再加载数据) Active Record提供了两个方法来获取符合条件的记录的条数count()和count_by_sql()。例如 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 has #{c3} line items in #{c2} orders (#{c1} orders in all) 在一个程序中数据库有可能被多个进程或多个程序访问随时都有可能获取最新的Model对象这些对象有可能刚刚被编辑过。 从某种程度上讲这主要应用在事务中不管怎么说当你需要手动刷新Model对象时Active Record可以帮助你只需调用reload()方法Model对象属性的值就会被数据库中的值更新。 stock Market.find_by_ticker(RUBY) loop do puts Price #{stock.price} sleep 60 stock.reload end (十、更新记录) 前面了解了检索的方法这次来看看Active Record怎样更新数据库中的记录。 如果你有一个Active Record对象或许对应于order表,你可以通过调用save方法将它写道数据库中去如果这个对象是先前从数据库中读取出来的save方法将会更新既有的记录否则将会新建一条记录。 如果一条既有记录被更新Active Record将会用它的主键和来匹配内存中的对象Active Record对象中的属性被更新到对应的列即使一个列中的值没有变化也会被更新在下面的例子中id为123的订单所有的内容都会被更新 order Order.find(123) order.name Fred order.save 不管怎样在下面的例子里Active Record对象只包含idnamepaytype当对象被保存的时候仅仅只有这些字段被更新注意如果你想要把对象保存到数据库那么在使用find_by_sql方法时一定要包含id字段。 orders Order.find_by_sql(select id, name, pay_type from orders where id123) first orders[0] first.name Wilma first.save 另外Active Record还提供了update_attribute()方法该方法可以将Model对象的某个属性保存到数据库。 order Order.find(123) order.update_attribute(:name, Barney) order Order.find(321) order.update_attributes(:name Barney, :email barneybedrock.com) 我们可以把读取和更新结合在一起使用update()方法或update_all()update()方法使用一个id和一组属性如果在数据库中对应的记录就更新指定的属性然后返回model对象。 order Order.update(12, :name Barney, :email barneybedrock.com) 也可以传递一组id或者属性和值的hash给update()方法这样会更新所有匹配的记录并且返回一组model对象。 最后update_all()方法允许你指定给update语句指定Where条件下面的例子给所有标题中含有java的商品涨价10% result Product.update_all(price 1.1*price, title like %Java%) 这里的返回值依赖于具体的数据库适配器很多数据库都返回被更新的记录数目。 下面我们看看save()和save!()这两个方法。 简单的save()方法在Model对象存在并且可以的保存的情况下返回true if order.save # all OK else # validation failed end 这样会导致你在所有调用save方法的地方都要加上检查但是Active Record假定save方法是在Controler的Action的上下文中的并且视图里的代码不进行这些检查。这部分书上看不明白不能确定。 不管怎样如果你需要在上下文环境中保存Model对象并且想确定是否所有的错误都被处理了你可以使用save!()方法如果Model对象不能保存那么这个方法会抛出一个RecordInvailid异常 begin order.save! rescue RecordInvalid error # validation failed end 转载于:https://www.cnblogs.com/deepbreath/p/4153317.html
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/88970.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!