I have a single client application - Angular JS frontend and a Rails API backend with a MySQL DB. I'm trying to convert the application into a single schema multi tenant application. I've done a lot of reading and:
I do not want to use a gem if possible - Apartment, which is multiple schemas and uses Postgres doesn't fit the bill, and act_as_tenant seems to use Thread.current to identify the tenant which I do not want to do.
I have read that default_scope should not be used as well, for a host of reasons I won't get into here.
I'm passing a tenant token in the request header from the frontend to the Rails backend, and using the tenant token I identify the tenant in my ApplicationController. I'm now figuring out the best way to both read and write data so that is associated with the tenant that made the request.
Having ruled out the options above, the only option I can see is to go into all of my controller methods and update them wherever data is being written and read. I would much rather apply some sort of callback to each of my Models, so that the tenant id is always written when data is being written and the tenant id is always used as a filter whenever data is being read.
Given that I cannot access the tenant token in the models, I am not sure how to proceed with this other than updating all my controller methods, which would be an arduous and mistake prone process.
Thanks in advance!
Not using default_scope is a good idea - it behaves as sort of a black box and can wreck havoc down the line especially if you ever do anything with paranoid deletion.
One way to do what you asked is to use thread_mattr_accessor. You can define the tenant_id token at the beginning of the web request, and then access it through the class attribute for the duration of the web request. This creates a thread-safe attributes accessor on your tenant model.
In your controller you can detect the tenant for the current request (using subdomain or token) and set the Token.current_id variable. This variable will be available for the duration of the request. Note that it will not automatically be available for any background jobs or other processes because the variable is set inside the current thread.
This method is demonstrated using scopes in this RailsCast, but you don't have to use scopes. You can set a helper method like current_tenant and then explicitly scope all your queries like current_tenant.posts.
# models/tenant.rb
class Tenant < ApplicationRecord
thread_cattr_accessor :current_id
# ...
end
# controllers/application_controller.rb
class ApplicationController < ActionController::Base
around_action :scope_current_tenant
private def scope_current_tenant
Tenant.current_id = current_tenant.id
yield
ensure
Tenant.current_id = nil
end
def current_tenant
#current_tenant ||= Tenant.find_by_token! params[:token]
end
helper_method :current_tenant
end
Related
Best(Standard) practice to send multiple parameters to REST get resource - Spring
What's the best practice to send multiple parameters on a REST GET resource call. Normally we can call GET call with path param &/ query. what is the best practice on how to achieve this(second and third).
Ex: /user/{username}/locaction} - Its a standard way
2. /user/{username}/{locaction}/{mobile_umber} - is it a standard way?
3. /user/{username}/{locaction}/{mobile_umber}/{age} - is it a standard way?
In terms of URLs, params tend to be more like RPC where you're invoking a function, e.g.:
/user?username=123
which is more like a traditional RPC call:
Object user = GetUsername(123);
REST represents a state of a resource which can be made up of many "states". Core information such as personal info, where 123 is the username:
/user/123 -> {"name":"Joe Bloggs"}
some aspects of the state of the user could change over time:
/user/123/location -> {"username":"123",lat:123456,lon:54568}
aspects of the user that are unlikely to change rapidly could be included in the core info /user/123 or if they're unlikely to be needed by a client, they can be requested separately:
/user/123/mobile -> {"username":"123",mobile:"345345"}
A User has a location and a User has a mobile and a User has an age. A location doesn't have a mobile or age so those aspects would never come under /user/location. They would come under the URL that represents the object that does have them:
/user/123/age -> {"username":"123", "age":100}
A location can have an accuracy which can either be requested separately:
/user/123/location/accuracy {"accuracy":"-1"}
or more likely included in the response to /user/123/location.
So the REST structure in this case mirrors the object hierarchy, the has parts.
The REST structure could also mirror the business structure:
/user/account
/user/contactinfo
/user/location
it just depends how you want to expose the data that represents a User and their states.
I'm making a web app where users can create pages, edit them, and delete them. In developing the prototype, I have a user access a route such as:
localhost:8000/mypage/1
The "1" in the URL refers to the ID in the database, so that the controller can fetch the appropriate associated data and populate the page accordingly.
The obvious problem here is that a user can plug in any number to that URL and edit someone else's page.
One obvious fix would be to add logic that checks whether or not page '1' belongs to the Auth::user(). But this would be an if statement that I have to add to every controller that carries out such function.
When I think about other sites, they never have ID's in the URL, or if they do, they look 'encrypted' in some form. What is the best practice for changing an ID into some uninterpretable string that I frequently see done on other websites?
Thank you for any help.
why don't you just use a middleware that check if the route can be acceded by the user? then you can call it with
$this->middleware('middlewareName');
in the controller that you need it or even in the web.php if you want a whole set of routes protected
I want to implement a tracking system for monitoring users' activity within the application.
The application is currently used within the business hours by about 600-2000 users.
I originally wanted to use a before_filter to the ApplicationController where every time a user would click a link, I'd save information such as user/admin id, params[:controller], params[:action] and other params of actions to the database. (I know about gems like audited - but not sure if I use them).
However I am wondering if I basically don't kill the app when for every click within the system will be called database to insert some data into it.
I was thinking of using a background method (sidekiq) for logging the action into the database.
Basically:
class ApplicationController
before_filter :log_request
def log_request
RequestLogger.perform_async(params[:controller], params[:action], current_user.id)
end
end
class RequestLogger
include Sidekiq::Worker
def perform(controller, action, user_id)
# Save data to the database
end
end
More or less.
I'd urge you to use a logfile. Compresses easily and then you can process entire logfiles in a batch. Just update Rails to log the session ID and you can track individual sessions.
I'm building an application that stores files into the FIWARE Object Storage. I don't quite understand what is the correct way of storing files into the storage.
The code python code snippet below taken from the Object Storage - User and Programmers Guide shows 2 ways of doing it:
def store_text(token, auth, container_name, object_name, object_text):
headers = {"X-Auth-Token": token}
# 1. version
#body = '{"mimetype":"text/plain", "metadata":{}, "value" : "' + object_text + '"}'
# 2. version
body = object_text
url = auth + "/" + container_name + "/" + object_name
return swift_request('PUT', url, headers, body)
The 1. version confuses me, because when I first looked at the only Node.js module (repo: fiware-object-storage) that works with Object Storage, it seemed to use 1. version. As the module was making calls to the old (v.1.1) API version instead of the presumably newest (v.2.0), referencing to the python example, not sure if that is an outdated version of doing it or not.
As I played more with the module, realised it didn't work and the code for it was a total mess. So I forked the project and quickly understood that I will need rewrite it form the ground up, taking the above mention python example from the usage guide as an reference. Link to my repo.
As of writing this the only methods that aren't implement is the object storage (PUT) and object fetching (GET).
Had some addition questions about the Object Storage which I sent to fiware-lab-help#lists.fiware.org, but haven't heard anything back so asking them here.
Haven't got much experience with writing API libraries. Should I need to worry about auth token expiring? I presume it is not needed to make a new authentication, every time we interact with storage. The authentication should happen once when server is starting-up (we create a instance) and it internally keeps it. Should I implement some kind of mechanism that refreshes the token?
Does the tenant id change? From the quote below is presume that getting a tenant I just a one time deal, then later you can use it in the config to make less authentication calls.
A valid token is required to access an object store. This section
describes how to get a valid token assuming an identity management
system compatible with OpenStack Keystone is being used. If the
username, password and tenant details are known, only step 3 is
required. source
During the authentication when fetching tenants how should I select the "right" one? For now i'm just taking the first one similar as the example code does.
Is it true that a object storage container belongs to only a single region?
Use only what you call version 2. Ignore your version 1. It is commented out in the example. It should be removed from the documentation.
(1) The token will be valid for some period of time. This could be an hour or a day, depending on the setup. This period of time should be specified in the token that is returned by the authentication service. The token needs to be periodically refreshed.
(2) The tenant id does not change.
(3) Typically only one tenant id is returned. It is possible, however, that you were assigned more than one id, in which case you have to pick which one you are currently using. Containers typically belong to a single tenant and are not shared between tenants.
(4) Containers are typically limited to a single region. This may change in the future when multi-region support for a container is added to Swift.
Solved my troubles and created the NPM module that works with the FIWARE Object Storage: https://github.com/renarsvilnis/fiware-object-storage-ge
I have a custom permission model for my project and I'm not using django's default permissions backend. I have a custom has_permission template tag to check if the user has the specified permission or not.
The problem is that there's lots of queries done for the same checks every time, I'm looking for a way to reduce my Permission queries. What I'm doing inside my templates is like :
{% if user|has_permission:'jpermission.can_edit_jpermission' or
user|has_permission:'jgroup.can_edit_jgroup' or
user|has_permission:'role.can_edit_role' %}
and the code for has_permission template tag is as follows :
rep = perm_name.split('.') # rep is for e.g. "jpermission.can_edit_jpermission"
ctn_type = rep[0]
codename = rep[1]
pr = JPermission.objects.filter(model_name=ctn_type, codename=codename)
if pr.exists():
if user.has_perm(pr[0]):
return True
Specifically talking, the problem is that every time i check even for the exactly same if statements, lots of queries are made (from what I'm doing, it's obvious there will be).
Is there any other way i can go at it ? like query all permissions once, cache them, and do something like how prefetch_related is handled to prohibit further db queries (python filtering with loops and ... ) ?
P.S: has_perm is also overridden and checks if users role, group or permissions have the specified permission or not)
There are multiple solutions for this.
Move permissions to user model as methods of model and use cached_property decorator so that consecutive calls to methods does not hit database again.
Store the permissions state in session when user logged in, and later use session data to check for permissions.
It looks like you are using django-guardian, and it is already caching the permissions:
Once checked for single object, permissions are stored and we don’t
hit database again if another check is called for this object. This is
great for templates, views or other request based checks (assuming we
don’t have hundreds of permissions on a single object as we fetch all
permissions for checked object).