calling a helper on Grape API name space - ruby-on-rails

Working with on an API using Grape API and was wondering if it was possible to call a function in the namespace before an api gets called. There are two ways that we validate permission within our API and instead of calling them in each API call I would like to do it in the namespace before hand.
api.rb looks a little something like this:
Module MyModule
class API < Grape::API
.
.
.
helpers do
.
.
.
def authenticate!
raise CanCan::AccessDenied unless authenticated?
end
def authorize!(*args)
# Not a super user and trying to access the API of a company other than your own?
if !current_user.super_user? && current_user.company != #company
raise CanCan::AccessDenied
end
Ability.new(current_user, host_parts).authorize!(*args)
end
end
################################################
# Clerk API
namespace :clerk do
authenticate!
resource: myResource do
**API code here**
end
end
end
end
Is it possible to call authenticate! for a whole namespace like i have below instead of calling it in each api?

You can just use a before block inside your namespace. Your code would be something like this:
Module MyModule
class API < Grape::API
helpers do
def authenticate!
raise CanCan::AccessDenied unless authenticated?
end
def authorize!(*args)
if !current_user.super_user? && current_user.company != #company
raise CanCan::AccessDenied
end
Ability.new(current_user, host_parts).authorize!(*args)
end
end
# Clerk API
namespace :clerk do
resource: myResource do
before do
authenticate!
end
end
end
end
end
The before block will be called before every call to your API.

Related

How can I redirect from a Module?

I tried TO Google Can I redirect_to in rails modules but couldn't come up with anything. Basically, I have a method that I am going to use across a couple of Controllers.
lib/route_module.rb
module RouteModule
def self.user_has_active_chocolate(c_id, u_id)
chocolate_id = c_id
user_id = u_id
unless UserChocolate.where(id: chocolate_id).empty?
if UserChocolate.where(id: chocolate_id).last.active?
true
else
false
# BREAKS OVER HERE...
redirect_to "/user/new-chocolate/#{user_id}"
end
else
false
redirect_to "/admin"
end
end
end
app/controllers/user_controllers.rb
include RouteModule
before_filter :thingz, only: [:display_user_chocolate]
# private
def thingz
RouteModule.user_has_active_chocolate(params["chocolate_id"], params["user_id"])
end
But... whenever I run this... It will break as soon as it hit's redirect_to.
undefined method `redirect_to' for RouteModule:Module
My other option is use ActiveSupport::Concerns but I just trouble converting this Module into a Concern.
When you include a module, it acts as a mixin. That said, you include and get all the methods of the module in the context of your class. The proper way would be:
module RouteModule
def user_has_active_chocolate(c_id, u_id) # NO self
...
end
end
And in the class:
include RouteModule
def thingz
# NO module method call (NO RouteModule)
user_has_active_chocolate(params["chocolate_id"], params["user_id"])
end

How to handle authentication token string in Grape API and token_and_options?

I'm using Ember front-end with Grape API and to authenticate a page I have something like:
def current_user
return nil if headers['Authorization'].nil?
#current_user ||= User.find_by_authentication_token(
headers['Authorization']
)
end
At the moment I'm using ember-simple-auth which sends something like as a header:
Token token="n2Rs5tokenLH", email="my#email.com"
Check out the Grape logger:
User Load (38.1ms) SELECT "users".* FROM "users" WHERE "users"."authentication_token" = 'Token token="n2Rs5tokenLH", email="my#email.com"' LIMIT 1
Now in rails I usually use authenticate_or_request_with_http_token to handle this. and I don't want to handle this manually using stuff like gsub or regular expressions. What is the best way to handle this in Grape?
Please note that the Grape API is mounted inside a rails project and inside app/api/backend/v1/default.rb:
module Backend
module V1
module Defaults
extend ActiveSupport::Concern
included do
version 'v1', using: :path
format :json
prefix :api
rescue_from :all do |e|
Backend::Base.logger.error e
end
helpers do
def current_user
return nil if headers['Authorization'].nil?
#current_user ||= User.find_by_authentication_token(
headers['Authorization']
)
end
def authenticate!
error!('401 Unauthorized', 401) unless current_user
end
end
end
end
end
end
Edit:
I just found out that I can use ActionController::HttpAuthentication::Token.token_and_options to do the job, however I'm not sure how should I include this in Grape project.
The structure of the app looks like:
⇒ tree app/api
app/api
└── backend
├── base.rb
└── v1
├── defaults.rb
└── ....
I tried to include ActionController::HttpAuthentication::Token in defaults.rbsomething like:
helpers do
include ActionController::HttpAuthentication::Token
def current_user
return nil if headers['Authorization'].nil?
#current_user ||= User.find_by_authentication_token(
token_and_options(headers['Authorization'])
)
end
def authenticate!
error!('401 Unauthorized', 401) unless current_user
end
end
But now I'm getting:
undefined method `authorization' for #<String:0x007ff51cdb85f8>
You're on the right path: use token_params_from and pass in the Authorization header directly.
helpers do
include ActionController::HttpAuthentication::Token
def current_user
return nil if headers['Authorization'].nil?
#current_user ||= User.find_by_authentication_token(token)
end
def token
token_params_from(headers['Authorization']).shift[1]
end
def authenticate!
error!('401 Unauthorized', 401) unless current_user
end
end
The undefined method exception is due to token_and_options expecting a ActionDispatch::Request object where you're providing a String.
I had to add a customized token_and_options function which looks like:
def token_and_options(auth_string)
if header = auth_string.to_s[/^Token (.*)/]
values = $1.split(',').
inject({}) do |memo, value|
value.strip!
key, value = value.split(/\=\"?/)
value.chomp!('"')
value.gsub!(/\\\"/, '"')
memo.update(key => value)
end
values.delete("token")
end
end
And then parse token with something like: token_and_options(headers['Authorization'])

call application controller method from engine

How do I call a method from ApplicationController in a rails engine?
We are using ckeditor gem to integrate ckeditor in our rails app. Since we implemented our own authorization system, I need to make a custom ckeditor authorization hook which needs to get the current_user object to decide whether engine controller-action is allowed for this user.
I have current_user defined in mail_app ApplicationController, I want to call it from CKeditor::ApplicationController.
I have included my code here
config/inititializers/ckeditor.rb
Ckeditor.setup do |config|
config.current_user_method do
current_user
end
config.authorize_with :chronus
end
lib/ckeditor/hooks/chronus.rb
module Ckeditor
module Hooks
class ChronusAuthorization
include Ckeditor::Helpers::Controllers
def initialize(controller)
#controller = controller
#controller.extend ControllerExtension
end
def authorize(action, model_object = nil)
raise Authorization::PermissionDenied unless authorized?(action, model_object)
end
def authorized?(action, model_object = nil)
if action
if #controller.current_user_for_chronus.is_admin?
[:index, :create, :destroy].include? action
else
[:create].include? action
end
end
end
private
module ControllerExtension
def current_user_for_chronus
ckeditor_current_user
end
end
end
end
end
Ckeditor::AUTHORIZATION_ADAPTERS[:chronus] = Ckeditor::Hooks::ChronusAuthorization
There is suggestion in rails guide to make the engine's scoped ApplicationController to inherit from the main ApplicationController. But I cannot do that as engine here is an external gem. (Or is there a way to change the inheriting class?)

Stubbing Grape helper

I have Rails app with Grape API.
The interface is done with Backbone and Grape API provides it all data.
All it returns is user-specific stuff, so i need reference to currently logged in user.
Simplified version looks like this:
API initialization:
module MyAPI
class API < Grape::API
format :json
helpers MyAPI::APIHelpers
mount MyAPI::Endpoints::Notes
end
end
Endpoint:
module MyAPI
module Endpoints
class Notes < Grape::API
before do
authenticate!
end
# (...) Api methods
end
end
end
API helper:
module MyAPI::APIHelpers
# #return [User]
def current_user
env['warden'].user
end
def authenticate!
unless current_user
error!('401 Unauthorized', 401)
end
end
end
So, as you can see, i get the current user from Warden and it works fine. But the problem is with testing.
describe MyAPI::Endpoints::Notes do
describe 'GET /notes' do
it 'it renders all notes when no keyword is given' do
Note.expects(:all).returns(#notes)
get '/notes'
it_presents(#notes)
end
end
end
How can I stub helpers's method *current_user* with some specific user?
I tried:
setting env/request, but it doesn't exist before calling get method.
stubbing MyAPI::APIHelpers#current_user method with Mocha
stubbing MyAPI::Endpoints::Notes.any_instance.stub with Mocha
Edit:
At the moment, it's stubbed this way:
spec:
# (...)
before :all do
load 'patches/api_helpers'
#user = STUBBED_USER
end
# (...)
spec/patches/api_helpers.rb:
STUBBED_USER = FactoryGirl.create(:user)
module MyAPI::APIHelpers
def current_user
STUBBED_USER
end
end
But it's definitely not the answer :).
comments mentioned in this issue should help you, It's how even Grape tests it's helpers,
https://github.com/intridea/grape/blob/master/spec/grape/endpoint_spec.rb#L475
(If the code is not there on the same line due to changes, just do a ctrl+f & look for helpers)
Here's some code from the same file
it 'resets all instance variables (except block) between calls' do
subject.helpers do
def memoized
#memoized ||= params[:howdy]
end
end
subject.get('/hello') do
memoized
end
get '/hello?howdy=hey'
last_response.body.should == 'hey'
get '/hello?howdy=yo'
last_response.body.should == 'yo'
end
Option 1
The recommended way is to use Grape::Endpoint.before_each:
context 'when user is logged in' do
before do
Grape::Endpoint.before_each do |endpoint|
allow(endpoint).to receive(:current_user).and_return(user)
end
end
after { Grape::Endpoint.before_each nil }
end
But this is quite verbose. It can live in a shared context, but you can't pass user as a parameter explicitly so you'd end up with:
let(:user) { create(:user) }
# ...
include_context 'signed in user'
Option 2
My preferred way is a more RSpec-like stubbing:
# helper
module AuthHelper
def current_user
# ...
end
end
# api
module API
module V1
class Auth < Grape::API
helpers AuthHelper
end
end
end
# spec
before do
allow_any_instance_of(AuthHelper).to receive(:current_user).and_return(user)
end
Option 3
You can also define helpers:
API::V1::User.helpers do
def current_user
user
end
end

Ruby: add method to the existing module

There is a module:
module ActionDispatch
module Routing
end
end
And methods:
def add_movie_path
end
def edit_movie_path
end
How I can add to module Routing this methods?
Is this only way?
Try:
module ActionDispatch
module Routing
def add_movie_path
end
def edit_movie_path
end
module_function :edit_movie_path
end
end
So that then you can do a call like it is a instance method like so:
class Make
include ActionDispatch::Routing
end
class MakeAll
def only_needs_the_one_method
ActionDispatch::Routing.edit_movie_path
end
end
You can also define it as a class method by using self.class_name and then directly access it like so:
module ActionDispatch
module Routing
def self.add_movie_path
end
def self.edit_movie_path
end
end
end
class Make
include ActionDispatch::Routing
def do_something
ActionDispatch::Routing.add_movie_path
end
end
class MakeAll
def only_needs_the_one_method
ActionDispatch::Routing.edit_movie_path
end
end
See that Modules Magic for more.
Unless I misunderstand what you're asking, how about something like:
module ActionDispatch
module Routing
def add_movie_path
end
def edit_movie_path
end
end
end
Alternatively, you could use module_eval.
Simply put your methods inside the module.
module ActionDispatch
module Routing
def add_movie_path
end
def edit_movie_path
end
end
end

Resources