How to properly implement quota reached functionality in rails - ruby-on-rails

I was wondering on how to properly and cleanly implement quota reached functionality in my SaaS depending on the plan the workspace is on.
Solution 1 (my first pick):
I was thinking of using the fail early principle and checking the user quota inside of the rails controller.
# ClientsController
before_action :check_quota_limit, only: [:create]
# ApplicationController
rescue_from MySaaS::QuotaLimitReached, with: :quota_limit_reached
Solution 2:
The other solution I was thinking of is doing it inside of the model. But this has a few drawbacks since you can easily bump into N+1 queries while validating + you don't always have the current user available through a model. Which would result in multiple queries just to be able to save this model.
# Client
class Client
validates :quota_limit_reached
end
I'm leaning towards solution 1 but I just want to see if anyone else has something that didn't cross my mind yet.

Related

Updating attribute on get request?

I have a situation where I would like to update an attribute when a certain third party fetches data from my api's endpoint.
Currently, I've set this up as follows
module Api
module V1
class ListingsController < ApplicationController
http_basic_authenticate_with name: "third_party_user", password: "secret", except: :index
before_action :update_status, only: [:publishable_listings]
def publishable_listings
#listings = Listings.where(to_publish: true)
end
private
def update_status
listings = Listings.where(to_publish: true).update_all(published: true)
end
end
end
end
and this is just the route
...
get 'publishable_listings' => "listings#publishable_listings"
...
Is this considered bad practice or could there be an alternative way to accomplish this?
Basically, this assumes that the only GET requests coming to publishable_listings would be from third_party_user and if anyone else would be able to make a GET this would be problematic since it would update the record without actually being published.
I think this question would fit better into https://codereview.stackexchange.com/tags/ruby.
Is this considered bad practice or could there be an alternative way to accomplish this?
Basically, this assumes that the only GET requests coming to publishable_listings would be from third_party_user and if anyone else would be able to make a GET this would be problematic since it would update the record without actually being published.
With your current architecture using basic auth, I don't see a different way of implementing this. Assuming that only your third party will ever know the password, this might be fine.
However, if you would introduce a concept of user, you would be able to only mark publishing for a user as published / read. You could implement this with a many to many relationship.
Another way of implementing this could be to just use curser based pagination and store the latest cursor in your client. This way, your client could go back and it's easier to debug and reason about.
https://slack.engineering/evolving-api-pagination-at-slack/
A few more suggestions
To keep your controller simple, you should only have the basic REST methods in your controller (index, show, new, create, edit, update, delete). In your case, you could have a PublishableListingsController with a show method instead of ListingsController with a publishable_listings.
See this great article for more details http://jeromedalbert.com/how-dhh-organizes-his-rails-controllers/.
Also the assignment to listings here is not really used and I would recommend to do this not an a before action, because, if your second query fails, you will end up with listing which are already marked published but where never actually received.
def update_status
listings = Listings.where(to_publish: true).update_all(published: true)
end
Ideally you want to do this in one operation or transaction.
def show
#listings = Listings.where(to_publish: true)
#listing.update_all(published: true)
end

Passing rails requests through a series of controllers?

The question is generalized but I want to ask about a specific case which I want to solve.
I'm working with a really really smelly code base of e-commerce app and I want to refactor it. I thought I should start with the User authentication.
Problem
Before every action in any controller, we check if the user is of a particular type: Guest, Signed-In or Admin and also, if the user is allowed to access this action based on the type. If all the conditions are met, then the action is executed. And this happens in majority of the actions in majority of the controllers.
My thinking
I know this code is smelly because checking if the user is of a particular type and (s)he has access to an action is not the action's responsibility.
My solution which may or may not be possible
We can make a SessionsController (or some other name) and let it handle the authentication and authorization part. But I want the SessionsController to do its job automatically before every request. i.e. Every request should go through the SessionsController and then this controller will decide whether or not to forward the request to the appropriate controller.
I search Google for this but didn't find anything. So my logical conclusion is that passing a request through a series of controllers might not be possible. But I'm not sure. So if it is possible, guide me how to do it. And if it is not possible, then suggest any other way to do it.
This sounds like a perfect example in which one or multiple before_action can be used. You can place a before_action in your ApplicationController:
# in app/controllers/application_controller.rb
private
def authorize_admin
render status: 401 unless current_user? && current_user.admin?
end
Then you can declare in any controller in which you want to run this method before running any action.
# in any controller - even the ApplicationController
before_action :authenticate
You can configure before_action to only run on certain conditions or with certain actions. Just a have a look at the how to use Filters in the Rails Guides.

Multi-tenant Rails app and restricting access to controllers

I am using Devise for authentication, and I have "modules" in my rails app. I am trying to figure out the best approach to security. For example, here are the few things that I want to accomplish:
I want the application controller to require login, unless they are accessing the registrations controller, in which case they are just submitting registration details.
On the application level, I would like to define scopes, permitting access to certain controllers that the user's company has access to.
Additionally, on each request, I want to verify that any IDs in the URL (whether it's a GET, POST, whatever), the user's company has access to that controller and ID in the parameter. (So they can't access Report ID 9 if their company doesn't have a report ID 9 associated with it)
I feel like this may be scalable, but I've never done this before so I'm not quite sure.
Bullet 1
In the ApplicationController, I would like to do something like this:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :authenticate_user! unless controller == "Registrations"
end
I tried placing a binding.pry in the application controller, but the controller_path seems to always be application. Not sure if there's an easy way to accomplish this without going to each individual controller, which I'm hoping to avoid because I don't want to accidentally forget something when I add a new controller down the road (basically going against DRY).
Maybe I can implement a security controller and have every controller inherit from it? Never did this before but this might work if I can't accomplish what I'm trying to do in the Application Controller.
Bullet 2
I have tried to access Devise's current_user variable from the Application Controller, but it does not exist, so I'm not sure if I can check the user's permissions from the ApplicationController. Again, I'd love to avoid having to place this check in each controller because as the application expands, I may eventually forget to implement checks.
EDIT
So it looks like I have bullet 1 addressed, but now I'm trying to figure out the other 2. Being able to implement some type of "scope" or permission module at the application level. Any ideas?
The skip_before_action directive can suppress execution of a before_action filter that's already defined. You can use this to turn off an action for a controller:
class ApplicationController < ActionController::Base
before_action :authenticate_user!
end
class RegistrationsController < ApplicationController
skip_before_action :authenticate_user!
end
The thing to note here is Ruby is a highly dynamic programming language and code can be executed while the class is being defined. It's important to pay close attention to when certain statements are run, as things like unless, the statement, tend to run immediately when in that context.
You'll see some others that allow deferred execution like in ActiveRecord with:
validates :name, unless: :anonymous?
Where that validates method has a specific option called unless which is distinct from the keyword unless. That defines a validation trigger with a condition attached to it.
On the other hand this code, while visually similar, is completely different:
validates :name unless anonymous?
This depends on a method called anonymous? being available at the class level and if it returns a non nil or false value will execute the validates function.

Logging Feature Usage in Rails App

I'm interested in logging information about what features users are using in my Rails app. I know of existing Gems for performance metrics, logging user activity (e.g., public_activity), or more general analytics (e.g., google analytics), but what I'm looking for is a bit difference.
For example, if I have a feature that enables users to export their data, what service would you recommend to keep track of how many users (and which users) are using this feature?
Simple option would of course be to write a another model (for example Activity) that keeps track of the usages:
class Activity < ActiveRecord::Base
# attributes for resource (export, in this case), action type (Excel export) and user id
end
Then it could be applied with before_filter on your ExportController:
ExportController < ApplicationController
before_filter :register_activity
def register_activity
ExportActivity.create { } # Apply the params here
end
end
This way also provides you with the possibility to easily access the data and make statistics about it as you have it under your own control.

Create basic RESTful API Server to a datastore

I have the most basic of questions, but the more I think about it, the more complex it gets.
I've been using rails and it follows the MVC paradigm in that db and api calls are abstracted through calls generated through the controller. This seems way too heavy for what I want.
1) I want a simple (basic) web server that sits in front of my datastore. (The contents of which happen to be stored in a directory structure that follows: /LOCATIONS/LOCATION/PRESENTERS/PRESENTER/YEAR/MN/)
2) I want to be able to host json files within that directory structure and GET them as needed.
3) I want to be able to PUT/POST append to those json files.
Seems like all I'd need is nginx with my datastore as a doc root and index.html files at critical places within the structure (e.g. site.com/Locations/index.html , site.com/locations/SF/presenters/solomon/index.html)?
How would I begin to solve this problem, (without the use of controllers of coarse)?
MVC Frameworks
without the use of controllers
You must be aware that there are many more frameworks than Rails out there, so when you ask about using a system to "sit in front of your datastore", you're really looking for different frameworks to handle requests, of which there are many.
The problem you have is how do you keep data consistency, whilst ensuring you can handle the relevant API requests (through JSON). The answer is to look at how the systems you're examining work.
I can only really vouch for Rails (it's the only framework I've got production apps for) -
--
Rails
Creating an API in Rails is so simple - I don't know why you'd think about doing anything else
Using the MVC principle might seem bloated to you, but the security, structure and extensibility it provides is unmatched.
Here is how to create an API in Rails:
#config/routes.rb
namespace :api do
resources :controller, only: [:update, :create] #-> only PUT / POST
end
#app/controllers/api/your_controller.rb
class API::YourController < ApplicationController
respond_to :json
def update
# handle PUT request
end
def create
# handle POST request
end
end
#app/models/model.rb
Class Model < ActiveRecord::Base
end
This is all you need - you'll be able to access domain.com/api/controller.json POST to create data, and domain.com/api/controller/4.json PUT to update it :)

Resources