使用JavaScript进行代码依赖选择RESTful

时间:2021-11-05 19:33:47

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

Ruby 2.0.0, Rails 4.0.3, Windows 8.1更新,PostgreSQL 9.3.3

I have code that uses JavaScript to power dependent selects. To do so, it references a controller method that retrieves the data for the following select. I'm told that, because that method is non-standard, this is not RESTful.

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

I understand that REST is a set of specific constraints regarding client/server communications. I've read some information about it but certainly don't have in-depth knowledge. I am curious about the impact and resolution. So, regarding the question about my configuration and REST: First, would that be accurate that it is not RESTful? Second, how does that impact my application? Third, what should/could I do to resolve that? Providing one example:

我理解REST是关于客户端/服务器通信的一组特定约束。我读过一些关于它的信息,但肯定没有深入的知识。我对影响和决心感到好奇。因此,关于我的配置和REST的问题:首先,它不是RESTful,这是否准确?第二,这对我的应用程序有什么影响?第三,我该如何解决这个问题?提供一个例子:

The route is: (probably the concern?)

路线是:(可能是担心?)

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

This is the first select: (OBTW, I use ERB but removed less than/percent)

这是第一个选择:(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?"}) 

This is the dependent select:

这是依赖选择:

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

This is the partial:

这是部分:

= 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:

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;
    });
    ...
});

And the method:

和方法:

  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

1 个解决方案

#1


5  

If I had to describe if, being RESTful means that:

如果我必须描述如果,休息意味着:

  1. You provide meaningful resources names
  2. 您提供了有意义的资源名称
  3. You use the HTTP verbs to express your intents
  4. 您使用HTTP谓词来表达您的意图
  5. You make proper use of HTTP codes to indicate status
  6. 适当地使用HTTP代码来表示状态

Provide meaningful resource names

提供有意义的资源名

As you probably heard it before, everything in REST is about resources. But from the outside, it's just the paths you expose. Your resources are then just a bunch of paths such as:

正如您之前可能听到的,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

For instance, if you had a path with the url

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

GET /burger_list?id=123

That would not be considered good practice.

这不会被认为是好的做法。

It means you need to think hard about the names you give your resources to make sure the intent is explicit.

这意味着你需要认真考虑你给你的资源的名称,以确保意图是明确的。

Use HTTP verbs to express your intents

使用HTTP动词来表达你的意图

It basically means using:

这基本上意味着使用:

  • GET to read a resource identified by an identifier (id) or a collection of resources
  • 获取通过标识符(id)或资源集合标识的资源
  • PUT to update a specific resource that you identify by an identifier (id)
  • 使用标识符(id)来更新指定的资源
  • DELETE to destroy a specific resource that you identify by an id
  • 删除以销毁您通过id标识的特定资源
  • POST to create a new resource
  • 发布以创建新的资源

Usually, in Rails, those verbs are, by convention, used to map specific actions in your controller.

通常,在Rails中,根据约定,这些谓词用于映射控制器中的特定操作。

  • GET goes to show or index
  • GET用于显示或索引
  • PUT goes to update
  • 将会更新
  • DELETE goes to destroy
  • 删除去摧毁
  • POST goes to create
  • 后去创建

That's why people usually say that if you have actions in your controllers that don't follow that pattern, you're not "RESTful". But in the end, only the routes you expose count. Not really your controller actions. It is a convention of course, and conventions are useful for readability and maintainability.

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

You make proper use of HTTP codes to indicate status

适当地使用HTTP代码来表示状态

You already know the usual suspects:

你已经知道常见的疑点:

  • 200 means OK, everything went fine.
  • 200意味着一切顺利。
  • 404 means NOT FOUND, could not find resource
  • 404表示找不到,找不到资源
  • 401 means UNAUTHORIZED, authentication failed, auth token invalid
  • 401表示未授权、身份验证失败、身份令牌无效
  • 500 means INTERNAL SERVER ERROR, in other words: kaput
  • 500表示内部服务器错误,换句话说:kaput

But there are more that you could be using in your responses:

但在你的回答中,你还可以用到更多:

  • 201 means CREATED, it means the resource was successfully created
  • 201表示已创建,表示已成功创建资源
  • 403 means FORBIDDEN, you don't have the privileges to access that resource
  • 403表示禁止,您没有权限访问该资源
  • ...

You get the picture, it's really about replying with the right HTTP code that represents clearly what happens.

您得到的是,它实际上是关于使用正确的HTTP代码来响应,它清楚地表示发生了什么。

Answering your questions

回答你的问题

would that be accurate that it is not RESTful?

这是不是说它不休息呢?

From what I see, the first issue is your path.

在我看来,第一个问题是你的道路。

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

What I understand is that you are retrieving a collection of car makes. Using a POST to retrieve a collection is against REST rules, you should be using a GET instead. That should answer your first question.

据我所知,你正在回收一批汽车产品。使用POST检索集合是违反REST规则的,您应该使用GET。这应该能回答你的第一个问题。

how does that impact my application?

这对我的应用程序有什么影响?

Well, the impact of not being restful in your case is not very big. It's mainly about readability, clarity and maintainability. Separating concerns and putting them in the right place etc... It's not impacting performance, nor is it a dangerous issue. You're just not RESTful and that makes it more complicated to understand your app, in your case of course.

在你的情况下,不休息的影响不是很大。它主要是关于可读性、清晰度和可维护性。把关注点分开,把它们放在正确的地方……它不会影响性能,也不是一个危险的问题。你只是没有RESTful,这就使得理解你的应用变得更加复杂,当然,在你的应用中。

what should/could I do to resolve that?

我该怎么解决这个问题呢?

Besides the route problem, the other issue is that your action is called make_list and that doesn't follow Rails REST conventions. Rails has a keyword to create RESTful routes:

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

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

This route expresses your intent much better than the previous one and is now a GET request. You can then use query parameters to filter the results. But it means we need to create a new controller to deal with it.

这条路径比前一条更好地表达了您的意图,现在是一个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

And of course we also need to change your jquery to make a GET request instead of a POST.

当然,我们还需要更改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;
  });
  ...
});

This is a much better solution, and it doesn't require too much work.

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

There is an excellent tutorial on REST on REST API tutorial, if you want to know more about the specifics. I don't know much about the small details, mostly what is useful on a day to day basis.

如果您想了解更多关于REST API教程的细节,这里有一个关于REST的优秀教程。我不太了解这些小细节,主要是日常生活中有用的东西。

Hope this helps.

希望这个有帮助。

#1


5  

If I had to describe if, being RESTful means that:

如果我必须描述如果,休息意味着:

  1. You provide meaningful resources names
  2. 您提供了有意义的资源名称
  3. You use the HTTP verbs to express your intents
  4. 您使用HTTP谓词来表达您的意图
  5. You make proper use of HTTP codes to indicate status
  6. 适当地使用HTTP代码来表示状态

Provide meaningful resource names

提供有意义的资源名

As you probably heard it before, everything in REST is about resources. But from the outside, it's just the paths you expose. Your resources are then just a bunch of paths such as:

正如您之前可能听到的,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

For instance, if you had a path with the url

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

GET /burger_list?id=123

That would not be considered good practice.

这不会被认为是好的做法。

It means you need to think hard about the names you give your resources to make sure the intent is explicit.

这意味着你需要认真考虑你给你的资源的名称,以确保意图是明确的。

Use HTTP verbs to express your intents

使用HTTP动词来表达你的意图

It basically means using:

这基本上意味着使用:

  • GET to read a resource identified by an identifier (id) or a collection of resources
  • 获取通过标识符(id)或资源集合标识的资源
  • PUT to update a specific resource that you identify by an identifier (id)
  • 使用标识符(id)来更新指定的资源
  • DELETE to destroy a specific resource that you identify by an id
  • 删除以销毁您通过id标识的特定资源
  • POST to create a new resource
  • 发布以创建新的资源

Usually, in Rails, those verbs are, by convention, used to map specific actions in your controller.

通常,在Rails中,根据约定,这些谓词用于映射控制器中的特定操作。

  • GET goes to show or index
  • GET用于显示或索引
  • PUT goes to update
  • 将会更新
  • DELETE goes to destroy
  • 删除去摧毁
  • POST goes to create
  • 后去创建

That's why people usually say that if you have actions in your controllers that don't follow that pattern, you're not "RESTful". But in the end, only the routes you expose count. Not really your controller actions. It is a convention of course, and conventions are useful for readability and maintainability.

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

You make proper use of HTTP codes to indicate status

适当地使用HTTP代码来表示状态

You already know the usual suspects:

你已经知道常见的疑点:

  • 200 means OK, everything went fine.
  • 200意味着一切顺利。
  • 404 means NOT FOUND, could not find resource
  • 404表示找不到,找不到资源
  • 401 means UNAUTHORIZED, authentication failed, auth token invalid
  • 401表示未授权、身份验证失败、身份令牌无效
  • 500 means INTERNAL SERVER ERROR, in other words: kaput
  • 500表示内部服务器错误,换句话说:kaput

But there are more that you could be using in your responses:

但在你的回答中,你还可以用到更多:

  • 201 means CREATED, it means the resource was successfully created
  • 201表示已创建,表示已成功创建资源
  • 403 means FORBIDDEN, you don't have the privileges to access that resource
  • 403表示禁止,您没有权限访问该资源
  • ...

You get the picture, it's really about replying with the right HTTP code that represents clearly what happens.

您得到的是,它实际上是关于使用正确的HTTP代码来响应,它清楚地表示发生了什么。

Answering your questions

回答你的问题

would that be accurate that it is not RESTful?

这是不是说它不休息呢?

From what I see, the first issue is your path.

在我看来,第一个问题是你的道路。

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

What I understand is that you are retrieving a collection of car makes. Using a POST to retrieve a collection is against REST rules, you should be using a GET instead. That should answer your first question.

据我所知,你正在回收一批汽车产品。使用POST检索集合是违反REST规则的,您应该使用GET。这应该能回答你的第一个问题。

how does that impact my application?

这对我的应用程序有什么影响?

Well, the impact of not being restful in your case is not very big. It's mainly about readability, clarity and maintainability. Separating concerns and putting them in the right place etc... It's not impacting performance, nor is it a dangerous issue. You're just not RESTful and that makes it more complicated to understand your app, in your case of course.

在你的情况下,不休息的影响不是很大。它主要是关于可读性、清晰度和可维护性。把关注点分开,把它们放在正确的地方……它不会影响性能,也不是一个危险的问题。你只是没有RESTful,这就使得理解你的应用变得更加复杂,当然,在你的应用中。

what should/could I do to resolve that?

我该怎么解决这个问题呢?

Besides the route problem, the other issue is that your action is called make_list and that doesn't follow Rails REST conventions. Rails has a keyword to create RESTful routes:

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

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

This route expresses your intent much better than the previous one and is now a GET request. You can then use query parameters to filter the results. But it means we need to create a new controller to deal with it.

这条路径比前一条更好地表达了您的意图,现在是一个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

And of course we also need to change your jquery to make a GET request instead of a POST.

当然,我们还需要更改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;
  });
  ...
});

This is a much better solution, and it doesn't require too much work.

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

There is an excellent tutorial on REST on REST API tutorial, if you want to know more about the specifics. I don't know much about the small details, mostly what is useful on a day to day basis.

如果您想了解更多关于REST API教程的细节,这里有一个关于REST的优秀教程。我不太了解这些小细节,主要是日常生活中有用的东西。

Hope this helps.

希望这个有帮助。