使用JavaScript为依赖项创建代码选择RESTful

Ruby 2.0.0,Rails 4.0.3,Windows 8.1 Update,PostgreSQL 9.3.3

我有使用JavaScript来驱动相关选择的代码。 为此,它引用一个控制器方法,该方法检索以下select的数据。 我被告知,因为该方法是非标准的,所以这不是RESTful。

我知道REST是一组有关客户端/服务器通信的特定约束。 我已经阅读了一些有关它的信息,但肯定没有深入的知识。 我对影响和解决方案感到好奇。 所以,关于我的配置和REST的问题:首先,它是否准确,它不是RESTful? 其次,这对我的申请有何影响? 第三,我应该/我可以做些什么来解决这个问题? 举一个例子:

路线是:(可能是关注?)

post 'cars/make_list', to: 'cars#make_list' 

这是第一个选择:(OBTW,我使用ERB但删除小于/%)

 = f.input(:ymm_year_id, {input_html: {form: 'edit_car', car: @car, value: @car.year}, collection: YmmYear.all.order("year desc").collect { |c| [c.year, c.id] }, prompt: "Year?"}) 

这是依赖选择:

 = render partial: "makes", locals: {form: 'edit_car', car: @car} 

这是部分:

 = simple_form_for car, defaults: {label: false}, remote: true do |f| makes ||= "" make = "" make = car.make_id if car.class == Car and Car.exists?(car.id) if !makes.blank? = f.input :ymm_make_id, {input_html: {form: form, car: car, value: make}, collection: makes.collect { |s| [s.make, s.id] }, prompt: "Make?"} else = f.input :ymm_make_id, {input_html: {form: form, car: car, value: make}, collection: [], prompt: "Make?"} end end 

JS:

 $(document).ready(function () { ... // when the #year field changes $("#car_ymm_year_id").change(function () { var year = $('select#car_ymm_year_id :selected').val(); var form = $('select#car_ymm_year_id').attr("form"); var car = $('select#car_ymm_year_id').attr("car"); $.post('/cars/make_list/', { form: form, year: year, car: car }, function (data) { $("#car_ymm_make_id").html(data); }); return false; }); ... }); 

方法:

  def make_list makes = params[:year].blank? ? "" : YmmMake.where(ymm_year_id: params[:year]).order(:make) render partial: "makes", locals: {car: params[:car], form: params[:form], makes: makes} end 

如果我必须描述,是否RESTful意味着:

  1. 您提供有意义的资源名称
  2. 您使用HTTP动词来表达您的意图
  3. 您正确使用HTTP代码来指示状态

提供有意义的资源名称

正如您之前可能听到的那样,REST中的所有内容都与资源有关。 但是从外面看,它只是你暴露的路径。 您的资源只是一堆路径,例如:

 GET /burgers # a collection of burgers GET /burger/123 # a burger identified with id 123 GET /burger/123/nutrition_facts # the nutrition facts of burger 123 POST /burgers # with data: {name: "humble jack", ingredients: [...]} to create a new burger PUT /burger/123 # with data: {name: "chicken king"} to change the name of burger 123 

例如,如果你有一个带url的路径

 GET /burger_list?id=123 

这不是一种好的做法。

这意味着您需要仔细考虑为资源提供的名称,以确保意图明确。

使用HTTP动词表达您的意图

它基本上意味着使用:

  • GET读取由标识符(id)或资源集合标识的资源
  • PUT更新您通过标识符(id)标识的特定资源
  • DELETE以销毁您通过ID标识的特定资源
  • POST以创建新资源

通常,在Rails中,按照惯例,这些动词用于映射控制器中的特定操作。

  • GET去展示或索引
  • PUT去更新
  • DELETE去摧毁
  • POST去创建

这就是为什么人们通常会说如果你的控制器中的动作不遵循这种模式,你就不会“RESTful”。 但最后,只有您公开的路线才算数。 不是你的控制器动作。 当然,这是一种约定,并且约定对于可读性和可维护性是有用的。

您正确使用HTTP代码来指示状态

你已经知道了通常的嫌疑人:

  • 200意味着好的,一切都很顺利。
  • 404表示NOT FOUND,找不到资源
  • 401表示UNAUTHORIZED,身份validation失败,身份validation令牌无效
  • 500表示INTERNAL SERVER ERROR,换句话说:kaput

但是您可以在回复中使用更多内容:

  • 201表示CREATED,表示资源已成功创建
  • 403表示FORBIDDEN,您没有访问该资源的权限

你得到的图片,它真的是用正确的HTTP代码回复,清楚地表明发生了什么。

回答你的问题

它是否准确,它不是RESTful?

从我看到的,第一个问题是你的道路。

 post 'cars/make_list', to: 'cars#make_list' 

我的理解是你正在检索汽车品牌的集合。 使用POST来检索集合是违反REST规则的,您应该使用GET代替。 这应该回答你的第一个问题。

这对我的申请有何影响?

那么,在你的情况下不安宁的影响不是很大。 它主要是关于可读性,清晰度和可维护性。 将问题分开并将它们放在正确的位置等……它不会影响性能,也不会成为危险的问题。 您当然不是RESTful,这使得理解您的应用程序变得更加复杂。

我该怎么做才能解决这个问题?

除了路由问题,另一个问题是您的操作名为make_list,并且不遵循Rails REST约定。 Rails有一个关键字来创建RESTful路由:

 resources :car_makes, only: [:index] # GET /car_makes , get the list of car makes 

此路线比前一路线更好地表达您的意图,现在是GET请求。 然后,您可以使用查询参数来过滤结果。 但这意味着我们需要创建一个新的控制器来处理它。

 class CarMakesController < ApplicationController def index makes = params[:year].blank? ? "" : YmmMake.where(ymm_year_id: params[:year]).order(:make) render partial: "makes", locals: {car: params[:car], form: params[:form], makes: makes} end private # Strong parameters stuff... end 

当然,我们还需要更改您的jquery以发出GET请求而不是POST。

 $(document).ready(function () { ... // when the #year field changes $("#car_ymm_year_id").change(function () { // ... $.get({ url: '/car_makes', data: { form: form, year: year, car: car }, success: function (data) { $("#car_ymm_make_id").html(data); }); return false; }); ... }); 

这是一个更好的解决方案,它不需要太多工作。

如果您想了解更多有关细节的信息,可以参考REST API REST教程的优秀教程。 我不太了解细节,主要是日常用处。

希望这可以帮助。