提交 4930f9d2 编写于 作者: V Vijay Dev

Merge branch 'master' of github.com:lifo/docrails

...@@ -177,7 +177,7 @@ def #{filter}_filter(*names, &blk) ...@@ -177,7 +177,7 @@ def #{filter}_filter(*names, &blk)
def prepend_#{filter}_filter(*names, &blk) # def prepend_before_filter(*names, &blk) def prepend_#{filter}_filter(*names, &blk) # def prepend_before_filter(*names, &blk)
_insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options| _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options|
options[:if] = (Array.wrap(options[:if]) << "!halted") if #{filter == :after} # options[:if] = (Array.wrap(options[:if]) << "!halted") if false options[:if] = (Array.wrap(options[:if]) << "!halted") if #{filter == :after} # options[:if] = (Array.wrap(options[:if]) << "!halted") if false
set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true)) # set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true)) set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true)) # set_callback(:process_action, :before, name, options.merge(:prepend => true))
end # end end # end
end # end end # end
...@@ -185,7 +185,7 @@ def prepend_#{filter}_filter(*names, &blk) ...@@ -185,7 +185,7 @@ def prepend_#{filter}_filter(*names, &blk)
# for details on the allowed parameters. # for details on the allowed parameters.
def skip_#{filter}_filter(*names, &blk) # def skip_before_filter(*names, &blk) def skip_#{filter}_filter(*names, &blk) # def skip_before_filter(*names, &blk)
_insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options| _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options|
skip_callback(:process_action, :#{filter}, name, options) # skip_callback(:process_action, :#{filter}, name, options) skip_callback(:process_action, :#{filter}, name, options) # skip_callback(:process_action, :before, name, options)
end # end end # end
end # end end # end
......
...@@ -13,7 +13,7 @@ endprologue. ...@@ -13,7 +13,7 @@ endprologue.
WARNING. This Guide is based on Rails 3.0. Some of the code shown here will not work in other versions of Rails. WARNING. This Guide is based on Rails 3.0. Some of the code shown here will not work in other versions of Rails.
If you're used to using raw SQL to find database records then, generally, you will find that there are better ways to carry out the same operations in Rails. Active Record insulates you from the need to use SQL in most cases. If you're used to using raw SQL to find database records, then you will generally find that there are better ways to carry out the same operations in Rails. Active Record insulates you from the need to use SQL in most cases.
Code examples throughout this guide will refer to one or more of the following models: Code examples throughout this guide will refer to one or more of the following models:
...@@ -69,16 +69,16 @@ The methods are: ...@@ -69,16 +69,16 @@ The methods are:
All of the above methods return an instance of <tt>ActiveRecord::Relation</tt>. All of the above methods return an instance of <tt>ActiveRecord::Relation</tt>.
Primary operation of <tt>Model.find(options)</tt> can be summarized as: The primary operation of <tt>Model.find(options)</tt> can be summarized as:
* Convert the supplied options to an equivalent SQL query. * Convert the supplied options to an equivalent SQL query.
* Fire the SQL query and retrieve the corresponding results from the database. * Fire the SQL query and retrieve the corresponding results from the database.
* Instantiate the equivalent Ruby object of the appropriate model for every resulting row. * Instantiate the equivalent Ruby object of the appropriate model for every resulting row.
* Run +after_find+ callbacks if any. * Run +after_find+ callbacks, if any.
h4. Retrieving a Single Object h4. Retrieving a Single Object
Active Record lets you retrieve a single object using five different ways. Active Record provides five different ways of retrieving a single object.
h5. Using a Primary Key h5. Using a Primary Key
...@@ -87,10 +87,10 @@ Using <tt>Model.find(primary_key)</tt>, you can retrieve the object correspondin ...@@ -87,10 +87,10 @@ Using <tt>Model.find(primary_key)</tt>, you can retrieve the object correspondin
<ruby> <ruby>
# Find the client with primary key (id) 10. # Find the client with primary key (id) 10.
client = Client.find(10) client = Client.find(10)
=> #<Client id: 10, first_name: => "Ryan"> # => #<Client id: 10, first_name: "Ryan">
</ruby> </ruby>
SQL equivalent of the above is: The SQL equivalent of the above is:
<sql> <sql>
SELECT * FROM clients WHERE (clients.id = 10) SELECT * FROM clients WHERE (clients.id = 10)
...@@ -100,14 +100,14 @@ SELECT * FROM clients WHERE (clients.id = 10) ...@@ -100,14 +100,14 @@ SELECT * FROM clients WHERE (clients.id = 10)
h5. +first+ h5. +first+
<tt>Model.first</tt> finds the first record matched by the supplied options. For example: <tt>Model.first</tt> finds the first record matched by the supplied options, if any. For example:
<ruby> <ruby>
client = Client.first client = Client.first
=> #<Client id: 1, first_name: "Lifo"> # => #<Client id: 1, first_name: "Lifo">
</ruby> </ruby>
SQL equivalent of the above is: The SQL equivalent of the above is:
<sql> <sql>
SELECT * FROM clients LIMIT 1 SELECT * FROM clients LIMIT 1
...@@ -121,10 +121,10 @@ h5. +last+ ...@@ -121,10 +121,10 @@ h5. +last+
<ruby> <ruby>
client = Client.last client = Client.last
=> #<Client id: 221, first_name: "Russel"> # => #<Client id: 221, first_name: "Russel">
</ruby> </ruby>
SQL equivalent of the above is: The SQL equivalent of the above is:
<sql> <sql>
SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1 SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1
...@@ -138,10 +138,10 @@ h5(#first_1). +first!+ ...@@ -138,10 +138,10 @@ h5(#first_1). +first!+
<ruby> <ruby>
client = Client.first! client = Client.first!
=> #<Client id: 1, first_name: "Lifo"> # => #<Client id: 1, first_name: "Lifo">
</ruby> </ruby>
SQL equivalent of the above is: The SQL equivalent of the above is:
<sql> <sql>
SELECT * FROM clients LIMIT 1 SELECT * FROM clients LIMIT 1
...@@ -155,10 +155,10 @@ h5(#last_1). +last!+ ...@@ -155,10 +155,10 @@ h5(#last_1). +last!+
<ruby> <ruby>
client = Client.last! client = Client.last!
=> #<Client id: 221, first_name: "Russel"> # => #<Client id: 221, first_name: "Russel">
</ruby> </ruby>
SQL equivalent of the above is: The SQL equivalent of the above is:
<sql> <sql>
SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1 SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1
...@@ -174,11 +174,11 @@ h5. Using Multiple Primary Keys ...@@ -174,11 +174,11 @@ h5. Using Multiple Primary Keys
<ruby> <ruby>
# Find the clients with primary keys 1 and 10. # Find the clients with primary keys 1 and 10.
client = Client.find(1, 10) # Or even Client.find([1, 10]) client = Client.find([1, 10]) # Or even Client.find(1, 10)
=> [#<Client id: 1, first_name: => "Lifo">, #<Client id: 10, first_name: => "Ryan">] # => [#<Client id: 1, first_name: "Lifo">, #<Client id: 10, first_name: "Ryan">]
</ruby> </ruby>
SQL equivalent of the above is: The SQL equivalent of the above is:
<sql> <sql>
SELECT * FROM clients WHERE (clients.id IN (1,10)) SELECT * FROM clients WHERE (clients.id IN (1,10))
...@@ -190,7 +190,7 @@ h4. Retrieving Multiple Objects in Batches ...@@ -190,7 +190,7 @@ h4. Retrieving Multiple Objects in Batches
Sometimes you need to iterate over a large set of records. For example to send a newsletter to all users, to export some data, etc. Sometimes you need to iterate over a large set of records. For example to send a newsletter to all users, to export some data, etc.
The following may seem very straight forward at first: The following may seem very straightforward, at first:
<ruby> <ruby>
# Very inefficient when users table has thousands of rows. # Very inefficient when users table has thousands of rows.
...@@ -199,9 +199,9 @@ User.all.each do |user| ...@@ -199,9 +199,9 @@ User.all.each do |user|
end end
</ruby> </ruby>
But if the total number of rows in the table is very large, the above approach may vary from being under performant to just plain impossible. But if the total number of rows in the table is very large, the above approach may vary from being underperforming to being plain impossible.
This is because +User.all.each+ makes Active Record fetch _the entire table_, build a model object per row, and keep the entire array in the memory. Sometimes that is just too many objects and demands too much memory. This is because +User.all.each+ makes Active Record fetch _the entire table_, build a model object per row, and keep the entire array of model objects in memory. Sometimes that is just too many objects and requires too much memory.
h5. +find_each+ h5. +find_each+
...@@ -215,9 +215,9 @@ end ...@@ -215,9 +215,9 @@ end
*Configuring the batch size* *Configuring the batch size*
Behind the scenes +find_each+ fetches rows in batches of +1000+ and yields them one by one. The size of the underlying batches is configurable via the +:batch_size+ option. Behind the scenes, +find_each+ fetches rows in batches of 1000 and yields them one by one. The size of the underlying batches is configurable via the +:batch_size+ option.
To fetch +User+ records in batch size of +5000+: To fetch +User+ records in batches of 5000, we can use:
<ruby> <ruby>
User.find_each(:batch_size => 5000) do |user| User.find_each(:batch_size => 5000) do |user|
...@@ -227,9 +227,9 @@ end ...@@ -227,9 +227,9 @@ end
*Starting batch find from a specific primary key* *Starting batch find from a specific primary key*
Records are fetched in ascending order on the primary key, which must be an integer. The +:start+ option allows you to configure the first ID of the sequence if the lowest is not the one you need. This may be useful for example to be able to resume an interrupted batch process if it saves the last processed ID as a checkpoint. Records are fetched in ascending order of the primary key, which must be an integer. The +:start+ option allows you to configure the first ID of the sequence whenever the lowest ID is not the one you need. This may be useful, for example, to be able to resume an interrupted batch process, provided it saves the last processed ID as a checkpoint.
To send newsletters only to users with the primary key starting from +2000+: To send newsletters only to users with the primary key starting from 2000, we can use:
<ruby> <ruby>
User.find_each(:batch_size => 5000, :start => 2000) do |user| User.find_each(:batch_size => 5000, :start => 2000) do |user|
...@@ -252,7 +252,9 @@ Invoice.find_in_batches(:include => :invoice_lines) do |invoices| ...@@ -252,7 +252,9 @@ Invoice.find_in_batches(:include => :invoice_lines) do |invoices|
end end
</ruby> </ruby>
The above will yield the supplied block with +1000+ invoices every time. The above will each time yield to the supplied block an array of 1000 invoices (or the remaining invoices, if less than 1000).
NOTE: The +:include+ option allows you to name associations that should be loaded alongside with the models.
h3. Conditions h3. Conditions
...@@ -911,14 +913,14 @@ end ...@@ -911,14 +913,14 @@ end
To call this +published+ scope we can call it on either the class: To call this +published+ scope we can call it on either the class:
<ruby> <ruby>
Post.published => [published posts] Post.published # => [published posts]
</ruby> </ruby>
Or on an association consisting of +Post+ objects: Or on an association consisting of +Post+ objects:
<ruby> <ruby>
category = Category.first category = Category.first
category.posts.published => [published posts belonging to this category] category.posts.published # => [published posts belonging to this category]
</ruby> </ruby>
h4. Working with times h4. Working with times
...@@ -1030,7 +1032,7 @@ Suppose you want to find a client named 'Andy', and if there's none, create one ...@@ -1030,7 +1032,7 @@ Suppose you want to find a client named 'Andy', and if there's none, create one
<ruby> <ruby>
Client.where(:first_name => 'Andy').first_or_create(:locked => false) Client.where(:first_name => 'Andy').first_or_create(:locked => false)
# => <Client id: 1, first_name: "Andy", orders_count: 0, locked: false, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27"> # => #<Client id: 1, first_name: "Andy", orders_count: 0, locked: false, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27">
</ruby> </ruby>
The SQL generated by this method looks like this: The SQL generated by this method looks like this:
......
...@@ -46,7 +46,7 @@ end ...@@ -46,7 +46,7 @@ end
We can see how it works by looking at some +rails console+ output: We can see how it works by looking at some +rails console+ output:
<shell> <ruby>
>> p = Person.new(:name => "John Doe") >> p = Person.new(:name => "John Doe")
=> #<Person id: nil, name: "John Doe", created_at: nil, :updated_at: nil> => #<Person id: nil, name: "John Doe", created_at: nil, :updated_at: nil>
>> p.new_record? >> p.new_record?
...@@ -55,7 +55,7 @@ We can see how it works by looking at some +rails console+ output: ...@@ -55,7 +55,7 @@ We can see how it works by looking at some +rails console+ output:
=> true => true
>> p.new_record? >> p.new_record?
=> false => false
</shell> </ruby>
Creating and saving a new record will send an SQL +INSERT+ operation to the database. Updating an existing record will send an SQL +UPDATE+ operation instead. Validations are typically run before these commands are sent to the database. If any validations fail, the object will be marked as invalid and Active Record will not perform the +INSERT+ or +UPDATE+ operation. This helps to avoid storing an invalid object in the database. You can choose to have specific validations run when an object is created, saved, or updated. Creating and saving a new record will send an SQL +INSERT+ operation to the database. Updating an existing record will send an SQL +UPDATE+ operation instead. Validations are typically run before these commands are sent to the database. If any validations fail, the object will be marked as invalid and Active Record will not perform the +INSERT+ or +UPDATE+ operation. This helps to avoid storing an invalid object in the database. You can choose to have specific validations run when an object is created, saved, or updated.
......
...@@ -719,9 +719,9 @@ X.local_constants # => ["X2", "X1", "Y"], assumes Ruby 1.8 ...@@ -719,9 +719,9 @@ X.local_constants # => ["X2", "X1", "Y"], assumes Ruby 1.8
X::Y.local_constants # => ["X1", "Y1"], assumes Ruby 1.8 X::Y.local_constants # => ["X1", "Y1"], assumes Ruby 1.8
</ruby> </ruby>
The names are returned as strings in Ruby 1.8, and as symbols in Ruby 1.9. The method +local_constant_names+ returns always strings. The names are returned as strings in Ruby 1.8, and as symbols in Ruby 1.9. The method +local_constant_names+ always returns strings.
WARNING: This method is exact if running under Ruby 1.9. In previous versions it may miss some constants if their value in some ancestor stores the exact same object than in the receiver. WARNING: This method returns precise results in Ruby 1.9. In older versions of Ruby, however, it may miss some constants in case the same constant exists in the receiver module as well as in any of its ancestors and both constants point to the same object (objects are compared using +Object#object_id+).
NOTE: Defined in +active_support/core_ext/module/introspection.rb+. NOTE: Defined in +active_support/core_ext/module/introspection.rb+.
......
...@@ -120,7 +120,7 @@ All subdirectories that exist within these three locations are added to the sear ...@@ -120,7 +120,7 @@ All subdirectories that exist within these three locations are added to the sear
You can add additional (fully qualified) paths to the pipeline in +config/application.rb+. For example: You can add additional (fully qualified) paths to the pipeline in +config/application.rb+. For example:
<ruby> <ruby>
config.assets.paths << "#{Rails.root}/app/assets/flash" config.assets.paths << Rails.root.join("app", "assets", "flash")
</ruby> </ruby>
h4. Coding Links to Assets h4. Coding Links to Assets
...@@ -232,7 +232,7 @@ There's also a default +app/assets/stylesheets/application.css+ file which conta ...@@ -232,7 +232,7 @@ There's also a default +app/assets/stylesheets/application.css+ file which conta
The directives that work in the JavaScript files also work in stylesheets, obviously including stylesheets rather than JavaScript files. The +require_tree+ directive here works the same way as the JavaScript one, requiring all stylesheets from the current directory. The directives that work in the JavaScript files also work in stylesheets, obviously including stylesheets rather than JavaScript files. The +require_tree+ directive here works the same way as the JavaScript one, requiring all stylesheets from the current directory.
In this example +require_self+ is used. This puts the CSS contained within the file (if any) at the top of any other CSS in this file unless +require_self+ is specified after another +require+ directive. In this example +require_self+ is used. This puts the CSS contained within the file (if any) at the precise location of the +require_self+ call. If +require_self+ is called more than once, only the last call is respected.
You can have as many manifest files as you need. For example the +admin.css+ and +admin.js+ manifest could contain the JS and CSS files that are used for the admin section of an application. You can have as many manifest files as you need. For example the +admin.css+ and +admin.js+ manifest could contain the JS and CSS files that are used for the admin section of an application.
......
...@@ -188,7 +188,7 @@ end ...@@ -188,7 +188,7 @@ end
You may notice that the actual product gets passed to the sweeper, so if we were caching the edit action for each product, we could add an expire method which specifies the page we want to expire: You may notice that the actual product gets passed to the sweeper, so if we were caching the edit action for each product, we could add an expire method which specifies the page we want to expire:
<ruby> <ruby>
expire_action(:controller => 'products', :action => 'edit', :id => product) expire_action(:controller => 'products', :action => 'edit', :id => product.id)
</ruby> </ruby>
Then we add it to our controller to tell it to call the sweeper when certain actions are called. So, if we wanted to expire the cached content for the list and edit actions when the create action was called, we could do the following: Then we add it to our controller to tell it to call the sweeper when certain actions are called. So, if we wanted to expire the cached content for the list and edit actions when the create action was called, we could do the following:
......
...@@ -461,12 +461,31 @@ Rails has 5 initialization events which can be hooked into (listed in the order ...@@ -461,12 +461,31 @@ Rails has 5 initialization events which can be hooked into (listed in the order
* +before_initialize+: This is run directly before the initialization process of the application occurs with the +:bootstrap_hook+ initializer near the beginning of the Rails initialization process. * +before_initialize+: This is run directly before the initialization process of the application occurs with the +:bootstrap_hook+ initializer near the beginning of the Rails initialization process.
* +to_prepare+: Run after the initializers are ran for all Railties (including the application itself), but before eager loading and the middleware stack is built. * +to_prepare+: Run after the initializers are ran for all Railties (including the application itself), but before eager loading and the middleware stack is built. More importantly, will run upon every request in +development+, but only once (during boot-up) in +production+ and +test+.
* +before_eager_load+: This is run directly before eager loading occurs, which is the default behaviour for the _production_ environment and not for the +development+ environment. * +before_eager_load+: This is run directly before eager loading occurs, which is the default behaviour for the _production_ environment and not for the +development+ environment.
* +after_initialize+: Run directly after the initialization of the application, but before the application initializers are run. * +after_initialize+: Run directly after the initialization of the application, but before the application initializers are run.
To define an event for these hooks, use the block syntax within a +Rails::Aplication+, +Rails::Railtie+ or +Rails::Engine+ subclass:
<ruby>
module YourApp
class Application < Rails::Application
config.before_initialize do
# initialization code goes here
end
end
end
</ruby>
Alternatively, you can also do it through the +config+ method on the +Rails.application+ object:
<ruby>
Rails.application.config.before_initialize do
# initialization code goes here
end
</ruby>
WARNING: Some parts of your application, notably observers and routing, are not yet set up at the point where the +after_initialize+ block is called. WARNING: Some parts of your application, notably observers and routing, are not yet set up at the point where the +after_initialize+ block is called.
......
...@@ -12,13 +12,50 @@ endprologue. ...@@ -12,13 +12,50 @@ endprologue.
h3. What are engines? h3. What are engines?
Engines can be considered miniature applications that provide functionality to their host applications. A Rails application is actually just a "supercharged" engine, with the `Rails::Application` class inheriting from `Rails::Engine`. Therefore, engines and applications share common functionality but are at the same time two separate beasts. Engines can be considered miniature applications that provide functionality to their host applications. A Rails application is actually just a "supercharged" engine, with the +Rails::Application+ class inheriting from +Rails::Engine+. Therefore, engines and applications share common functionality but are at the same time two separate beasts. Engines and applications also share a common structure, as you'll see later in this guide.
Engines are also closely related to plugins where the two share a common +lib+ directory structure and are both generated using the +rails plugin new+ generator.
The engine that will be generated for this guide will be called "blorgh". The engine will provide blogging functionality to its host applications, allowing for new posts and comments to be created. For now, you will be working solely within the engine itself and in later sections you'll see how to hook it into an application.
Engines can also be isolated from their host applications. This means that an application is able to have a path provided by a routing helper such as +posts_path+ and use an engine also that provides a path also called +posts_path+, and the two would not clash. Along with this, controllers, models and table names are also namespaced. You'll see how to do this later in this guide.
To see demonstrations of other engines, check out "Devise":https://github.com/plataformatec/devise, an engine that provides authentication for its parent applications, or "Forem":https://github.com/radar/forem, an engine that provides forum functionality.
h3. Generating an engine h3. Generating an engine
TODO: The engine that will be generated for this guide will be called "blorgh". It's a blogging engine that provides posts and comments and that's it. To generate an engine with Rails 3.1, you will need to run the plugin generator and pass it the +--mountable+ option. To generate the beginnings of the "blorgh" engine you will need to run this command in a terminal:
<shell>
$ rails plugin new blorgh --mountable
</shell>
The +--mountable+ option tells the plugin generator that you want to create an engine (which is a mountable plugin, hence the option name), creating the basic directory structure of an engine by providing things such as the foundations of an +app+ folder, as well a +config/routes.rb+ file. This generator also provides a file at +lib/blorgh/engine.rb+ which is identical in function to an application's +config/application.rb+ file.
Inside the +app+ directory there lives the standard +assets+, +controllers+, +helpers+, +mailers+, +models+ and +views+ directories that you should be familiar with from an application.
At the root of the engine's directory, lives a +blorgh.gemspec+ file. When you include the engine into the application later on, you will do so with this line in a Rails application's +Gemfile+:
<ruby>
gem 'blorgh', :path => "vendor/engines/blorgh"
</ruby>
By specifying it as a gem within the +Gemfile+, Bundler will load it as such, parsing this +blorgh.gemspec+ file and requiring a file within the +lib+ directory called +lib/blorgh.rb+. This file requires the +blorgh/engine.rb+ file (located at +lib/blorgh/engine.rb+) and defines a base module called +Blorgh+.
<ruby>
require "blorgh/engine"
module Blorgh
end
</ruby>
Within +lib/blorgh/engine.rb+ is the base class for the engine:
<ruby>
TODO: lib/blorgh/engine.rb
</ruby>
TODO: Describe here the process of generating an engine and what an engine comes with. Within the +app/controllers+ directory there is a +blorgh+ directory and inside that a file called +application_controller.rb+. This file will provide any common functionality for the controllers of the engine. The +blorgh+ directory is where the other controllers for the engine will go. By placing them within this namespaced directory, you prevent them from possibly clashing with identically-named controllers within other engines or even within the application.
h3. Providing engine functionality h3. Providing engine functionality
......
...@@ -628,7 +628,7 @@ There is no need (and it is error prone) to deploy a new instance of an app by r ...@@ -628,7 +628,7 @@ There is no need (and it is error prone) to deploy a new instance of an app by r
For example, this is how the test database is created: the current development database is dumped (either to +db/schema.rb+ or +db/development.sql+) and then loaded into the test database. For example, this is how the test database is created: the current development database is dumped (either to +db/schema.rb+ or +db/development.sql+) and then loaded into the test database.
Schema files are also useful if you want a quick look at what attributes an Active Record object has. This information is not in the model's code and is frequently spread across several migrations but is all summed up in the schema file. The "annotate_models":http://agilewebdevelopment.com/plugins/annotate_models plugin, which automatically adds (and updates) comments at the top of each model summarizing the schema, may also be of interest. Schema files are also useful if you want a quick look at what attributes an Active Record object has. This information is not in the model's code and is frequently spread across several migrations, but is summed up in the schema file. The "annotate_models":https://github.com/ctran/annotate_models gem automatically adds and updates comments at the top of each model summarizing the schema if you desire that functionality.
h4. Types of Schema Dumps h4. Types of Schema Dumps
......
...@@ -596,6 +596,8 @@ match "/stories/:name" => redirect {|params| "/posts/#{params[:name].pluralize}" ...@@ -596,6 +596,8 @@ match "/stories/:name" => redirect {|params| "/posts/#{params[:name].pluralize}"
match "/stories" => redirect {|p, req| "/posts/#{req.subdomain}" } match "/stories" => redirect {|p, req| "/posts/#{req.subdomain}" }
</ruby> </ruby>
Please note that this redirection is a 301 "Moved Permanently" redirect. Keep in mind that some web browsers or proxy servers will cache this type of redirect, making the old page inaccessible.
In all of these cases, if you don't provide the leading host (+http://www.example.com+), Rails will take those details from the current request. In all of these cases, if you don't provide the leading host (+http://www.example.com+), Rails will take those details from the current request.
h4. Routing to Rack Applications h4. Routing to Rack Applications
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册