【问题标题】:Rails: Routes, Controllers, Views, Oh My(exclamation)Rails:路由、控制器、视图、Oh My(感叹号)
【发布时间】:2013-04-13 11:56:32
【问题描述】:

我无法理解路由、控制器和视图之间的关联(以及它们如何相互连接)。

所以,我的控制器使用 index,show,new,create,destroy 方法。以及对应的

GET    /entries(.:format)                     entries#index
POST   /entries(.:format)                     entries#create
GET    /entries/new(.:format)                 entries#new
GET    /entries/:id/edit(.:format)            entries#edit
GET    /entries/:id(.:format)                 entries#show
PUT    /entries/:id(.:format)                 entries#update
DELETE /entries/:id(.:format)                 entries#destroy

如果我添加一个新方法vote_up 或vote_down,例如,以及具有匹配操作名称的视图,它会不起作用。

1) 添加新动作并将它们连接到视图的正确方法是什么? 2) 奖励 使这些方法与 ajax 兼容(使用 ajax 渲染部分)的正确方法是什么?如果用户没有启用 js 会怎样?

我可能会根据我得到的答案扩展/改进这个问题。

我厌倦了在谷歌上搜索诸如 自定义操作路线轨道 之类的东西来大杂烩我的应用程序。这是令人筋疲力尽和糟糕的形式,我终于达到了理解术语的水平——我是 100% 自学的……所以请尽量理解一个年轻的学徒。

【问题讨论】:

  • routes.rb 文件中的邮政编码。

标签: ruby-on-rails methods


【解决方案1】:

从一开始就是这样想的:

1) 您的应用要做的唯一一件事就是响应 HTTP 请求。

最典型的请求类型是:

  • GET - 用户在浏览器的 URL 栏中输入内容并点击回车。

  • POST - 用户提交表单。

还有其他种类的 HTTP 请求,最重要的是 PUT、PATCH 和 DELETE。 Rails 遵循 REST 模式,这意味着它为这些 HTTP 动词分配了特定的含义。

2) 当任何请求进入您的应用时,必须将其路由到控制器操作。

您的routes.rb 文件是一组用于 Rails 路由器 (ActionDispatch) 的指令,用于告诉路由器将请求发送到何处。 “标准”rails 资源作为快捷方式给出,如下所示:

resources :things

这意味着:

GET /things => things#index

GET /things/:id => things#show

GET /things/new => things#new

GET /things/edit/:id => things#edit

POST /things => things#create

PUT /things/:id => things#update

DELETE /things/:id => things#destroy

这些被认为是标准的 RESTful 操作 - 您的 resources :things 声明没有设置其他任何内容。因此,如果您希望控制器执行其他非标准操作,则必须手动添加它们。

如果要对特定记录执行操作,最好的方法是使用:

resources :things do
  member do
    get 'vote_up'
  end
end

这告诉路由器,如果有人向/things/123/vote_up 发出GET 请求,它应该触发ThingsController vote_up 操作。

Rails Guide 中详细说明了所有这些内容,您应该阅读全文。

3) 您的控制器的工作是发送对请求的响应。

通常这意味着从数据库中加载一条记录并呈现该记录的视图。

每个控制器操作都以将响应发送回传入请求而结束。此响应可以是 render 调用 - 这意味着以某种格式发回一些数据 - 或 redirect 调用 - 这基本上会为您发出新请求,因此您会收到其他请求的响应。

在 Rails 中,重定向实际上是将请求发送到不同的控制器操作。

Render 调用发送数据作为对请求的响应。

当您调用render :new 时,这是render :template => :new 的快捷方式,它加载app/views/things/new.html.erb(或其他)模板,将来自控制器(通常是您的实例变量)的数据发送给它,并使用模板对其进行评估语言(erb、haml 等)这会产生一大串 HTML,然后控制器将其传递给浏览器。

想亲自看看这是什么?尝试使用render :text => 'Hello World' 结束控制器,甚至:

render :inline => '<!DOCTYPE html><head><title>Inline Wow!</title></head><body>Mind blown.</body></html>'

看看会发生什么。

在响应(呈现)时,您可以发送“普通”HTML 模板,其中包含整个页面的信息(头部、正文等),或者 Ajax 使用的部分信息。您还可以发送原始数据,例如 JSON 或 XML。它实际上只是文本,并且根据该文本的内容(以及随之而来的 HTTP 标头),浏览器、脚本或客户端应用程序会相应地处理它。

再次,请参阅Rails Guide。

4) 当浏览器发出请求时,您可能想要发回 HTML。如果请求是由 Ajax 发出的,您可能想要发回 JSON。

对于像vote_up 这样的自定义操作,您可能根本不想显示模板,而只是重定向。所以,你可能会有这样的事情:

ThingsController < ApplicationController

  def vote_up
    @thing = Thing.find(params[:id])
    @thing.vote_up
    redirect_to @thing
  end

end

现在,路由器的好处之一是它会为您提供 URL 助手。如果您已经创建了如前所示的路由和操作,那么在您的“显示内容”页面上,您可能会有这样的 URL:

link_to 'Vote up this thing!', vote_up_thing_path(@thing)

这将创建一个指向things/123/vote_up 的链接,如果有人点击它,它将在ThingsController 上运行vote_up 操作中的代码,然后重定向回显示事物视图。

5) 您的模板使用链接和表单向控制器发送消息。链接发出 GET 请求,表单发出 POST 请求。

如果您想开始处理 AJAX 请求,那很好。在这种情况下,您只需要在 Javascript 中发出请求并处理响应。因此,例如,您可以在模板中添加如下内容:

= link_to 'Vote up this thing', vote_up_thing_path(@thing), :id => 'vote-up-button'

然后在 Javascript(使用 jQuery)中你可以有这样的函数:

$(function(){
  $('a#vote-up-button').click( function(event){
    event.preventDefault();
    $.ajax({
      url: this.attr('href'),
      type: 'GET',
      success: function(){...},
      error: function(){...}
    });
  });
});

在这种情况下,jQuery Ajax 方法只是发出一个 get 请求,然后根据它得到的响应运行一个回调函数。

6) 你的控制器/路由的结构不会影响你可以发出什么样的请求,只有什么动作会响应什么 URL 上的什么 HTTP 方法。

您在控制器操作中所做的操作决定了您是否准备好响应 javascript 或 html 请求等。

虽然 rails 确实能够在单个控制器操作中处理多种请求格式,但使用 respond_to 块,出于实用性的考虑,我发现当您选择让路由仅响应一种格式或另一个。

IE:我会让你的正常页面加载请求(索引、显示、新建、编辑)只是 HTML 请求,然后我会让你想要添加的任何其他 AJAX 操作仅是 Javascript —— 即。他们用 JSON 而不是 HTML 来响应。当然,您不必这样做,但如果这样做,您的生活会更轻松。

我希望这能让您更清楚地了解您的应用中发生了什么。欢迎使用 Rails,您正在加入一个很棒的社区!

【讨论】:

    【解决方案2】:

    欢迎来到 ROR 世界。 :)

    路由、控制器和视图协同工作以将 HTTP 请求转换为某种类型的响应(无论是 HTML、JSON 还是 XML)。每种方法都针对不同的问题。

    从头开始,views 是 rails 世界中的模板,它们通常是 ERB。 ERB 只是一种模板系统,也可以使用其他模板系统,例如haml。他们的工作是获取控制器提供给他们的一些数据并生成格式化输出,通常是 HTML、JSON 或 XML。

    但是您如何知道要为特定请求呈现哪个视图?您如何将数据放入您的视图中,以便它可以完成您需要的所有花哨的动态内容?这就是控制器的用武之地。Controllers 是 ruby​​ 类,其任务是检查 已解析 HTTP 请求和任何相关参数,从数据库(或任何地方)获取数据,然后将该数据传递给一个看法。控制器通常有几种不同的方法,每种方法对应不同的任务(例如创建、显示、更新等)。

    最后,Routes 是一种 DSL,用于解析 HTTP 请求并将解析的 HTTP 请求分派给特定的控制器方法。它们是 Rails 用来将 URL 路由到方法的粘合剂,因此得名 routes。

    关于您的具体问题:

    1) 要创建一个新动作,您必须添加一个路由、一个控制器方法和一个视图。因此,例如,如果您想计算您的条目数,您可以添加如下路线:

    get '/entries/count' => "entries#count"
    

    这告诉 ROR 在收到 URL 时调用 entries 控制器中的 count 方法。在这种情况下,您的控制器方法很简单,例如:

    def count
       @cnt = Entries.count
    end
    

    最后,您将在 app/views/entries/count.html.erb 中创建一个类似以下内容的视图:

    <p>Count: <%= @cnt %></p>
    

    2) Ajax 兼容代码实际上只是一种询问“如果此请求的请求格式是 JSON 怎么办?”。为此,您需要使用respond_to 方法。在某种程度上,respond_to 是一种指定不同视图 来处理请求格式的正式方式。要继续上面的示例,您可以这样做:

    def count
      @cnt = Entries.count
      respond_to do |fmt|
        fmt.html # This just renders the default template
        fmt.json { render json: { count: @cnt } }
      end
    end
    

    注意- 以上所有代码都是徒手的。 :)

    【讨论】:

    • 感谢您的优质回答!这一切的魔法是如何发生的?这就是从外面很难理解的东西……有点神奇,不是吗? :)
    • 有点神奇,是的。但是任何足够先进的技术也是如此! :) 如果您真的想回答 那个 问题,您可能需要阅读 ROR 源代码,或者至少浏览一下API docs。从开发人员的角度来看,Rails 提供了这些服务,只要您遵循 API,您就无需担心如何使用。但是如果你想学习,Rails 源码才是权威。
    【解决方案3】:

    如果你有 RESTful 控制器:

    resources :entries do
      collection do
        get :vote_down
        get :vote_up
      end
    end
    

    这将生成 2 个额外的路线:

    GET    /entries/:id/vote_up(.:format)                 entries#vote_up
    GET    /entries/:id/vote_down(.:format)               entries#vote_down
    

    您可以轻松地将 HTTP 方法更改为 GET、POST、PUT 和 DELETE。

    另外,请查看路线文档中的“Adding More RESTful Actions”。

    【讨论】:

    • 这些可能应该是 POST 请求。
    • @ole,请阅读上面的整个问题。我正在寻找一个完整、详细的答案。我非常感谢您的反馈,但我正在寻找如何将其与控制器/视图及其交互方式联系起来。
    猜你喜欢
    • 1970-01-01
    • 2012-12-14
    • 2012-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-06
    相关资源
    最近更新 更多