Following the tutorial for Twilio Client. Got stuck here where you do the testing
https://www.twilio.com/docs/quickstart/ruby/client/incoming-calls
curl -X POST http://localhost:3000/voice
I keep getting the WEBrick::HTTPStatus::LengthRequired response.
When I put it as
curl -X POST http://localhost:3000/voice -d ''
It works. But how do I fix for this in my routes or controller?
routes.rb
post 'voice', to: 'calls#voice', as: :voice
controller
def voice
response = Twilio::TwiML::Response.new do |r|
# Should be your Twilio Number or a verified Caller ID
r.Dial :callerId => '+16479316790' do |d|
d.Client 'jenny'
end
end
render :text => response.text
end
Thanks!
Also, if you have done this previously... having trouble adding localhost:3000 as the callback url in the dashboard. Any suggestions?
The voice URL does not need to be a POST request, it can be a GET request. In the App dashboard, you can change the type of the voice request URL to GET and then modify your routes.rb to use get.
Using 'localhost' as the domain will not work as want a URL to point to your webserver. What you instead want is the full URL to your web server which you can accomplish with something like ngrok.
Related
I started Ruby on Rails few days ago, and I'm struggling with routing.
Indeed, I would like to make a post request through my routes.rb, but I keep having a
No route matches [GET] "/orders/refresh"
error.
Here is my routes.rb :
# frozen_string_literal: true
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
get '/orders', to: 'orders#index'
get '/orders/active(/:q)', to: 'orders#active'
post '/orders/refresh', to: 'orders#refresh'
end
and here is my controller (orders_controller.rb) :
# frozen_string_literal: true
class OrdersController < ApplicationController
def index
#orders = Order.order(:departure_date).all
render json: #orders.to_json
end
def active
if !params[:q]
#orders = Order.order(:departure_date).where(active: true)
else
#orders = Order.order(:departure_date).where("reference = ? OR client_name = ? OR departure_city = ? OR arrival_city = ?",
params[:q], params[:q], params[:q], params[:q])
.where(active: true)
end
render json: #orders.to_json
end
def refresh
response = RestClient.get 'https://wakeo-technical-test.s3.eu-west-3.amazonaws.com/api.json'
json = JSON.parse response
if !json.nil?
json.each do |order|
old_order = Order.find_by(reference: order["client_number"])
if !old_order.nil?
old_order.update(departure_date: order["dep_time"])
old_order.update(arrival_date: order["arr_time"])
old_order.update(client_name: order["company"])
old_order.update(departure_city: order["dep_city"])
old_order.update(arrival_city: order["arr_city"])
end
end
else
puts "error seeding external API"
end
end
end
From what I have understood, it seems like RoR will try to find a GET request for that specific URL, and since it won't find any, it will throw that error. How could I make that request be a POST for Rails ?
Also, I would appreciate any suggestion about how I should use ActiveRecord Querying, I'm pretty sure I could do it better here.
Thanks, have a great day !
EDIT : Here is the list of different routes my app seems to be capable of, including my POST.
Routes and error
The most common reason you unexpectly get GET requests instead of PUT, PATCH, POST or DELETE is that you are using link_to 'Something', '/some_path', method: :post and you broke the Rails Unobtrusive Javascript Driver (Rails UJS):
Because submitting forms with HTTP methods other than GET and POST
isn't widely supported across browsers, all other HTTP methods are
actually sent over POST with the intended method indicated in the
_method parameter. Rails automatically detects and compensates for this.
Rails does that with a JavaScript event handler attached to any link with the data-method attribute. But if you broke that functionality the browser will just perform its default action which is sending a GET request when the user clicks a link.
This problem usually boils down to one or more of:
Your javascript is throwing an error which halts script execution (use the browser console to find the error, make it suck less).
Rails UJS is not included in your assets pipeline or webpacker packs and thus not in the page.
The quick and easy solution to sidestep the problem is by using button_to which actually creates a form and does not require any JavaScript trickery. After all forms can send POST requests. And by just passing a _METHOD hidden field Rack will treat the request as any other HTTP verb.
button_to 'Something', '/some_path', method: :post
But in the long run you should probably fix the problem if you want to use any of the features of Rails UJS.
Your routes.rb is expecting a POST request to /orders/refresh routes, but apparently you are testing with a GET request.
Try changing your routes.rb:
Rails.application.routes.draw do
# ...
get '/orders/refresh', to: 'orders#refresh'
end
... or change your request to a POST request. If you are using Rails forms, you must do something like this:
form_with(url: "/orders/refresh", method: "post")
Ok, I think I figured it out.
It might be because when I hit /orders/refresh directly in my web browser, it will try to find a GET corresponding to the request.
I managed to make POST using a client like Postman, and everything works fine.
Thank you for your help !
I am integrating twilio click to call into my rails project.
Everything works fine however the url: in my twilio controller cannot be found on heroku. However, it can be found if you navigate to it in a browser. The phone dials but the voice says "Sorry a problem has occurred, good bye." If I change the url to an external xml file it works fine, just doesn't recognize this particular one. So I'm lead to believe that the controller etc works fine.
twillio_controller.rb
def call
#full_phone = current_user.phone
#partial_phone = #full_phone.last(-1)
#connected_number = "+61" + #partial_phone
#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 => #connected_number,
:url => 'http://besttradies.herokuapp.com/mytradies/connect.xml', # Fetch instructions from this URL when the call connects
)
#msg = { :message => 'Phone call incoming!', :status => 'ok' }
end
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 'If this were a real click to call implementation, you would be connected to an agent at this point.', :voice => 'alice'
end
render text: response.text
end
The OP solved in the comments above:
Figured it out. Routes for connect needed to be POST and I also had to
add skip_before_action :verify_authenticity_token to the twilio
controller as it was behind membership doors.
I have a twilio app that is making phone calls. I put the guts of it in a Worker, and now cannot get the API to recognize the url I am passing as a valid url for my TwiML response. Code is below. Any ideas? Also note that I have tried both #{root_path}connect and #{root_url}connect
Worker
#numbers.each do |dial|
if (dial.phone_number =~ /[\(\)0-9\- \+\.]{10,11}/).nil?
raise Exception, "bad phone number"
end
call = client.account.calls.create(
:from => my_number,
:to => dial.phone_number,
:url => "#{root_path}connect"
)
controller
def connect
response = Twilio::TwiML::Response.new do |r|
r.Say 'The Time Has come to take over the world Pinky', :voice => 'alice'
end
render text: response.text
end
routes
root :to => 'call_logs#index'
resources :call_logs, only: [:create, :index] do
collection { post :call_score_range,:call_warrants_with_date_range,:connect }
end
Twilio developer evangelist here.
I think your problem is that the worker has no concept of Rails' routes. Routes are only available by default in controllers and views, so you are probably not passing a URL to Twilio.
I can't see where you call your worker from in the first place, but one idea would be to pass the URL you want to send to the API into the worker from where it is created in a controller.
I hope this helps. Please let me know if there's anything else I can do for you.
I am using the twitter gem for ruby and need to send a POST request to users/lookup endpoint.
As per the gem source code documentation(https://github.com/sferik/twitter/blob/4e8c6dce258073c4ba64f7abdcf604570043af71/lib/twitter/rest/users.rb), the request should be POST by default, unless I pass :get :
#option options [Symbol, String] :method Requests users via a GET request instead of the standard POST request if set to ':get'.
def users(*args)
arguments = Twitter::Arguments.new(args)
request_method = arguments.options.delete(:method) || :post
flat_pmap(arguments.each_slice(MAX_USERS_PER_REQUEST)) do |users|
perform_with_objects(request_method, '/1.1/users/lookup.json', merge_users(arguments.options, users), Twitter::User)
end
end
I am calling it as follows:
users = #client.users(twitter_screen_names_arr, [:method, :post])
However, I am not sure if this is actually resulting in a POST request / a GET request.
How can I make sure if this is a POST/GET? I would like to print the request that is being made to get a clarity on what actually gets sent.
Thanks!
As you can see from the code it uses POST by default. This behavior is also specified with RSpec.
You can invoke the users method like this:
#client.users(twitter_screen_names_arr, :method => :post)
or simply
#client.users(twitter_screen_names_arr)
since POST is the default request method.
If you don’t trust the code or the specs, you could run the request through a proxy to verify this behavior manually.
I have 2 apps running on my localhost on port 3000 and 9000 (rails 2 and sinatra app).
I have set up a controller in the rails app (without any specific model or view) in app/controllers/finance_service.rb
class FinanceServiceController < ApplicationController
def after_token_create
p "after token create function: #{params.inspect}"
end
end
and had set up a route like so :
map.finance_service '/finance_service' , :controller => "finance_service", :action => "after_token_create"
and When I access it on the url http://localhost:3000/finance_service
I get error on template missing, but that's fine because it means the route is working (I am using it as a service api to the another app).
when trying to access the method from the other app using httparty gem like so :
HTTParty.post("http://localhost:3000/FinanceServiceController/after_token_create", :body => post_params)
I get an error on the rails app-
myapp/public/404.html (method_not_allowed)
Also tried from advanced Rest client app, and I get the same error.
Shouldn't the request be like this? since the route matcher is /finance_service
HTTParty.post("http://localhost:3000/finance_service", :body => post_params)