The Rails Way 读书笔记 | Chapter 651CTO博客 - 亚美娱乐

The Rails Way 读书笔记 | Chapter 651CTO博客

2019年04月23日13时11分05秒 | 作者: 辰龙 | 标签: 办法,数据库,能够 | 浏览: 2780

Working with ActiveRecord
An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data. 包装一行数据库表或视图的记载的一个目标,封装了数据库的拜访,增加了范畴逻辑。 – Martin Fowler, P of EA
这便是ActiveRecord.  是按Martin Fowler的Active Record形式来完成的。假如你遵从它的约好,那么你会很简略的去运用它,可是你也能够不遵从它约好,增加自己的装备。
The Basics 想创立一个model类,就必须是ActiveRecord::Base的子类(除了那些不好数据库映射的类)。 class Client < ActiveRecord::Base end
依照约好,类名Client会映射为clients。Rails了解复数。Rails也希望数据库表里运用id为主键,这个id是integer类型且是自增加的。
当你在开发形式下,一切对数据库schema的改动都会反映到浏览器里。可是在操控台下,你是看不到这些改动的,除非履行: Dispatcher.reset_application!
当你想创立一个model的时分,能够运用generator来生成: ruby script/generate model client 它会帮你生成model文件,测验文件,以及migration脚本(skip-migration 参数越过这一项)。 (以上内容很简略,如同也没有做笔记的必要,可是为了统一写一点)
Migrations 这个数据库搬迁东西很便利,谁用谁知道!
Creating Migrations $ ruby script/generate migration -h  能够看用法。
Naming Migrations rails曾经的migration脚本的版别号是三位数字,但忘掉从哪个版别开端改成了年月日时分秒的组合了,包含最新的版别: mysql> select * from schema_migrations; ++ | version        | ++ | 20081214154443 |  | 20081214163921 |  | 20081214165047 |  | 20081214170446 |  | 20081214171908 |  | 20081214181045 |  | 20081214183221 |  ++
这感觉很难用了。
Migration Pitfalls 这有个问题, 我也碰到过,便是当你开发的时分,你需求创立一个migration脚本,那么你就必须先从代码库里更新最新的版别,以便你能树立正确的版别号。 可是假如两个人一起树立migration,就会出现问题,有时分人多了就会打乱migration的版别,会带来不少费事。现在这种以时刻组合生成的版别号,处理了这个问题。
Migration API create_table(name, options)  这个办法能够创立一个表,而且主动把id设为主键,Rails的默许行为。你也能够不需求主键: create_table :ingredients_recipes, :id => false do |t|   t.integer :ingredient_id   t.integer :recipe_id end 你也能够自界说主键: create_table :ingredients, :id => ingredient_id do |t|   t.integer :xxx end
:force => true参数会每次履行migration的时分删去存在的表,从头生成。在production下要当心这个选项,或许会让你丢掉数据。
:options 选项能够让你在SQL CREATE声明后边增加一些自界说的指令。这要依托详细的数据库了,比方你能够指定字符集等。
:temporary => true 能够让你用来创立暂时表,可是或许不常用。
Defining Columns add_column办法,能够帮你增加column
 Column Type Mappings 这个你需求参看the rails way P150页的表了。假如你记不住那些类型映射,能够看看详细的数据库链接适配器里界说的native_database_types办法,举例,Mysql适配器里界说的: NATIVE_DATABASE_TYPES = {         :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY".freeze,         :string      => { :name => "varchar", :limit => 255 },         :text        => { :name => "text" },         :integer     => { :name => "int", :limit => 4 },         :float       => { :name => "float" },         :decimal     => { :name => "decimal" },         :datetime    => { :name => "datetime" },         :timestamp   => { :name => "datetime" },         :time        => { :name => "time" },         :date        => { :name => "date" },         :binary      => { :name => "blob" },         :boolean     => { :name => "tinyint", :limit => 1 }       }
此适配器的方位是rails源码/activerecord/lib/activerecord/connection_adapters/下。
Column Options :default => value  ,设置默许值,假如没有这个参数是指默许设为null。 :limit => size, 指定数据库里类型的长度。 :null => false, 指定这个字段不能为空。
Decimal Precision decimal类型承受两个参数: :precision => number  有几位有用数字 :scale     => number  准确到小数点后几位 运用这个数据类型指定有用数字是个最佳实践。
Column Type Gotchas 字段类型的挑选依靠的是你挑选数据库和你运用的需求两方面,并不是那么简略: binary。  在数据库里存储二进制数据通常会导致大的功用问题。这要看你的运用场景了,国内的博客圈javaeye便是在数据库里存储了大的二进制数据,那是由于数据量太大。只是增加了数据库服务器的负载。  2.:boolean。这个不同的数据库完成的不同,有的用1,0来表明true和false,可是有的数据库用T和F。Rails关于这个处理的相当好,所以你不必忧虑这个。不管你数据库的值设置1,仍是F,都会正常作业。 :date, :datetime和:time。 Rails把数据库里的datetime字段映射为Time类,这是由于,Time是用C完成的,转化起来更快,而DateTime类是纯Ruby完成,比较慢。假如你想改动这种映射联系,那么能够把下面的代码放到你的lib目录下,而且在config/environment.rb里require它:   require ‘date’   # It’s necessary to do this, because Time doesn’t   # support dates before 1970...(这么做是为了让Time支撑1970年之前的时刻)   class ActiveRecord::ConnectionAdapters::Column     def self.string_to_time(string)       return string unless string.is_a?(String)       time_array = ParseDate.parsedate(string)[0..5]       begin         Time.send(Base.default_timezone, *time_array)       rescue         DateTime.new(*time_array) rescue nil       end   end   end
 :decimal。 运用decimal替代float是正确的做法。 5. :float。 不要用float来存储钱银等要有准确有用数字的数据。 :integer和:string。 这儿需求留意的是这两数据类型的长度。你需求验证存储的数据是否超越你约束的数据类型长度,假如没有约束,需求验证默许的长度,11位和255位。  :text。 这有是一个导致功用问题的字段。假如你非得有个字段需求用在你的运用里,那么把它放到一个独自的表里。  :timestamp。
Custom Data Types 假如你在你的项目里运用数据库指定的数据类型,比方double类型,双精度,那么你能够在config/environmet.rb里指定: config.active_record.schemat_format = :sql
“Magic” Timestamp Columns created_at或者是created_on,updated_at或者是updated_on。 这些都会主动的进行create或update操作把数据写到数据库。经过设置config/environment.rb能够封闭此功用: ActiveRecord::Base.record_timestamps = false 你也能够不这么狠, 一会儿冲击了悉数model,你能够在指定的model里来设置record_timestamps = false
Macro-Style Methods Relationship Declarations 像has_many,belongs_to这种办法就归于Macro-style methods, 一种DSL。 它们其实都是类办法。
Convention over Configuration 约好大于装备。这是Rails的精力地点。
Pluralization Rails有个类叫Inflector,是用来转化string类型的单复数。看比如: $ script/console >> Inflector.pluralize “project” => “projects” >> Inflector.pluralize “virus” => “viri” >> Inflector.pluralize “pensum” => “pensums” 这些都是默许规矩,你也能够自界说,在config/initializers/inflections.rb里装备自己的单复数转化规矩: # ActiveSupport::Inflector.inflections do |inflect| #   inflect.plural /^(ox)$/i, \1en #   inflect.singular /^(ox)en/i, \1 #   inflect.irregular person, people #   inflect.uncountable %w( fish sheep ) # end 这是ActiveSupport里完成的功用。
Setting Names Manually 你能够运用set_table_name和set_primary_key来越过Rails的约好。 例如: class Client < ActiveRecord::Base   set_table_name “CLIENT”   set_primary_key “CLIENT_ID” end 除非你有一个专门的DBA团队来处理这些表名,或者是处理留传体系的时分来这么用,其他情况下仍是遵从Rails约好来的轻松。
Legacy Naming Schemes 正如我方才想到的,作者也想到了,作者不愧是作者啊,我只能做个读者。。。
当你处理留传体系(legacy schemas)的时分,肯定会处处的写set_table_name和set_primary_key。 我曾经有个项目就这么做的,呵呵,不好意思,早看到这本书就好了。其实咱们有愈加DRY(Dont repeat yourself)的做法: ActiveRecord::Base.pluraize_table_name = false 关了Rails对表名的单复数匹配约好,还有一些其他的装备来协助你: ActiveRecord::Base.primary_key_prefix_type = :table_name 假如指定这个,那么rails就会去找tablenameid这个主键了,而不去找id。 假如是 ActiveRecord::Base.primary_key_prefix_type = :table_name_with_underscore被指定,那么便是找tablename_id table_name_prefix办法被指定的话,是设置表名的前缀是数据库的姓名。 table_name_suffix这是加后缀。 underscore_table_names设置为false是阻挠ActiveRecord把数据库名用下划线分隔。
Defining Attributes 你能够经过sql指令或是gui东西来修正数据库的字段,可是最完美的办法是运用migrations。
Default Attribute Values migrations脚本答应你设置数据库字段的默许值,经过:default选项。可是大多数的时分,咱们应该在model层来设置默许值,而不是数据库层。由于默许值也是事务逻辑代码,应该放在model层面。
有个比如是当一个特点并没有被赋值的时分,回来’n/a’而不是nil。 Rails并没有给咱们供给一个类等级的办法来在model设置默许值,那么咱们就用getter/setter类办法来完成,作者这儿介绍了TDD的开发办法,有爱好的同志们能够去看原版。
class Specification < ActiveRecord::Base   def tolerance     read_attribute(:tolerance) or ‘n/a’   end end
class SillyFortuneCookie < ActiveRecord::Base   def message=(txt)     write_attribute(:message, txt + ‘ in bed’)   end end
改善: class Specification < ActiveRecord::Base   def tolerance     self[:tolerance] or ‘n/a’   end end class SillyFortuneCookie < ActiveRecord::Base   def message=(txt)     self[:message] = txt + ‘ in bed’   end end

Serialized Attributes ActiveRecord最酷的特性之一便是有才能符号一个text类型的字段存储被序列化的数据,我忍不住又想到javaeye。
Text类型存储的极限是64k,假如你序列化的特点文件超越这个规范会犯错。另一方面,假如你的特点非常大,或许你应该从头考虑该做什么-至少把它们移到独自的表里,而且运用一个你的服务器答应的大的字段类型。
CRUD: Creating, Reading, Updating, Deleting 四个规范的数据库操作。
Creating New ActiveRecord Instances 最直接的办法是用model的new办法: >> c = Client.new => #<Client:0x2515584 @new_record=true, @attributes={“name”=>nil, “code”=>nil}> >> c.new_record? => true
也能够用一个块: >> c = Client.new do |client| > client.name = “Nile River Co.” >> client.code = “NRC” >> end => #<Client:0x24e8764 @new_record=true, @attributes={“name”=>”Nile River Co.”, “code”=>”NRC”}>
运用hash参数: >> c = Client.create(:name => “Nile River, Co.”, :code => “NRC”) => #<Client:0x4229490 @new_record_before_save=true, @new_record=false, @errors=#<ActiveRecord::Errors:0x42287ac @errors={}, @base=#<Client:0x4229490 ...>>, @attributes={“name”=>”Nile River, Co.”, “updated_at”=>Mon Jun 04 22:24:27 UTC 2007, “code”=>”NRC”, “id”=>1, “created_at”=>Mon Jun 04 22:24:27 UTC 2007}> 留意,这条记载现已保存了。
Reading ActiveRecord Objects find >> first_project = Project.find(1) >> boom_client = Client.find(99) ActiveRecord::RecordNotFound: Couldn’t find Client with ID=99 from /vendor/rails/activerecord/lib/active_record/base.rb:1028:in `find_one’ 留意:edge rails这儿现已不会抛出反常了,当没有找到对应记载的时分,会回来nil,可是运用find!或者是find_by_xxx!会抛出反常。
你能够运用:order选项来排序找出最终一项: >> all_clients = Client.find(:first, :order => ‘id desc’) => #<Client:0x2508244 @attributes={“name”=>”Paper Jam Printers”, “code”=>”PJP”, “id”=>”1”}>
可是rails2.2+不需求这么做了,有了:last办法。 你也能够加多个参数: >> p = Product.find(1,2,3,4,5) => [#<Product:0x22d7b00 @attributes={ 。。。 >> p.size => 5
可是你用find_by_xxx(1,2)后边的2会被当作order参数。
Reading and Writing Attributes The attributes Method ActiveRecord目标有一个attributes办法,回来的是一个hash。

Accessing and Manipulating Attributes Before They Are Typecast <attribute>_before_type_cast办法,  能够得到原始的数据目标,未转化的。class Timesheet < ActiveRecord::Base   before_save :fix_rate   def fix_rate     rate_before_type_cast.tr!(‘$,’,’’)   end end
Dynamic Attribute-Based Finders find_by_xxx魔法,是运用method_missing办法,经过正则匹配来完成的。 find_by_xxx_and_xxx find_all_by_xxx(xxx,:order => xx_id)
find_by_sql(“select * from xxxs”) 比如: >> Client.find_by_sql(“select * from clients where code like ‘A%’”) => [#<Client:0x4206b34 @attributes={“name”=>”Amazon, Inc.”, ...}>]
>> param = “A” >> Client.find(:all, :conditions => [“code like ?”, “#{param}%”]) => [#<Client:0x41e3594 @attributes={“name”=>”Amazon, Inc...}>] 
ActiveRecord是用connection.select_all办法来履行你的sql的。
还有便是要留意你的find查询要用占位符(?),防止sql注入问题。
The Query Cache Rails默许敞开一些简略的查询缓存来优化功用。 当find发作的时分,查询缓存都会被激活。一个hash成果被存储在当前线程里。当由相同的sql句子履行时,就回来缓存的成果。比如: User.cache do   puts User.find(:first)   puts User.find(:first)   puts User.find(:first) end 看日志: Person Load (0.000821) SELECT * FROM people LIMIT 1 CACHE (0.000000) SELECT * FROM people LIMIT 1 CACHE (0.000000) SELECT * FROM people LIMIT 1 select句子只是被履行了一次。 save和delete操作会铲除缓存,这是为了防止导致过错的成果。调用clear_query_cache这个类办法就会清空悉数查询缓存。
Default Query Caching in Controllers 功用原因,ActiveRecord的查询缓存被默许翻开的以处理controller actions。SqlCache模块被界说在ActionController的caching.rb里,是被mixin 到ActionController::Base里,而且被perform_action办法用alias_method_chain包装。 module SqlCache   def self.included(base) #:nodoc:     base.alias_method_chain :perform_action, :caching   end   def perform_action_with_caching     ActiveRecord::Base.cache do       perform_action_without_caching     end   end end
Limitations “select foo from bar where id = 1 select foo from bar where id = 1 limit 1 是两个不同的查询,会被缓存为两个不同的实体。

Updating 看比如: class ProjectController < ApplicationController   def update     Project.update(params[:id], params[:project])     redirect_to :action=>’settings’, :id => project.id   end   def mass_update     Project.update(params[:projects].keys,params[:projects].values])     redirect_to :action=>’index’   end end
下面比如是mode的验证被履行两次,由于update在调用的时分也会履行验证办法。 class ProjectController < ApplicationController   def update     @project = Project.update(params[:id], params[:project])     if @project.valid? # uh-oh, 你想再次运转validate?       redirect_to :action=>’settings’, :id => project.id     else       render :action => ‘edit’     end   end end
最好的处理办法是用update_attributes(object) class ProjectController < ApplicationController   def update     @project = Project.find(params[:id]     if @project.update_attributes(params[:project])       redirect_to :action=>’settings’, :id => project.id     else       render :action => ‘edit’     end   end end update_attributes办法回来true或false,判别的根据是数据是否保存成功。
Updating by Condition update_all能够一次更新多个记载。比如: Project.update_all(“manager = ‘Ron Campbell’”, “technology = ‘Rails’”) 这个比如是更新当technology为rails的时分一切记载的manager为Ron Campbell。
Updating a Particular Instance save办法在保存成功今后回来true,失利今后回来false。 save!在失利今后则抛出反常。
Updating Specific Attributes update_attribute()能够更新一个指定的特点,可是不会去调用验证。
Convenience Updaters Rails provides a number of convenience update methods in the form of increment, decrement, and toggle, which do exactly what their names suggest with numeric and boolean attributes. Each has a bang variant (such as toggle!) that additionally invokes save after modifying the attribute.
Controlling Access to Attributes class Customer < ActiveRecord::Base   attr_protected :credit_rating end customer = Customer.new(:name => “Abe”, :credit_rating => “Excellent”) customer.credit_rating # => nil customer.attributes = { “credit_rating” => “Excellent” } customer.credit_rating # => nil # and now, the allowed way to set a credit_rating customer.credit_rating = “Average” customer.credit_rating # => “Average” 作者没有介绍attr_accessible :name这个办法, 这个办法是白名单办法来维护你的model特点,比attr_protected更安全。

Deleting and Destroying delete和destroy有所不同。 delete办法,是直接用sql来从数据库删去记载,并不会加载任何ruby类。所以比较快 destroy会先加载这个model的目标,然后调用这个目标的destroy办法。
版权声明
本文来源于网络,版权归原作者所有,其内容与观点不代表亚美娱乐立场。转载文章仅为传播更有价值的信息,如采编人员采编有误或者版权原因,请与我们联系,我们核实后立即修改或删除。

猜您喜欢的文章