NoMethodError: undefined method `sort` from Twilio voice example

NoMethodError: undefined method `sort` from Twilio voice example

我正在尝试建立一个调用人员的示例 Twilio Rails 项目。我正在学习与 this repo 相关的教程,并且基本上拥有代码库的副本。我收到一个错误,我认为是来自这一行 @validator = Twilio::Util::RequestValidator.new(@@twilio_token)

这是我的 twilio_controller.rb

class TwilioController < ApplicationController
  # Before we allow the incoming request to connect, verify
  # that it is a Twilio request
  skip_before_action :verify_authenticity_token
  before_action :authenticate_twilio_request, :only => [
    :connect
  ]

  @@twilio_sid = ENV['TWILIO_ACCOUNT_SID']
  @@twilio_token = ENV['TWILIO_AUTH_TOKEN']
  @@twilio_number = ENV['TWILIO_NUMBER']
  @@api_host = ENV['TWILIO_HOST']

  # Render home page
  def index
    render 'index'
  end

  def voice
    response = Twilio::TwiML::Response.new do |r|
      r.Say "Yay! You're on Rails!", voice: "alice"
      r.Sms "Well done building your first Twilio on Rails 5 app!"
    end
    render :xml => response.to_xml
  end

  # Handle a POST from our web form and connect a call via REST API
  def call
    contact = Contact.new
    contact.user_phone  = params[:userPhone]
    contact.sales_phone = params[:salesPhone]

    # Validate contact
    if contact.valid?

      @client = Twilio::REST::Client.new @@twilio_sid, @@twilio_token
      # Connect an outbound call to the number submitted
      @call = @client.calls.create(
        :from => @@twilio_number,
        :to => contact.user_phone,
        :url => "#{@@api_host}/connect/#{contact.encoded_sales_phone}" # Fetch instructions from this URL when the call connects
      )

      # Let's respond to the ajax call with some positive reinforcement
      @msg = { :message => 'Phone call incoming!', :status => 'ok' }

    else

      # Oops there was an error, lets return the validation errors
      @msg = { :message => contact.errors.full_messages, :status => 'ok' }
    end
    respond_to do |format|
      format.json { render :json => @msg }
    end
  end

  # This URL contains instructions for the call that is connected with a lead
  # that is using the web form.
  def connect
    # Our response to this request will be an XML document in the "TwiML"
    # format. Our Ruby library provides a helper for generating one
    # of these documents
    response = Twilio::TwiML::Response.new do |r|
      r.Say 'FUCK.', :voice => 'alice'
      # r.Dial params[:sales_number]
    end
    render text: response.text
  end


  # Authenticate that all requests to our public-facing TwiML pages are
  # coming from Twilio. Adapted from the example at
  # http://twilio-ruby.readthedocs.org/en/latest/usage/validation.html
  # Read more on Twilio Security at https://www.twilio.com/docs/security
  private
  def authenticate_twilio_request
    twilio_signature = request.headers['HTTP_X_TWILIO_SIGNATURE']
    # Helper from twilio-ruby to validate requests.
    @validator = Twilio::Util::RequestValidator.new(@@twilio_token)

    # the POST variables attached to the request (eg "From", "To")
    # Twilio requests only accept lowercase letters. So scrub here:
    post_vars = params.reject {|k, v| k.downcase == k}

    is_twilio_req = @validator.validate(request.url, post_vars, twilio_signature)

    unless is_twilio_req
      render :xml => (Twilio::TwiML::Response.new {|r| r.Hangup}).text, :status => :unauthorized
      false
    end
  end

end

错误图片:

我正在使用 ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-darwin15]Rails 5.1.0

您的代码很可能在 is_twilio_req = @validator.validate(request.url, post_vars, twilio_signature) 处失败,因为在检查 gem's code 时,它在

以下的 sort 处失败

data = url + params.sort.join

这是因为在Rails 5.1中,ActionController::Parameters不再继承自Hash,所以Hash方法如sort(see Hash docs ) 将不再有效。

您需要将 params 显式转换为散列:

def authenticate_twilio_request
  twilio_signature = request.headers['HTTP_X_TWILIO_SIGNATURE']
  @validator = Twilio::Util::RequestValidator.new(@@twilio_token)

  # convert `params` which is an `ActionController::Parameters` object into `Hash`
  # you will need `permit!` to strong-params-permit EVERYTHING so that they will be included in the converted `Hash` (you don't need to specifically whitelist specific parameters for now as the params are used by the Twilio gem)
  params_hash = params.permit!.to_hash

  post_vars = params_hash.reject {|k, v| k.downcase == k}

  is_twilio_req = @validator.validate(request.url, post_vars, twilio_signature)

  unless is_twilio_req
    render :xml => (Twilio::TwiML::Response.new {|r| r.Hangup}).text, :status => :unauthorized
    false
  end
end