Rails 5 jQuery .ajax方法数据格式

问题描述:

升级到Rails 5后,我遇到了我的jQuery .ajax请求问题。我相信这与(有些)新的强大参数有关。我收到以下错误:Rails 5 jQuery .ajax方法数据格式

ArgumentError (When assigning attributes, you must pass a hash as an argument.): 

我在想,我错误地在我的阿贾克斯请求(使用的CoffeeScript)的设置我的数据包。

或者可能是我的可信参数无法正常工作。

使用byebug,它似乎我的控制器的第一行没问题,但它在第二行失败:@prospect.update(prospect_params[:status])。这里是byebug的@_params变量:

1: @_params = <ActionController::Parameters {"prospect"=><ActionController::Parameters {"id"=>"16", "status"=>"inactive"} permitted: false>, "controller"=>"prospects", "action"=>"update_status"} permitted: false> 

下面是我的控制器的片段,并Coffescript

控制器

# PUT /prospects/update_status 
    def update_status 
    @prospect = Prospect.find(params[:id]) 
    @prospect.update(prospect_params[:status]) 

    respond_to do |format| 
     if @prospect.update_attributes(prospect_params) 
     format.json { head :no_content } 
     else 
     format.json { render json: @prospect.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

...

private 
    # Use callbacks to share common setup or constraints between actions. 
    def set_prospect 
    @prospect = Prospect.find(params[:id]) 
    end 

    # Only allow a trusted parameter "white list" through. 
    def prospect_params 
    params.require(:prospect).permit(:name, :status, :priority, :id) 
    end 

Coffeescript

# Update prospects active list when a toggle switch is clicked 
    $("#prospects_list").on "change", ".js-switch", -> 
     prospect_id = $(this).parent('form').find('input[name="prospect[id]"]').val() 
     if @checked 
      status = 'active' 
     else 
      prospect_status = 'inactive' 
     # Get parent TR 
     tr = $(this).closest('tr') 
     # Update prospect using Ajax 
     $.ajax 
      url: '/prospects/update_status' 
      type: 'POST' 
      data: { prospect: {id: prospect_id, status: prospect_status } } 
      dataType: 'json' 
      success: (data) -> 
       return 
      false 
+0

你想params哈希表是什么样子? – the12

感谢Зелёный和max让我走向正确的方向。这是我用过的工作。我只需要一个小的变化到控制器

控制器

# PUT /prospects/update_status 
def update_status 
    @prospect = Prospect.find(prospect_params[:id]) 
    respond_to do |format| 
    if @prospect.update(status: prospect_params[:status]) 
     format.json { head :no_content } 
    else 
     format.json { render json: @prospect.errors, status: :unprocessable_entity } 
    end 
    end 
end 

您传递参数的值。

查看错误信息you must pass a hash as an argument.

@prospect.update(prospect_params[:status]) 
# here is you pass a value of status key, that's not a hash 
# {"id"=>"16", "status"=>"inactive"} 
# prospect_params[:status] => "inactive" 

使用刚:

@prospect.update(prospect_params) 
# that's pass a hash 
# prospect_params => {"id"=>"16", "status"=>"inactive"} 

或者:

@prospect.update(status: prospect_params[:status]) 
+0

谢谢。虽然这有点令人困惑,因为我没有完全弄清楚哈希是什么,它帮助我找到了正确的语法。我会在另一个答案中发布它。 – Ryan

开始问自己,如果你真的需要一个特定的路线更新状态,或者这应该是对规范更新路由的请求:

PATCH /prospects/:id 

在这种情况下,你应该改变你的AJAX的处理程序:ID的路径,而不是:

# Update prospects active list when a toggle switch is clicked 
$("#prospects_list").on "change", ".js-switch", -> 
    prospect_id = $(this).parent('form').find('input[name="prospect[id]"]').val() 
    if @checked 
     status = 'active' 
    else 
     prospect_status = 'inactive' 
    # Get parent TR 
    tr = $(this).closest('tr') 
    # Update prospect using Ajax 
    $.ajax 
     url: '/prospects/' + prospect_id 
     type: 'PATCH' # Not POST! 
     data: { prospect: { status: prospect_status } } 
     dataType: 'json' 
     success: (data) -> 
      return 
     false 

如果出于某种原因想为这个特定的方法,你可以通过移动解决它PARAMS。

# config/routes.rb 
resources :prospects do 
    member do 
    patch :update_status 
    end 
end 

# PATCH /prospects/:id/update_status 
def update_status 
    @prospect = Prospect.find(params[:id]) 
    respond_to do |format| 
    if @prospect.update_attributes(prospect_params) 
     format.json { head :no_content } 
    else 
     format.json { render json: @prospect.errors, status: :unprocessable_entity } 
    end 
    end 
end 

# ... 

def prospect_params 
    params.require(:prospect).permit(:name, :status, :priority) 
end 

# coffeescript 
url: '/prospects/' + prospect_id +'/update_status' 

使用@prospect.update(prospect_params[:status])两次更新记录,并裙子强参数,它会引发异常。

+0

更高版本的Rails使用PATCH而不是PUT,因为语义匹配更好地更新记录。 – max

+0

感谢您的双重更新。我修正了这一点。接下来我会尝试使用PATCH,但现在我想尽可能少地进行更改,因为我必须跨越许多jquery调用来复制它。 – Ryan

+0

如果你正在复制这个,那么你做错了。定义一个简单的JavaScript函数,它接受更新(一个对象)并返回[promise对象](http://joseoncode.com/2011/09/26/a-walkthrough-jquery-deferred-and-promise/)( '返回$ .ajax(...)')。然后通过在promise对象上使用'.done'来定义回调。 – max