25、Rails路由与控制器全解析

Rails路由与控制器全解析

1. 命名路由的强大之处

在Rails中, connect root 并非定义路由的唯一方法名。实际上,你可以随意选择一个名称来定义路由,只需用它替代 connect 即可。例如:

map.catalog “library/“, :controller => “library”, :action => “list”

这会生成一个名为 catalog 的命名路由,可通过 catalog_url catalog_path 来引用( catalog_path 不包含主机名和端口号)。若要重定向到 library 控制器的 list 动作,可使用:

redirect_to(catalog_url)

这种方式简洁明了,且由于你为路由指定了有意义的名称,代码的可读性也大大提高。与之相比,使用 connect 创建的匿名路由则稍显繁琐:

redirect_to(:controller => “library”, :action => “list”)

若路由包含命名参数,例如:

map.borrow_book “library/borrow/:isbn”, 
                :controller => “library”,
                :action => “borrow”

获取该路由的URL很简单,只需调用 borrow_book_url 并传入ISBN即可:

borrow_book_url(“9780307237699”)
# 或者
borrow_book_url(:isbn => “9780307237699”)

若模式中存在多个命名参数,它们将按出现顺序或使用常规的哈希表示法传递给辅助方法。

2. RESTful路由

REST(表述性状态转移)在开发基本博客应用时就已被引入。RESTful路由被视为Rails应用的新标准,在可能的情况下,应优先使用它而非传统路由方式。简单来说,RESTful路由不仅将URL与控制器中的代码匹配,还将资源标识符(如URL)和HTTP动词映射到七个预定义的动作,这些动作通常通过模型层在数据库中执行CRUD操作。

2.1 map.resources

RESTful路由可通过 resources 方法定义。例如:

map.resources :books

若要声明多个资源,可在一行中传递符号列表:

map.resources :books, :catalogs, :users

这一行代码能创建七个RESTful路由,具体如下表所示:
| 路由名称 | HTTP方法 | URL | BooksController中的动作 |
| — | — | — | — |
| books | GET | /books | index |
| formatted_books | POST | /books | create |
| new_book | GET | /books/new | new |
| book | GET | /books/:id | show |
| edit_book | GET | /books/:id/edit | edit |
| formatted_book | PUT | /books/:id | update |
| formatted_book | DELETE | /books/:id | destroy |

每个命名路由都可通过 _url _path 辅助方法访问(不包括以 formatted_ 开头的路由)。不过,在Rails 2.3中,格式化路由将被移除,因为它们很少使用且会占用内存。格式化辅助方法也将被替代,可通过向常规路由辅助方法传递 :format 参数来实现相同功能,例如:

books_path(:format => “xml”)

实际上,生成的路由数量不止七个,因为上述每个路由都有一个包含 :format 参数的对应路由。整个REST范式基于这样一个理念:对于给定资源,可以有多种“表示形式”。以下是包含 :format 参数的路由表:
| 路由名称 | HTTP方法 | URL | BooksController中的动作 |
| — | — | — | — |
| formatted_books | GET | /books.:format | index |
| formatted_books | POST | /books.:format | create |
| formatted_new_book | GET | /books/new.:format | new |
| formatted_book | GET | /books/:id.:format | - |
| formatted_edit_book | GET | /books/:id/edit:format | edit |
| formatted_book | PUT | /books/:id.format | update |
| formatted_book | DELETE | /books/:id.:format | destroy |

id 的值可通过 params[:id] 访问, format 则可通过 params[:format] 访问。不过,使用 respond_to 方法可避免通过 params 哈希对象来获取格式。例如, GET /books 请求将由 index 动作处理,而 POST /books 请求将映射到 create 动作。同样, GET /books.xml 仍由 index 动作处理,但请求格式为XML,动作应相应地提供XML响应。

由于HTTP动词在路由系统中具有重要意义,若要删除资源,仅访问URL是不够的,必须显式发送 DELETE 请求。这为应用提供了额外的保护,可防止意外的、可能造成损害的操作。例如,网络爬虫通常不会向Web应用发送 DELETE 请求。

若不需要全部七个动作,可通过指定 :only :except 选项来节省内存资源。例如:

map.resources :books, :only => [:index, :show]
2.2 map.resource

resources 方法假设 index 动作将显示资源列表,而其他动作用于显示、编辑、创建和销毁单个资源。当需要处理单个资源(即单例资源)时,可使用 resource 方法。传递给该方法的符号应为单数形式,而对应的控制器默认使用复数形式。例如:

map.resource :catalog

运行 rake routes 可查看生成的路由,这些路由与 resources 生成的有所不同,且均为单数形式:

POST   /catalog               {:controller=>”catalogs”, :action=>”create”}
POST   /catalog.:format       {:controller=>”catalogs”, :action=>”create”}
new_catalog
GET    /catalog/new           {:controller=>”catalogs”, :action=>”new”}
formatted_new_catalog
GET    /catalog/new.:format   {:controller=>”catalogs”, :action=>”new”}
edit_catalog
GET    /catalog/edit          {:controller=>”catalogs”, :action=>”edit”}
formatted_edit_catalog 
GET    /catalog/edit.:format  {:controller=>”catalogs”, :action=>”edit”}
catalog 
GET    /catalog              {:controller=>”catalogs”, :action=>”show”}
formatted_catalog 
GET    /catalog.:format      {:controller=>”catalogs”, :action=>”show”}
PUT    /catalog              {:controller=>”catalogs”, :action=>”update”}
PUT    /catalog.:format      {:controller=>”catalogs”, :action=>”update”}
DELETE /catalog              {:controller=>”catalogs”, :action=>”destroy”}
DELETE /catalog.:format      {:controller=>”catalogs”, :action=>”destroy”}

通过控制台查看路由可能不太直观,对于复杂的路由项目,可考虑安装Vasco插件,它是一个路由浏览器,可从 http://github.com/relevance/vasco 获取。 GET /catalog 将显示单例资源(无需通过 id 标识,因为它是全局唯一的),且没有任何路由映射到 index 动作,因为只有一个目录,无需列表。

3. 自定义RESTful路由

通过向 resources 方法传递额外参数的哈希,可自定义生成的路由。除了前面提到的 :only :except 选项(Rails 2.2中引入),还有以下几个常用选项:

3.1 :as

:as 选项为每个生成的路由指定一个不同的路径名称。例如:

map.resources :books, :as => “titles”

这将生成与前面表格中相同的路由,但路径为 titles 而非 books 。因此, GET /titles/42 将映射到 BooksController show 动作。此选项常用于资源名称包含下划线,但希望URL中使用连字符的情况。需要注意的是,生成的 _url _path 辅助方法仍基于资源名称,例如,仍然是 new_book_url new_book_path ,而非 new_title_url new_title_path

3.2 :collection, :member, 和 :new

这三个选项用于添加映射到除七个默认动作之外的其他动作的路由。 :collection 为处理集合资源的动作指定一个或多个命名路由。例如:

map.resources :books, :collection => { :search => :get }

这将识别 GET /books/search 请求,并生成 search_books_url search_books_path 辅助方法(以及添加 formatted_ 后的两个对应辅助方法)。HTTP方法的可接受值包括 :get :post :put :delete :any 。当请求的HTTP动词无关紧要时,可使用 :any

:member :collection 类似,但用于处理集合中的单个成员的动作。例如:

map.resources :books, :member => { :borrow => :post }

这将生成访问 borrow_book 命名路由的辅助方法。

:new 用于定义创建新资源的路由。例如:

map.resources :books, :new => { :register => :post }

POST /books/new/register 这样的请求将被识别,并由 BooksController register 动作处理。生成的命名路由为 register_new_books formatted_register_new_books 。若要更改现有 new 方法的接受动词映射,也可通过 :new 参数实现。例如:

map.resources :books, :new => { :new => :any, :register => :post }
3.3 :conditions

:conditions 参数最初作为 connect 方法的选项引入。由于它用于定义单个路由的HTTP动词限制,在RESTful上下文中很少使用。

3.4 :controller

:controller 选项为生成的路由指定不同的控制器。例如:

map.resources :books, :controller => “titles”

当接收到 GET /books 请求时,Rails将知道由 TitlesController index 动作处理该请求。生成的命名路由和辅助方法仍基于资源名称,因此不受影响。

3.5 :has_one 和 :has_many

:has_one :has_many 是用于声明基本嵌套资源的简写选项。二者的区别在于, :has_one 映射单例资源,而 :has_many 映射复数资源。例如:

map.resources :books, :has_one => :author, :has_many => [:reviews, :categories]

这相当于以下更明确的嵌套路由声明:

map.resources :books do |book|
  book.resource :author
  book.resources :reviews
  book.resources :categories
end

这种更明确的表示法允许创建嵌套层次很深的资源,但应避免过度嵌套,因为这会导致URL过长,辅助方法难以记忆和输入。Rails社区的共识是,如第6章中评论资源所示的一级嵌套路由是一个可接受的折衷方案。

技术上,还可在块之前向 resources 传递 :shallow => true 选项,以表明在通过资源的 id 访问单个资源时,块内声明的路由/辅助方法无需前缀资源名称(或指定的 :name_prefix :path_prefix )。

若想了解更多关于这些选项的信息,可查看在线文档,并阅读官方指南 “Rails Routing from the Outside In”

4. 生成Rails指南

Rails指南可在线获取,也可在Rails项目中运行 rake doc:guides 来生成所有官方指南。该任务将指南放置在 doc\guides 文件夹中。在浏览器中打开 index.html ,即可从显示的指南中选择感兴趣的内容。目前的指南包括 “Getting Started with Rails”、“Rails Database Migrations”、“Active Record Associations” 等,未来可能会发布更多新指南。阅读这些指南有助于巩固、整合和扩展所学的概念。

5. 其他选项

若前面提到的选项仍无法满足需求,还有一些其他选项可供使用:
- :name_prefix :path_prefix :分别用于为生成的路由添加字符串前缀(如 “book_”)和包含变量的前缀(格式与传递给 connect 的模式相同,如 “/publisher/:publisher_id”)。
- :singular resource 方法不可用)和 :plural :用于指定资源名称的正确单数和复数形式。
- :requirements 和任意命名的参数(之前用通用名称 :<parameter_name> 表示):这些选项在 connect 方法中也有讨论。

6. 命名空间资源

Rails支持所谓的命名空间资源,即资源的URL始终以给定字符串为前缀。 ActionController 定义了 namespace 方法,可自动为生成的路由添加前缀。例如:

map.namespace(:admin) do |admin|
  admin.resources :books
end

这会带来以下几个影响:
- 每个与书籍相关的路由现在都期望传入的URL以 admin 为前缀。例如,要访问书籍列表,需要发送 GET /admin/books 请求。
- 控制器现在应位于 app\controllers\admin 文件夹中,并且名称应以 Admin:: 为前缀。在这种情况下,控制器名称应改为 Admin::BooksController
- 若通过脚手架生成 BooksController ,会发现应用无法正常工作。这是因为应用中用于访问书籍相关路由的所有辅助方法现在都将以 admin 为前缀,例如 admin_books_url

尽管需要进行一些调整,但将几个控制器分组到一个公共命名空间中通常是个不错的主意。最常见的场景是将属于管理部分的一系列控制器分组。虽然通过精心组合 :name_prefix :path_prefix 也可实现相同的结果,但如果命名空间路由适用,就没有必要这样做。

7. 辅助方法与RESTful路由

RESTful路由不仅能简洁地生成路由,在使用辅助方法时也具有优势。以下是从博客应用中选取的几个方法调用示例:

redirect_to(@article)
redirect_to([@article, @comment])
redirect_to(article_comments_url(@article))
<%= link_to ‘Edit’, edit_article_path(article) %>
<%= link_to ‘Show’, [@article, @comment] %>

这些方法只需传入对象,就能理解需要生成的URL。这得益于Rails的“约定优于配置”原则。辅助方法很“智能”,知道传入对象(如 @article )意味着要显示该资源,因此会使用相应的控制器名称和对象的 id 来生成URL(例如, GET /articles/12 请求)。

同样,辅助方法也能识别嵌套路由。例如, [@article, @comment] 会自动映射到类似 /articles/12/comments/3 的路径。这个数组本质上是在告诉传递给它的方法(如 redirect_to link_to )要显示该评论(如 id 为3),并提醒注意它嵌套在文章资源(如 id 为12)中。可以将这种表示法视为一些冗长的 _url _path 辅助方法的简写形式。

8. 控制器的使用

路由只是整个过程的一部分,另一部分是控制器中定义的实际代码。如果你熟悉ASP.NET,这在概念上类似于代码后置模型,是每个Rails应用的重要组成部分。最终目标是实现关注点分离,在控制器中放置足够的逻辑来协调应用,而繁重的工作由模型层完成,展示则委托给视图。

8.1 生成控制器

在之前的示例中,控制器通常是通过运行脚手架生成器间接创建的。实际上,控制器存储在文本文件中,你可以在正确的目录中创建文件并手动编写代码。但更方便实用的方法是将 controller 参数传递给 generate 脚本。例如:

C:\projects\> rails chapter8
C:\projects\> cd chapter8
C:\projects\chapter8> ruby script/generate controller Account
exists  app/controllers/
exists  app/helpers/
create  app/views/account
exists  test/functional/
create  app/controllers/account_controller.rb
create  test/functional/account_controller_test.rb
create  app/helpers/account_helper.rb

这将生成控制器文件(如 account_controller.rb )、用于定义特定于该控制器的辅助方法的辅助文件(如 account_helper.rb )以及功能测试用例(如 account_controller_test.rb )。可使用 app\helpers\application_helper.rb 来定义可被应用中每个控制器重用的辅助方法。

生成的控制器代码如下:

class AccountController < ApplicationController
end

需要注意的是,这样定义的控制器默认不是RESTful的。若要使其成为RESTful控制器,需在 routes.rb 中使用 map.resources 方法,并添加相应的七个默认动作。因此,当需要创建RESTful控制器时,通常使用脚手架生成器更为方便。

控制器生成器还接受动作/视图列表。例如:

C:\projects\chapter8> ruby script/generate controller BankAccount deposit withdraw
exists  app/controllers/
exists  app/helpers/
create  app/views/bank_account
create  test/functional/
create  app/controllers/bank_account_controller.rb
create  test/functional/bank_account_controller_test.rb
create  app/helpers/bank_account_helper.rb
create  app/views/bank_account/deposit.html.erb
create  app/views/bank_account/withdraw.html.erb

这将生成常规的控制器文件,并为给定参数中指定的视图生成默认的XHTML代码。生成的控制器将包含相应的动作:

class BankAccountController < ApplicationController
  def deposit
  end
  def withdraw
  end
end

若要销毁现有的控制器及其相关文件,可使用 ruby script/destroy controller ControllerName 命令。可以使用驼峰式(如类名)或蛇形命名法(如文件名)的字符串来指定要生成或销毁的控制器名称。

8.2 动作处理

路由会指示Rails实例化哪个控制器类,并调用哪个方法名(即动作)。但如果方法名不存在,会发生什么呢?为了理解其工作原理,需要了解Rails用于动作处理的算法。

假设传入的请求需要执行 deposit 动作,Rails将按以下步骤处理:
1. 在控制器中搜索公共方法 deposit 。若找到该方法,则执行它。
2. 若未找到该方法,Rails会在控制器中查找 method_missing 方法。若存在该方法,则执行它。在 method_missing 方法中,可以通过参数访问动作名称。
3. 若 method_missing 方法也不存在,Rails会搜索相应的模板。例如,若控制器为 AccountController ,通过Web浏览器请求的动作是 deposit ,则会在 app\views\account 中搜索 deposit.html.erb 模板。
4. 最后,若以上都未找到,将抛出 “Unknown action” 异常。

这四个步骤对开发者有一些影响。通常,第一步是期望的结果,因此确保动作定义为公共方法(Ruby的默认设置)很重要。若将动作定义为受保护或私有方法,这些方法在控制器内部可用,但最终用户无法将其作为动作访问。

若需要隐藏一个必须为公共的方法,可使用 hide_action 方法。不过,这种情况通常很少需要,并且往往表明代码可能需要重新设计。

综上所述,Rails的路由和控制器系统提供了强大而灵活的功能,通过合理运用各种路由选项和控制器生成方法,能高效地构建出结构清晰、易于维护的Web应用。

Rails路由与控制器全解析

9. 路由与控制器的交互流程总结

为了更清晰地理解Rails中路由与控制器的交互过程,我们可以用一个流程图来展示。

graph LR
    A[请求进入] --> B{路由匹配}
    B -->|匹配成功| C[确定控制器与动作]
    C --> D{动作方法存在?}
    D -->|存在| E[执行动作方法]
    D -->|不存在| F{method_missing存在?}
    F -->|存在| G[执行method_missing]
    F -->|不存在| H{模板存在?}
    H -->|存在| I[渲染模板]
    H -->|不存在| J[抛出“Unknown action”异常]
    B -->|匹配失败| K[处理路由未匹配情况]

这个流程图展示了从请求进入到最终处理结果的完整过程。首先,请求会经过路由匹配,如果匹配成功,会确定对应的控制器和动作。然后检查动作方法是否存在,若不存在则依次检查 method_missing 方法和对应模板是否存在,若都不存在则抛出异常。若路由匹配失败,则会有相应的处理机制。

10. RESTful路由的优势与应用场景分析

RESTful路由在Rails应用中有诸多优势,下面我们通过表格来详细分析其优势及对应的应用场景。
| 优势 | 说明 | 应用场景 |
| — | — | — |
| 简洁性 | 只需一行代码 map.resources 就能生成多个路由,减少了路由定义的代码量。 | 开发大型应用时,有大量资源需要定义路由,使用RESTful路由能提高开发效率。 |
| 语义化 | HTTP动词和URL的组合能清晰表达操作意图,如 GET 用于获取资源, POST 用于创建资源等。 | 构建API时,语义化的路由能让API更易于理解和使用。 |
| 安全性 | 删除资源需要显式发送 DELETE 请求,防止意外操作。 | 涉及敏感数据操作,如删除用户信息、删除重要文件等场景。 |
| 可维护性 | 路由结构清晰,便于后续的维护和扩展。 | 项目长期迭代开发,需要不断添加或修改路由时,RESTful路由更易于管理。 |

11. 实际项目中使用Rails路由和控制器的最佳实践

在实际项目中,为了更好地使用Rails的路由和控制器,我们可以遵循以下最佳实践:

11.1 路由设计
  • 合理使用命名路由 :使用有意义的命名路由,提高代码的可读性和可维护性。例如:
map.catalog “library/“, :controller => “library”, :action => “list”
  • 优先使用RESTful路由 :在可能的情况下,尽量使用 map.resources 来定义路由,遵循RESTful原则。
  • 控制路由嵌套深度 :避免过度嵌套路由,建议只使用一级嵌套路由,以保持URL的简洁性和可读性。
11.2 控制器设计
  • 遵循单一职责原则 :每个控制器应该只负责一个特定的业务逻辑,避免控制器过于臃肿。
  • 使用过滤器 :利用Rails的过滤器(如 before_action after_action 等)来处理一些公共的逻辑,如身份验证、日志记录等。例如:
class ApplicationController < ActionController::Base
  before_action :authenticate_user!
end
  • 合理组织动作方法 :将相关的动作方法放在一起,便于代码的查找和维护。
11.3 错误处理
  • 统一错误处理 :在 ApplicationController 中定义统一的错误处理机制,捕获并处理各种异常,提供友好的错误信息给用户。例如:
class ApplicationController < ActionController::Base
  rescue_from StandardError, with: :handle_error

  private

  def handle_error(exception)
    render json: { error: exception.message }, status: :internal_server_error
  end
end
12. 未来Rails路由和控制器的发展趋势展望

随着Web开发技术的不断发展,Rails的路由和控制器也可能会有一些新的发展趋势。

  • 更智能的路由匹配 :未来可能会引入更智能的路由匹配算法,能够根据请求的上下文和用户的行为自动调整路由匹配规则,提高路由匹配的准确性和效率。
  • 与微服务架构的集成 :随着微服务架构的流行,Rails可能会提供更好的支持,使路由和控制器能够更方便地与微服务进行交互,实现分布式应用的开发。
  • 增强的安全性 :在网络安全日益重要的今天,Rails可能会进一步加强路由和控制器的安全性,提供更多的安全机制和防护措施,如防止DDoS攻击、SQL注入等。
  • 更好的性能优化 :不断优化路由和控制器的性能,减少响应时间,提高应用的吞吐量,以满足高并发场景下的需求。

总之,Rails的路由和控制器系统是一个强大而灵活的工具,通过深入理解和合理运用,我们能够构建出高质量、高性能的Web应用。同时,我们也需要关注其未来的发展趋势,以便在项目中及时采用新的技术和方法,提升开发效率和应用质量。

"Mstar Bin Tool"是一款专门针对Mstar系列芯片开发的固件处理软件,主要用于智能电视及相关电子设备的系统维护深度定制。该工具包特别标注了"LETV USB SCRIPT"模块,表明其对乐视品牌设备具有兼容性,能够通过USB通信协议执行固件读写操作。作为一款专业的固件编辑器,它允许技术人员对Mstar芯片的底层二进制文件进行解析、修改重构,从而实现系统功能的调整、性能优化或故障修复。 工具包中的核心组件包括固件编译环境、设备通信脚本、操作界面及技术文档等。其中"letv_usb_script"是一套针对乐视设备的自动化操作程序,可指导用户完成固件烧录过程。而"mstar_bin"模块则专门处理芯片的二进制数据文件,支持固件版本的升级、降级或个性化定制。工具采用7-Zip压缩格式封装,用户需先使用解压软件提取文件内容。 操作前需确认目标设备采用Mstar芯片架构并具备完好的USB接口。建议预先备份设备原始固件作为恢复保障。通过编辑器修改固件参数时,可调整系统配置、增删功能模块或修复已知缺陷。执行刷机操作时需严格遵循脚本指示的步骤顺序,保持设备供电稳定,避免中断导致硬件损坏。该工具适用于具备嵌入式系统知识的开发人员或高级用户,在进行设备定制化开发、系统调试或维护修复时使用。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值