Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 475 lines (381 sloc) 27.3 KB
rails开发简易流程
1、创建rails项目:rails <项目名称>
2、生成控制器:ruby script/generate controller <控制器名称> <控制器方法(可选)>
#控制器里的方法和view里面的视图是关联的
#则:在控制器里选定方法(say_hello)后view会相应相关联的视图(say_hello.rhtml)
3、生成模型
rials命名约定:
1、若一个控制器的类名为MyRialsObject,则对应的文件名为my_rails_boject.rb
2、模型类都继承于ActiveRecord::Base
3、控制器都继承于ApplicationController
rails学习心得:
1、number_to_currency(number, options={})
将数 字 格 式 化 为 金 额 字 符 串 。 此 方 法 的 第 二 个 参 数 是 一 个 hash ,用 于 定 制 输 出 格 式 。用:precision 选项可以指定数字的精度,默认精度为 2;用:unit 选项可以指定货币类型,默 认 值 为 “ $ ”; :separator 选 项 用 于 指 定 整 数 与 小 数 之 间 的 分 隔 符 , 默 认 值 为
“.”;:delimiter 选项用于指定整数部分的定界符,默认值为“,”。
number_to_currency(1234567890.50) ->$1.234,567,890.50
number_to_currency(1234567890.506) ->$1.234,567,890.51
number_to_currency(1234567890.50, :unit => "&pound;",
:separator => "," , :delimiter => "" )
-> &pound; 123456789,50
2、我们所采用的渐进式的 Ajax 开发方式:首先从一个传统的应用程序开始,逐渐向其中增加
Ajax 的特性。Ajax 可能很难调试;如果逐渐添加 Ajax 特性,当遇到困难时,你也可以比较容易地找
出问题所在。另外,正如我们看到的,从一个传统的应用程序开始也使你能够更容易地同时支持 Ajax 和
非 Ajax 的行为方式
3、(即使在开发环境)在修改routes.rb后需要重启服务器,因为由于性能原因routes做过缓存
4、测试夹具在每个数据行的开头处必须使用空格来缩进,而不能使用 tab 键;并且同一条记录中所有的数据行必须使用同样的缩进量。最后,你还需要确保每个条目中每个字段的名称正确: 如果 YAML 中指定的属性名与数据库字段名不匹配,可能导致一些很难跟踪的异常
5、generate 命令在创建它们的同时会为它们创建单元测试。自己动手创建的类没有与之对应的单元测试了
6、setup()的方法,这个方法就会在每个测试方法运行之前首先运行,可以用于初始化值,避免重复
7、 assert_not_nil assigns["items" ]
assigns 这个 hash 只能用字符串来查询。譬如说,assigns[:items]就不行,因为这里使用的
键是一个符号,而不是字符串。如果你想要使用符号,则可以调用assigns 方法,而不是直接查询这个 hash
8、任何不直接属于模型、视图或者控制器的代码都应该放在 lib 目录下。将文件放到 lib 目录下之后,你就可以在应用程序的任何地方使用它们。如果文件中包含了类或者模块的定义,并且文件名是类名或者模块名的小写格式,那么 Rails 就会自动装载这个文件。譬如说生成 PDF 收 据 的 代 码 位 于 lib/pdf_stuff/receipt.rb 文 件 , 那 么 只 要 这 个 类 名 叫PdfStuff::Receipt,Rails 就能够找到并自动装载它。
9、如果想要把应用程序与目前以 Gem 形式安装的 Rails 版本绑定,只要输入下列命令即可:
depot>rake rails:freeze:gems
这个命令会在幕后将最新版本的 Rails 库拷贝到 vendor/rails 目录下——当应用程序启动时,
Rails 会首先到这里来寻找自己需要的库,然后再寻找全系统共享的版本。所以,经过固化之后,应用
程序就与一个特定的 Rails 版本绑定在一起了。需要注意:固化操作只是把 Rails 框架放进你的应用程序,其他 Ruby 库仍然要到全局共享区去获取。如果在固化之后希望取消绑定、继续使用系统共享的 Rails 版本,可以直接把 vendor/rails 目录删掉,也可以执行下列命令:
depot>rake rails:unfreeze
这条命令会把某个版本(当前或者某个特定)的 Rails 冻结起来,放进 vendor 目录中。这样会减少由于动态升级造成的风险,如果你需要最新的特性,则需要使用 unfreeze 和 refreeze 命令来启用它们。
运行时环境切换
depot> ruby script/server -e development
depot> ruby script/server -e test
depot> ruby script/server -e production
10、仅仅能够正确处理字符串编码还不足以保证整个应用程序都能正确操作 Unicode 字符。你需要
确保数据走过的整条路径——从浏览器直到数据库——都使用同样的编码方式。
11、在rails中涉及到非英文等其他字符时,使用rails自带的.chars.length方法来实现计算字符个数和.chars.reversed方法实现字符串反转,否则用ruby自带的.length,.reversed等会出错。
12、depot> rake db:migrate:redo STEP=3
缺省情况下, redo 会回退一个迁移任务并重新实施它。如果想要重做多个需要加上“STEP=”参数 。
13、写成下面这样,那么即便应用程序中已经没有 OrderHistory 类,这个迁移任务同样可以运行。
class CreateOrderHistories < ActiveRecord::Migration
class Order < ActiveRecord::Base; end
class OrderHistory < ActiveRecord::Base; end
...
14、ActiveRecord 是 Rails 采用的对象一关系映射(ORM)层。
ActiveRecord 采用了标准的 ORM 模型:表映射到类、记录映射到对象、字段映射到对象的属性。
15、Ruby 对“真值”的定义非常简单:除了 nil 和 false 之外的所有值都会被解释为 true
16、Order.find(:first)不一定返回应用程序创建的第一条订单数据。
find(:first,...)方法根据指定的条件能够找到多条记录,那么将返回其中的第一条记录;
如果没有符合条件的记录,就会返回 nil
17、 带 感 叹 号 (!) 的 find_by_ 调 用 在 没 有 找 到 对 应 记 录 的 时 候 不 会 返 回 nil 而 是 会 抛 出
ActiveRecord:: RecordNotFound 异常
order = Order.find_by_name!("Dave Thomas" )
18、新建的模型对象必定符合查询条件的要求,如果你使用的是 find_or_create_by_开头的查询方
法,则这个模型对象会被自动保存到数据库中。
cart = Cart.find_or_initialize_by_user_id(user.id)
cart.items << new_item
cart.save
另外,多字段组合查询只有_and 这样一种形式。不能在字段名之间用_or_分隔
19、ActiveRecord 根据 id 字段来跟踪数据的归属。如果在用 find_by_sql()方法获取数据时没有
取出 id 字段,那么得到的模型对象就无法再次存回数据库。糟糕的是,ActiveRecord 会尝试保存它
们,然后悄无声息地失败。譬如说,下列代码不会更新数据库:
result = LineItem.find_by_sql("select quantity from line_items" )
result.each do |li|
li.quantity += 2
li.save
end
20、为了支持模块化,同时又不会在性能上损失太多,Rails 会将查询结果缓存起来。这些都是自动进行的,通常对用户是透明的,所以你并不需要为此做些什么。
21、默认情况下,ActiveRecord 认为连接表的名字应该是将两张目标表的名字按照字母顺序连接起
来得到的结果。譬如前面的例子, 我们将 categories 表和 products 表连接起来,所以ActiveRecord
会尝试找到一张名为 categories_products 的连接表。
22、class Point #Create or open the class Point
class Point3D < Point #Create a subclass of Point
class << Point #Open the eigenclass of the object Point
---------------------------------------------------------------------------------------------------------------------------------------------------------
Rails Guides learn:
model:
1.you can describe new model copy in the Migration to out of the model's validates.
example:
class AddaddNumToProducts < ActiveRecord::Migration
class Product < ActiveRecord::Base
end
def self.up
add_column :products, :add_num, :integer
Product.reset_column_information
Product.create!(:add_num => 99)
end
def self.down
remove_column :products, :add_num
end
end
method:reset_column_information is used to Reset all the cached information about columns, which will cause them to be reloaded on the next request.
---------------------------------------------------------------------------------------------------------------------------------------------------------
when deploy a new instance of an app,load the schema is simple and fast.if no nessery don't use the entire migration history.
---------------------------------------------------------------------------------------------------------------------------------------------------------
The possible length constraint options are:
:minimum The attribute cannot have less than the specified length.
:maximum The attribute cannot have more than the specified length.
:in (or :within) The attribute length must be included in a given interval. The value for this option must be a range.
:is The attribute length must be equal to the given value.The possible length constraint options are:
---------------------------------------------------------------------------------------------------------------------------------------------------------
The following methods trigger validations, and will save the object to the database only if the object is valid:
create
create!
save
save!
update
update_attributes
update_attributes!
The bang versions (e.g. save!) raise an exception if the record is invalid. The non-bang versions don’t: save and update_attributes return false, create and update just return the objects.
---------------------------------------------------------------------------------------------------------------------------------------------------------
The following methods skip validations, and will save the object to the database regardless of its validity. They should be used with caution.
decrement!
decrement_counter
increment!
increment_counter
toggle!
update_all
update_attribute
update_counters
Note that save also has the ability to skip validations if passed :validate => false as argument. This technique should be used with caution.
save(:validate => false)
invalid? is simply the inverse of valid?. invalid? triggers your validations and returns true if any errors were added to the object, and false otherwise.
---------------------------------------------------------------------------------------------------------------------------------------------------------
Callbacks:
before_validation
after_validation
before_save
after_save
before_create
around_create
after_create
before_update
around_update
after_update
before_destroy
after_destroy
around_destroy
---------------------------------------------------------------------------------------------------------------------------------------------------------
The after_initialize callback will be called whenever an Active Record object is instantiated, either by directly using new or when a record is loaded from the database.
The after_find callback will be called whenever Active Record loads a record from the database. after_find is called before after_initialize if both are defined.
---------------------------------------------------------------------------------------------------------------------------------------------------------
callback methods use the third class:
1.the method in the third class must have a argument and method's name must same to callback
2.if the third class's method is not a classmethod please use: callbalck ThirdClass.new
else callback
---------------------------------------------------------------------------------------------------------------------------------------------------------
Observers:
1.create: rails generate observer XXX
2.registering observers: config.active_record.observers = :XXX #Activate observers that should always be running.
As usual, settings in config/environments take precedence over those in config/application.rb. So, if you prefer that an observer doesn’t run in all environments, you can simply register it in a specific environment instead.
useage:
class MailerObserver < ActiveRecord::Observer
observe :registration, :user
def after_create(model)
# code to send confirmation email...
end
end
#whenever a Registation or User was created, the MialerOberver will send a email
---------------------------------------------------------------------------------------------------------------------------------------------------------
Model.first or last won't raise exceptions,intead they return nil, if there were no results.
# Very inefficient when users table has thousands of rows.
User.all.each do |user|
NewsLetter.weekly_deliver(user)
end
#better chosen,when users table has much more rows.
User.find_each(:batch_size => 5000) do |user| #you can also figure from which to start by use: :start => Num
NewsLetter.weekly_deliver(user)
end
---------------------------------------------------------------------------------------------------------------------------------------------------------
Optimistic locking
If an update request is made with a lower value in the lock_version field than is currently in the lock_version column in the database, the update request will fail with an ActiveRecord::StaleObjectError.
c1 = Client.find(1)
c2 = Client.find(1)
c1.first_name = "Michael"
c1.save
c2.name = "should fail"
c2.save # Raises a ActiveRecord::StaleObjectError
---------------------------------------------------------------------------------------------------------------------------------------------------------
Eager loading is the mechanism for loading the associated records of the objects returned by Model.find using as few queries as possible.
clients = Client.all(:limit => 10)
clients.each do |client|
puts client.address.postcode
end
This code looks fine at the first sight. But the problem lies within the total number of queries executed. The above code executes 1 ( to find 10 clients ) + 10 ( one per each client to load the address ) = 11 queries in total.
Solution to N + 1 queries problem:
Active Record lets you specify in advance all the associations that are going to be loaded. This is possible by specifying the includes method of the Model.find call. With includes, Active Record ensures that all of the specified associations are loaded using the minimum possible number of queries.
Revisiting the above case, we could rewrite Client.all to use eager load addresses:
clients = Client.includes(:address).limit(10)
clients.each do |client|
puts client.address.postcode
end
The above code will execute just 2 queries, as opposed to 11 queries in the previous case:
SELECT * FROM clients LIMIT 10
SELECT addresses.* FROM addresses
WHERE (addresses.client_id IN (1,2,3,4,5,6,7,8,9,10))
---------------------------------------------------------------------------------------------------------------------------------------------------------
when to use the singular Resources:
you have a resource that clients always look up without referencing an ID. For example, you would like /profile to always show the profile of the currently logged in user. In this case, you can use a singular resource to map /profile (rather than /profile/:id) to the show action.
example: match "profile" => "users#show"
---------------------------------------------------------------------------------------------------------------------------------------------------------
This resourceful route
resource :geocoder
creates six different routes in your application, all mapping to the Geocoders controller:
Verb Path action used for
GET /geocoder/new new return an HTML form for creating the geocoder
POST /geocoder create create the new geocoder
GET /geocoder show display the one and only geocoder resource
GET /geocoder/edit edit return an HTML form for editing the geocoder
PUT /geocoder update update the one and only geocoder resource
DELETE /geocoder destroy delete the geocoder resource
Controller Namespaces and Routing:
You may wish to organize groups of controllers under a namespace. Most commonly, you might group a number of administrative controllers under an Admin:: namespace. You would place these controllers under the app/controllers/admin directory, and you can group them together in your router:
namespace "admin" do
resources :posts, :comments
end
this also creates six different routes in your application(like above),and this will add the /admin in front of the path.
If you want to route /posts (without the prefix /admin) to Admin::PostsController, you could use
scope :module => "admin" do
resources :posts, :comments
end
or, for a single case
resources :posts, :module => "admin"
If you want to route /admin/posts to PostsController (without the Admin:: module prefix), you could use
scope "/admin" do
resources :posts, :comments
end
or, for a single case
resources :posts, :path => "/admin/posts"
---------------------------------------------------------------------------------------------------------------------------------------------------------
Nested routes allow you to capture this relationship in your routing. In this case, you could include this route declaration:
resources :magazines do
resources :ads
end
---------------------------------------------------------------------------------------------------------------------------------------------------------
The Query String
The params will also include any parameters from the query string. For example, with this route:
match ':controller/:action/:id'
An incoming path of /photos/show/1?user_id=2 will be dispatched to the show action of the Photos controller. params will be { :controller => “photos”, :action => “show”, :id => “1”, :user_id => “2” }.
---------------------------------------------------------------------------------------------------------------------------------------------------------
Advanced Constraints
If you have a more advanced constraint, you can provide an object that responds to matches? that Rails should use. Let’s say you wanted to route all users on a blacklist to the BlacklistController. You could do:
class BlacklistConstraint
def initialize
@ips = Blacklist.retrieve_ips
end
def matches?(request)
@ips.include?(request.remote_ip)
end
end
TwitterClone::Application.routes.draw do
match "*path" => "blacklist#index",
:constraints => BlacklistConstraint.new
end
---------------------------------------------------------------------------------------------------------------------------------------------------------
You should put the root route at the end of the file
You may restrict the listing to the routes that map to a particular controller setting the CONTROLLER environment variable:
$ CONTROLLER=users rake routes
---------------------------------------------------------------------------------------------------------------------------------------------------------
session is only available in the controller and the view and can use one of a number of different storage mechanisms:
CookieStore – Stores everything on the client.
DRbStore – Stores the data on a DRb server.
MemCacheStore – Stores the data in a memcache.
ActiveRecordStore – Stores the data in a database using Active Record.
Sessions are lazily loaded.
flash is a special part of the session which is cleared with each request.
#If an action sets the flash and redirects here, the values
# would normally be lost when another redirect happens, but you
# can use 'flash.keep' to make it persist for another request.
#you can use flash.now to print the flash at the current request.
Note that while for session values you set the key to nil, to delete a cookie value you should use cookies.delete(:key).
---------------------------------------------------------------------------------------------------------------------------------------------------------
Obviously, after filters can not stop the action from running.
Around filters are responsible for running the action, but they can choose not to, which is the around filter’s way of stopping it.
#example:
class ApplicationController < ActionController::Base
around_filter :catch_exceptions
private
def catch_exceptions
yield
rescue => exception
logger.debug "Caught exception! #{exception}"
raise
end
end
---------------------------------------------------------------------------------------------------------------------------------------------------------
The request Object
Property of request Purpose
host The hostname used for this request.
domain(n=2) The hostname’s first n segments, starting from the right (the TLD).
format The content type requested by the client.
method The HTTP method used for the request.
get?, post?, put?, delete?, head? Returns true if the HTTP method is GET/POST/PUT/DELETE/HEAD.
headers Returns a hash containing the headers associated with the request.
port The port number (integer) used for the request.
protocol Returns a string containing the protocol used plus “://”, for example “http://”.
query_string The query string part of the URL, i.e., everything after “?”.
remote_ip The IP address of the client.
url The entire URL used for the request.
---------------------------------------------------------------------------------------------------------------------------------------------------------
The response Object
The response object is not usually used directly, but is built up during the execution of the action and rendering of the data that is being sent back to the user, but sometimes – like in an after filter – it can be useful to access the response directly. Some of these accessor methods also have setters, allowing you to change their values.
Property of response Purpose
body This is the string of data being sent back to the client. This is most often HTML.
status The HTTP status code for the response, like 200 for a successful request or 404 for file not found.
location The URL the client is being redirected to, if any.
content_type The content type of the response.
charset The character set being used for the response. Default is “utf-8”.
headers Headers used for the response.
---------------------------------------------------------------------------------------------------------------------------------------------------------
From the controller’s point of view, there are three ways to create an HTTP response:
Call render to create a full response to send back to the browser
Call redirect_to to send an HTTP redirect status code to the browser
Call head to create a response consisting solely of HTTP headers to send back to the browser
---------------------------------------------------------------------------------------------------------------------------------------------------------
The Difference Between render and redirect_to:
redirect_to ---Your code stops running and waits for a new request for the browser. It just happens that you’ve told the browser what request it should make next, by sending back an HTTP 302 status code.
render ---doesn’t run any code in the target action,just render the page.
#we can initialize the data at current action to avoid twice request,for make up speed.
---------------------------------------------------------------------------------------------------------------------------------------------------------
The javascript_include_tag helper returns an HTML script tag for each source provided.
The stylesheet_link_tag helper returns an HTML <link> tag for each source provided.
---------------------------------------------------------------------------------------------------------------------------------------------------------
You can also create a layout with multiple yielding regions:
<html>
<head>
<%= yield :head %>
</head>
<body>
<%= yield %>
</body>
</html>
The main body of the view will always render into the unnamed yield. To render content into a named yield, you use the content_for method.
---------------------------------------------------------------------------------------------------------------------------------------------------------
#example:
A basic search form
<%= form_tag(search_path, :method => "get") do %>
<%= label_tag(:q, "Search for:") %>
<%= text_field_tag(:q) %>
<%= submit_tag("Search") %>
<% end %>
search_path can be a named route specified in “routes.rb”:
map.search “search”, :controller => “search”
The above view code will result in the following markup:
<form action="/search" method="get">
<label for="q">Search for:</label>
<input id="q" name="q" type="text" />
<input name="commit" type="submit" value="Search" />
</form>
For every form input, an ID attribute is generated from its name (“q” in the example). These IDs can be very useful for CSS styling or manipulation of form controls with JavaScript.
---------------------------------------------------------------------------------------------------------------------------------------------------------
form_tag(:controller => "people", :action => "search", :method => "get", :class => "nifty_form")
# => <form action="/people/search?method=get&class=nifty_form" method="post">
Here you wanted to pass two hashes, but the Ruby interpreter sees only one hash, so Rails will construct a URL with extraneous parameters. The correct way of passing multiple hashes as arguments is to delimit the first hash (or both hashes) with curly brackets:
form_tag({:controller => "people", :action => "search"}, :method => "get", :class => "nifty_form")
# => <form action="/people/search" method="get" class="nifty_form">
This is a common pitfall when using form helpers, since many of them accept multiple hashes. So in future, if a helper produces unexpected output, make sure that you have delimited the hash parameters properly.
Do not delimit the second hash without doing so with the first hash, otherwise your method invocation will result in an expecting tASSOC syntax error.
---------------------------------------------------------------------------------------------------------------------------------------------------------
Each test method gets a freshly initialized table in the test database, loaded
from the fixtures we provide. This is automatically done by the rake test com-
mand, but can be done separately by running rake db:test:prepare.
---------------------------------------------------------------------------------------------------------------------------------------------------------
when want to display html code from ruby code must use the #method: html_safe
#usage:<%= select_tag(:product,"<option>mafei</option>".html_safe)
---------------------------------------------------------------------------------------------------------------------------------------------------------
rails的session默认based on a cookieStore,4K大小限制,为了安全仅把user_id 和 flash消息放入session.
A secure hash is included with the cookie to ensure data integrity (a user cannot alter his user id
without knowing the secret key included in the hash).
---------------------------------------------------------------------------------------------------------------------------------------------------------
object.update_attributes! :xxx => 'xxx'
如果更新失败数据库不改变,但是object里面的xxx属性是会改变的
---------------------------------------------------------------------------------------------------------------------------------------------------------
Something went wrong with that request. Please try again.