2

I'm failing to understand the correlation between routes, controllers, and views (and how they connect to each other).

So, I've got my controller with the index,show,new,create,destroy methods. And the corresponding

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

How come if I add a new method vote_up or vote_down, for example, and the views with matching action names, it doesn't work.

1) What is the proper way to add new actions and connect them to views? 2) Bonus What is the proper way to make these methods ajax-compatible (render a partial with ajax)? What happens if the user doesn't have js enabled?

I may expand/evolve this question based on the answers I get.

I'm tired of googling things like custom action route rails and the like to hodge-podge my apps. It's draining and poor form and I'm finally getting to the level to comprehend the lingo--I've been self taught 100%...so please try to be understanding if you can for a young padawan.

4

3 回答 3

6

从一开始就是这样想的:

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

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

所有这些都在Rails 指南中详细说明,您应该阅读整个内容。

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 指南

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 助手。如果您已经创建了如前所示的路由和操作,那么在您的“show thing”页面上,您可能会有这样的 URL:

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

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

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,您正在加入一个很棒的社区!

于 2013-04-20T02:49:09.710 回答
2

欢迎来到 ROR 世界。:)

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

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

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

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

关于您的具体问题:

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

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

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

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

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

于 2013-04-20T02:06:58.260 回答
0

如果你有 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。

此外,请检查路线文档中的“添加更多 RESTful 操作”。

于 2013-04-20T02:02:45.027 回答