Log Out User and Change token to NIL - ruby

I've started to create an Api for my rails application. I am currently creating the Sessions Controller for Log in.
Sign Out seems to be working, but I'd really like the to be able to Sign Out the User AND set the users oauth_token equal to NIL.(oauth_token = nil)
I've tried the code below, but it can't seem to find the correct user by using their oauth_token.
Curl Command
curl -v -H 'Content-Type: application/json' -H 'Accept: application/json' -X DELETE
http://localhost:3000/api/sessions/\?auth_token\=5c147a84cd5418771b9063dddcbfde96d5a8630b
API CONTROLLER
module Api
module V1
class SessionsController < ApplicationController
skip_before_filter :verify_authenticity_token,
:if => Proc.new { |c| c.request.format == 'application/json' }
respond_to :json
def destroy
user = User.find_by_oauth_token(params[:session][:oauth_token])
if user.present?
user.oauth_token = nil
user.save
end
sign_out
render :status => 200,
:json => { :success => true,
:info => "Logged Out",
:data => {} }
end
end
end
end
CONTROLLER
class SessionsController < ApplicationController
def destroy
sign_out
redirect_to root_path
end
end
SESSION HELPER
def sign_out
current_user = nil
cookies.delete(:remember_token)
end
ROUTES
### API Routes
namespace :api, defaults: {format: 'json'} do
scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do
resources :sessions, only: [:new, :create, :destroy]
end
end
LOGS
Started DELETE "/api/sessions/?auth_token=5c147a84cd5418771b9063dddcbfde96d5a8630b"
for 127.0.0.1 at 2014-09-01 00:05:37 -0700
Processing by Api::V1::SessionsController#destroy as JSON
Parameters: {"auth_token"=>"5c147a84cd5418771b9063dddcbfde96d5a8630b", "session"=>{}}
User Load (1.7ms) SELECT "users".* FROM "users" WHERE "users"."oauth_token" IS NULL LIMIT 1
Completed 200 OK in 130ms (Views: 0.4ms | ActiveRecord: 6.4ms)

I was able to figure it out by changing my Curl Command to this:
curl -v -H 'Content-Type: application/json' -H 'Accept: application/json' -X DELETE
http://localhost:3000/api/sessions -d
"{\"session\":{\"oauth_token\":\"5c147a84cd5418771b9063dddcbfde96d5a8630b\"}}"

Related

Authentication problem in Ruby Sinatra web app

I have a simple Sinatra app with two controllers and api helper
# ApplicationController
class ApplicationController < Sinatra::Base
register Sinatra::ActiveRecordExtension
helpers ApiHelper
configure :production, :development do
enable :logging
end
before do
content_type :json
end
get '/hello' do
{ message: 'Hello!' }.to_json
end
end
# ArticlesController
class ArticlesController < ApplicationController
before do
authenticate!
end
get '/articles' do
articles = Article.all
articles.map { |article| serialize(article) }
end
...
end
# ApiHelper
module ApiHelper
def authenticate!
halt 403, { message: 'Unauthorized!' }.to_json unless authorized?
end
private
def authorized?
request.env['HTTP_AUTHORIZATION'] == 'Bearer 123qweasd'
end
end
When I do
curl -X GET -i -H 'Accept: application/json' http://localhost:4567/hello
to do helth check I get 403 Unauthorized. Why? I don't require authentication in /hello endpoint, only in /articles CRUD endpoints so I don't understand why it authenticates in /hello. According to the docs before block is used to perform some action before other action runs but I don't call authenticate! in before block in ApplicationController. What am I missing?
It turned out that not knowingly I was using ArticlesController as a middleware. My config.ru looked like this.
run ApplicationController
use ArticlesController
which made it so that the authenticate! was called before every request.
I changed my config.ru to this:
map '/' do
run ApplicationController
end
map '/articles' do
run ArticlesController
end
And it works.

unable to make api request with http ruby gem

I am trying to translate a curl request that works in the terminal for me into ruby code using the http gem.
This is the curl request that gives me back the valid json I want:
curl -X GET --header 'Accept: application/json' --header 'api_key: somekey' --header 'authtoken: sometoken' 'https://cdn.domain.io/v3/content_types/shirts/entries?environment=dev'
With the http gem I try to do this in my ruby script:
HTTP.headers(:Accept => "application/json", :api_key => 'somekey', :authtoken => 'sometoken').get("https://cdn.domain.io/v3/content_types/shirts/entries", :params => { :environment => 'dev'}).body.readpartial
And this gives my back "api_key":["is not valid."]} error from the server
What am I doing wrong? How do I get this to work?
Typhoeus seems to be working out well:
require "typhoeus"
require 'multi_json'
require "awesome_print"
response = Typhoeus::Request.new(
"https://api.domain.io/v3/content_types/shirts/entries?environment=dev",
headers: { api_key: "somekey", access_token: "sometoken",
accept_encoding: "gzip" }
).run
# puts response.body
begin
ap MultiJson.load(response.body, :symbolize_keys => true)
rescue MultiJson::ParseError => exception
p exception.data # => "{invalid json}"
p exception.cause # => JSON::ParserError: 795: unexpected token at '{invalid json}'
end

Cannot redirect to nil! (Error) - Rails 4 Nested Form

I am following a tutorial on Udemy and adding an address to my Custom Devise Admin #Show Page.
after completing the nesting and controller modifications I am getting this error in the address controller create redirect.
No route matches {:action=>"show", :admin_id=>"B1CA", :controller=>"admin"} missing required keys: [:id]
My Admin Controller:
class AdminController < ApplicationController
before_action :authenticate_admin!
def show
#admin = Admin.find_by_admin_ident(params[:id])
#addresses = #admin.addresses
end
def index
#admins = Admin.all
end
end
My Address Controller: - Provided full controller incase I have erred somewhere else thats causing this.
class Admin::AddressesController < ApplicationController
before_action :set_address, only: [:show, :edit, :update, :destroy]
# GET /addresses
# GET /addresses.json
def index
#addresses = Address.all
end
# GET /addresses/1
# GET /addresses/1.json
def show
end
# GET /addresses/new
def new
#admin = Admin.find_by_id(params[:admin_ident])
#address = Address.new
end
# GET /addresses/1/edit
def edit
end
# POST /addresses
# POST /addresses.json
def create
#admin = Admin.find_by_id(params[:admin_ident])
#address = Address.new(address_params)
#address.admin = #admin
respond_to do |format|
if #address.save
format.html { redirect_to admin_path, notice: 'Address was successfully created.' }
format.json { render :show, status: :created, location: #admin }
else
format.html { render :new }
format.json { render json: #admin.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /addresses/1
# PATCH/PUT /addresses/1.json
def update
respond_to do |format|
if #address.update(address_params)
format.html { redirect_to #address, notice: 'Address was successfully updated.' }
format.json { render :show, status: :ok, location: #address }
else
format.html { render :edit }
format.json { render json: #address.errors, status: :unprocessable_entity }
end
end
end
# DELETE /addresses/1
# DELETE /addresses/1.json
def destroy
#address.destroy
respond_to do |format|
format.html { redirect_to addresses_url, notice: 'Address was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_address
#address = Address.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def address_params
params.require(:address).permit(:admin_id, :address_ident, :number, :name, :st_type, :unit_apt, :grid, :city, :province, :postal_code)
end
end
I am using custom identifiers as opposed to the standard rails /1 ect.. for id's this is how they are implemented.
Admin: - Exact same implementation in Addresses
class Admin < ActiveRecord::Base
before_create :generate_admin_ident
# Model Relations
has_many :addresses, dependent: :destroy
# Model Validations
validates_uniqueness_of :admin_ident
# Unique Ident Generator
def generate_admin_ident
begin
self.admin_ident = SecureRandom.hex(2).upcase
other_admin = Admin.find_by(admin_ident: self.admin_ident)
end while other_admin
end
# Vanity URL
def to_param
admin_ident
end
end
My form_for: Oddly enough this is not namespaced, but loads the form as follows -
<%= form_for [:admin, #admin, #address] do |f| %>
...
<% end %>
My routes File:
devise_for :admins, controllers: { sessions: 'admins/sessions', registrations: 'admins/registrations', passwords: 'admins/passwords', confirmations: 'admins/confirmations', unlocks: 'admins/unlocks'}
#Nests Addresses to Admin
resources :admins, only: [:index, :show], controller: 'admin' do
resources :addresses, except: [:index], controller: 'admin/addresses'
end
My Controller File Layout
Error Screen Better Errors
Please let me know if you want anymore information, I will do my best to accommodate!
EDIT # 1: - Rails Server Output
Started POST "/admins/B1CA/addresses" for ::1 at 2016-05-26 22:47:52 -0600
Processing by Admin::AddressesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"D2Sq2Pbq2bLxpOxBveSFf/3ivRJcm5jbhw39mnB/C1UnDll8z3fdEJMaf9315fcIaI6o7foTrvWrH7pT2y2BtA==", "address"=>{"admin_id"=>"", "address_ident"=>"", "number"=>"1234", "name"=>"Something", "st_type"=>"St", "unit_apt"=>"101", "grid"=>"SE", "city"=>"Calgary", "province"=>"AB", "postal_code"=>"T2B 5V5"}, "commit"=>"Create Address", "admin_id"=>"B1CA"}
Admin Load (0.3ms) SELECT "admins".* FROM "admins" WHERE "admins"."id" IS NULL LIMIT 1
(0.1ms) BEGIN
Address Exists (0.2ms) SELECT 1 AS one FROM "addresses" WHERE "addresses"."address_ident" = '' LIMIT 1
Address Load (0.1ms) SELECT "addresses".* FROM "addresses" WHERE "addresses"."address_ident" = $1 LIMIT 1 [["address_ident", "9F608A04"]]
SQL (0.1ms) INSERT INTO "addresses" ("address_ident", "number", "name", "st_type", "unit_apt", "grid", "city", "province", "postal_code", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING "id" [["address_ident", "9F608A04"], ["number", "1234"], ["name", "Something"], ["st_type", "St"], ["unit_apt", "101"], ["grid", "SE"], ["city", "Calgary"], ["province", "AB"], ["postal_code", "T2B 5V5"], ["created_at", "2016-05-27 04:47:52.551915"], ["updated_at", "2016-05-27 04:47:52.551915"]]
(0.8ms) COMMIT
Redirected to
Completed 500 Internal Server Error in 7ms (ActiveRecord: 1.7ms)
ActionController::ActionControllerError - Cannot redirect to nil!:
Rake Routes Output for Admin_Addresses:
admin_addresses POST /admins/:admin_id/addresses(.:format) admin/addresses#create
new_admin_address GET /admins/:admin_id/addresses/new(.:format) admin/addresses#new
edit_admin_address GET /admins/:admin_id/addresses/:id/edit(.:format) admin/addresses#edit
admin_address GET /admins/:admin_id/addresses/:id(.:format) admin/addresses#show
PATCH /admins/:admin_id/addresses/:id(.:format) admin/addresses#update
PUT /admins/:admin_id/addresses/:id(.:format) admin/addresses#update
DELETE /admins/:admin_id/addresses/:id(.:format) admin/addresses#destroy
Edit: #2: Error When redirect to path is:** admin_addresses_path(#admin)
ActionController::UrlGenerationError at /admins/B1CA/addresses
No route matches {:action=>"create", :admin_id=>nil, :controller=>"admin/addresses"} missing required keys: [:admin_id]
Edit: 3 - Error when form for is set to below
<%= form_for [#admin, #address] do |f| %>
...
<% end %>
NoMethodError at /admins/B1CA/addresses/new
undefined method `addresses_path' for #<#<Class:0x007fc532933768>:0x007fc534b799a8>
Did you mean? admin_addresses_path
I think you May get wrong params for finding your admin. Change
#admin = Admin.find_by_id(params[:admin_ident])
format.html { redirect_to admin_path, notice: 'Address was successfully created.' }
To:
# admin_id here, not admin_ident
#admin = Admin.find_by_id(params[:admin_id])
format.html { redirect_to #admin, notice: 'Address was successfully created.' }
Or if you want to redirect to admin addresses:
# need to remove " except: [:index]" in your address routes
# routes
resources :addresses, controller: 'admin/addresses'"
# controller
format.html { redirect_to admin_addresses_path(#admin), notice: 'Address was successfully created.' }

No Route Matches DELETE Sessions Api

I've started to create an Api for my rails application. I am currently creating the Sessions Controller for Log in.
But for some reason I am getting this error
Started DELETE "/api/v1/sessions/?auth_token=6157d3673725013ebddbb5e26e8cd64756949110"
for 127.0.0.1 at 2014-08-29 18:54:18 -0700
ActionController::RoutingError (No route matches [DELETE] "/api/v1/sessions"):
I am not understanding why this is happening. Sign Out seems to work perfectly on the actual web application.
I know it may need an ID according to the rake routes but I'm not sure how to implement this.
API CONTROLLER
module Api
module V1
class SessionsController < ApplicationController
skip_before_filter :verify_authenticity_token,
:if => Proc.new { |c| c.request.format == 'application/json' }
respond_to :json
def destroy
sign_out
render :status => 200,
:json => { :success => true,
:info => "Logged Out",
:data => {} }
end
end
end
end
CONTROLLER
class SessionsController < ApplicationController
def destroy
sign_out
redirect_to root_path
end
end
SESSION HELPER
def sign_out
current_user = nil
cookies.delete(:remember_token)
end
ROUTES
### API Routes
namespace :api, defaults: {format: 'json'} do
scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do
resources :sessions, only: [:new, :create, :destroy]
end
end
RAKE ROUTES
api_v1_sessions POST /api/v1/sessions(.:format)
api/v1/sessions#create {:format=>"json"}
api_v1_session DELETE /api/v1/sessions/:id(.:format)
api/v1/sessions#destroy {:format=>"json"}
From the documentation
You can use resource instead of the resources routes helper. It's used to create routes for a singular resource that you don't access using IDs.
namespace :api, defaults: {format: 'json'} do
namespace :v1, constraints: ApiConstraints.new(version: 1, default: true) do
resource :session, only: [:new, :create, :destroy]
end
end
which will give you
GET /session/new
POST /session
DELETE /session

How can we test /user/show?id=xx with rspec?

The route in my system is:
user_show GET /user/show(.:format) user#show.
The controller code is:
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user}
end
end
_spec.rb
describe 'GET #show' do
it 'should return success' do
get :show, id:#user.id
expect(response).to be_success
end
end
result is:
Failure/Error: expect(response).to be_success
expected success? to return true, got false
In the browser, when I type xxx/user/show, it get error.
ActiveRecord::RecordNotFound in UserController#show
But if I type xxx/user/show?id=31, it shows user with id=31!!
Thanks for #Alex Wayne, I add more information here: I check the routes.rb file:
get "user/show"
get "user/index"
get "user/delete"
get "user/edit"
post "user/update"
resource :users, :path => :user, :as => :user
I personal think my teammate should not write down "get user/show, get user/index...." based on Rails Routing. But I can't change their code. So,
anyone know how to test user/show?id=xxx ? Many thanks~!!!!

Resources