No route matches? - ruby-on-rails

I'm getting a "No route matches" exception in one of my tests (and using curl from the command line) one of my routes (POST /users/confirm). The curl's I've tried are as follows, neither of them work and receive the same exceptions outlined in the below notes:
curl -X POST -H "Content-Type: application/json; version=1" \
-d '{ user: { "token":"1deb36b4e6a7ba6d9203" } }' \
http://localhost:3000/appname/users/confirm
curl -X POST -H "Content-Type: application/json; version=1" \
-d '{ "token":"1deb36b4e6a7ba6d9203" }' \
http://localhost:3000/appname/users/confirm
My test is as follows. I have config.wrap_parameters = true in my /config/application.rb file...
Here is my User UsersController#confirm action along with my strong params. I params.require(:user).permit(:token) as opposed to simply params.permit(:token) because, as stated above, I have config.wrap_parameters = true in my /config/application.rb file...
This is my route entry...
Here is the output from rails routes (app name removed)...
I have config.wrap_parameters = true in my /config/application.rb file...
Oddly enough, if I change my params in my test to post :confirm, params: { token: #user.confirmation_token }, I get the following error instead:
At a loss. Any thoughts?

It turns out I didn't need :token in my route after all. Changed it to this, and all is well:
post '/appname/users/confirm/', to: 'users#confirm', as: 'appname_users_confirm'

Related

Proper forming of API requests

The following command in the console:
curl 'https://3b803ce956aa.ngrok.io/api/v1/send' -i --header "Accept: application/json" --header "Content-Type: application/json" -H 'Accept-Charset: utf-8' -H 'Authorization: Token token="GeUPm5xoxQFXR0ijJOZ6W6xr2ME1wZUWiaB3PLg9uZ8uGhFFDE7YnqCjFQwcCs0zgbtHjIiuc2jxo4I5"' -d '{"server_id":1,"building_id":1}'
but also with a version
--data '{"server_id":1,"building_id":1}'
is being received by the API controller. The routes are defined as:
namespace :api do
namespace :v1 do
post 'send', to: 'messages#send', defaults: { format: :json }
However, the handling of the requests is failing, in both cases, as it receives and returns:
Processing by Api::V1::MessagesController#send as JSON
Parameters: {"server_id"=>1, "building_id"=>1, "message"=>{"server_id"=>1, "building_id"=>1}}
Completed 500 Internal Server Error in 0ms (ActiveRecord: 0.0ms)
ArgumentError (wrong number of arguments (given 1, expected 0)):
where the controller action
def send
#request = JSON.parse(request.body.read)
#messagelog = Messagelog.create(server_id: params[:server_id], building_id: params[:building_id]
[...]
Two oddities appear:
the fact that the parameters are repeated with the contents of the parameters as part of the message
the action expects 0 arguments
I do not understand why the parameters get interpreted twice (this is a sub-question..). How can the API controller action be construed to accept the parameters?
By default Rails wraps JSON request parameters into a hash guessing its name from controller class. You can read details here.
So if you don't need this "guessed" hash in your params just remove :json from :format array in config\initializers\wrap_parameters.rb. Or you can use fine-grained control at the controller level as described above.

How do I convert this curl command to Ruby rest-client put request?

I have this curl command which I need to covert to PUT request
curl https://example.com/api/v2/students/id.json \
-d '{"student":{"description":{"body":"Adding a new test description"}}}' \
-H "Content-Type: application/json" \
-v -u test#gmail.com:Abcd1234 \
-X PUT
Trial
I tried this PUT, but it doesn't work. It doesn't throw any error, but it does not add the description.
put(
"https://example.com/api/v2/students/id.json",
{:student => {:description => {:body => 'Adding a new test description.'}}},
{ 'Authorization' => "Basic #{authorization_token}" }
)
In your curl example, you provided the body as a (JSON-formatted) string:
curl ... \
-d '{"student":{"description":{"body":"Adding a new test description"}}}' \
...
The direct equivalent in rest-client would also use a (JSON-formatted) string:
put( ...,
'{"student":{"description":{"body":"Adding a new test description"}}}',
...
)
According to the README:
rest-client does not speak JSON natively, so serialize your payload to a string before passing it to rest-client.
You can use the rest-client log to show the actual HTTP request sent, and compare it with what curl sends.
How to debug/display request sent using RestClient
How to display request headers with command line curl
curl https://example.com/api/v2/students/id.json \
-d '{"student":{"description":{"body":"Adding a new test description"}}}' \
-H "Content-Type: application/json" \
-v -u test#gmail.com:Abcd1234 \
-X PUT
use
put(
"https://test%40gmail.com:Abcd1234#example.com/api/v2/students/id.json",
{student: {description: {body: 'Adding a new test description.'}}},
#{'student': {'description': {'body': 'Adding a new test description.'}}},
#{:student => {:description => {:body => 'Adding a new test description.'}}}.to_json,
{content_type: :json, accept: :json}
)

Rails ActionController ignores request headers

I have a simple controller method that logs headers via ActionController's #headers method:
class ThingsController < ActionController::Base
def show
Rails.logger.info headers
render json: {response: 'success'}
end
end
However, when I call this controller method via curl with headers, they are not logged:
curl "http://localhost:3000/things/1” \
-H "access-token XXX" \
-H "token-type Bearer" \
-H "client YYY" \
-H "expiry 1234" \
-H "uid test#test" \
Instead, the following headers are logged:
{"X-Frame-Options"=>"SAMEORIGIN", "X-XSS-Protection"=>"1; mode=block", "X-Content-Type-Options"=>"nosniff"}
I thought my Rails 5 app's CORS policy might be to blame, so I installed the rack-cors gem and configured it in the initializer below. Unfortunately, it did not change the result.
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*',
headers: :any,
methods: %i(get post put patch delete options head)
end
end
I don't think this has anything to do with CORS.
In Rails 5.2, the ActionController instance method #headers is delegated to the response object.
https://github.com/rails/rails/blob/v5.2.0/actionpack/lib/action_controller/metal.rb#L150
delegate :headers, :status=, :location=, :content_type=,
:status, :location, :content_type, to: "#_response"
To access the request headers, you can do so via the request object. http://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-headers
Additionally, your cURL syntax needs to change to delimit the key from the value.
curl "http://localhost:3000/things/1” \
-H "access-token: XXX" \
-H "token-type: Bearer" \
-H "client: YYY" \
-H "expiry: 1234" \
-H "uid: test#test" \
Per the Rack spec (and RFC 3875), headers sent by the client are prefixed with HTTP_ and all occurrences of - are replaced with _.
To log the headers you specified via cURL:
class ThingsController < ActionController::Base
def show
Rails.logger.info {
request.headers.env.slice(
"HTTP_ACCESS_TOKEN",
"HTTP_TOKEN_TYPE",
"HTTP_CLIENT",
"HTTP_EXPIRY",
"HTTP_UID"
)
}
render json: {response: 'success'}
end
end

How to reading and Output [FILTERED] value from parameters in Ruby

I am using curl to post json to my example service. I am posting json to the service as shown below
curl \
> -i \
> -H "Accept: application/json" \
> -H "Content-type: application/json" \
> -X POST \
> -d '{"email":"micky#minn.com","full_names":"Inisne Dats", "password": "oasswn"}' http://localhost:3000/api/admin_users
Below is my method thats responsible for creating and saving the new Active record Object
def create
user = AdminUser.new(white_list)
if user.save
head 200
else
puts user.errors.full_messages
head 500
end
end
My Whitelist method below
private
def white_list
params.require(:admin_user).permit(:email,:full_names,:password)
end
The problem is that this code never saves because the password is FILTERED, I have inspected the parameters and this is the output;
{"email"=>"micky#minn.com", "full_names"=>"Inisne Dats", "password"=>"[FILTERED]", "admin_user"=>{"email"=>"micky#minn.com", "full_names"=>"Inisne Dats"}}
Can anyone help show me how to retrieve the filtered password and use it once the parameters reach the controller method create. Or I'm I using whitelisting feature wrong?
#j-dexx gave me this answer. I had to wrap the parameters with a root "admin_user" key like so:
{ "admin_user":
{ "email": "micky#minn.com",
"full_names": "Inisne Dats",
"password": "oasswn",
"password_confirmation": "oasswn"
}
}
...so I changed my post request to:
curl \
> -i \
> -H "Accept: application/json" \
> -H "Content-type: application/json" \
> -X POST \
> -d '{"admin_user":{"email":"micky#minn.com","full_names":"Inisne Dats","password":"oasswn","password_confirmation":"oasswn"}}' http://localhost:3000/api/admin_users
That did the trick!

Devise with Simple Token Authentication

i am using the following gem and devise now, since devise remove the support for token authentication.
https://github.com/gonzalo-bulnes/simple_token_authentication
What i am missing here is that, I have all the configuration setup but when i hit http://localhost:3000/user/sign_in.json using the RestConsole Tester on Google.
I am getting the following error:
ActionController::InvalidAuthenticityToken at /users/sign_in.json
ActionController::InvalidAuthenticityToken
actionpack (4.0.2)
lib/action_controller/metal/request_forgery_protection.rb, line 163
def initialize(controller)
#controller = controller
end
def handle_unverified_request
raise ActionController::InvalidAuthenticityToken
end
end
end
protected
Any ideas?
Your POST is failing a CSRF token check. You can validate this is the case by temporarily removing protect_from_forgery from your application_controller.rb which should make this work.
This article provides a solution for overriding that check on a specific controller, which should be safe for login requests.
You could try this
Authenticate:
curl -H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-X POST http://localhost:3000/users/sign_in \
-d '{"user" : { "email" : "test#example.com", "password" : "password"}}' \
-c cookie
Show:
curl -H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-X GET http://localhost:3000/pages/1.xml \
-b cookie
That works for me.

Resources