geocode_ip_address except specific controllers - ruby-on-rails

I have added geocode_ip_address in ApplicationController so I can get the user location info from their session.
I have some controllers that I don't want them to be checked against Geokit. It really slows application and there's no need for geo check there.
Since its called like geocode_ip_address and not as a before_filter I'm not able to use skip_before_filter
Any idea?

it actually uses store_ip_location filter so you can put
skip_before_filter :store_ip_location
That being said it stores the result of the geo code inside a cookie that is being checked before making a service call so the subsequent calls should not impact performance that much

You can selectively NOT INVOKE the code based on the controller you're in like so:
unless ["controller1", "controller2", "etc"].member?(params[:controller])
geocode_ip_address
end
Put the names of the controllers you don't want the code to run for in the list and it won't be invoked in those controllers.
You could also create a constant that's a list of controllers like this:
CONTROLLERS_TO_NOT_FILTER_BY_GEOCODE = ["controller1", "controller2", "etc"]
unless CONTROLLERS_TO_NOT_FILTER_BY_GEOCODE.member?(params[:controller])
geocode_ip_address
end

Related

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.

Ruby on Rails - Controller without Views

Iam new in Ruby on Rails. Normally I work with other web languages and now (of course) I try to compare it with other languages using on web.
But sometimes i have some problem to understand the philosophy and the character of Ruby on Rails. Of course i understand the concept of MVC.
But now Iam not absolutely sure:
Is ist OK to create and use a controller without views? In some cases you need a "class" for some usefull functionality used by other controllers they have views. Or is it a better style to use a module?
I try to find it out by reading a lot of articles and examples, but didnt find detailed information about this content.
When developing Ruby On Rails apps, it's recommended to put most of your business logic in the models, so for the controllers the logic need to be minimal to provide info for the views, so if it doesn't work with a view chance that you need a controller are really low.
Is it OK to create and use a controller without views
Yep it's okay.
The key thing to keep in mind is that Ruby/Rails is object orientated.
This means that every single you do with your controllers/models etc should have the "object" you're manipulating at its core.
With this in mind, it means you can have a controller without corresponding views, as sometimes, you just need to manipulate an object and return a simple response (for example with Ajax).
--
We often re-use views for different actions (does that count as not having a view):
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def search
render :index, layout: false
end
end
The notion of skinny controller, fat model is sound in principle, you have to account for the times when you may need small pieces of functionality that can only be handled by a controller:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def update
#user = User.find params[:id]
#user.update
respond_to do |format|
format.js {render nothing: true}
format.html
end
end
end
A very rudimentary example of Rails is a drive-thru:
view = input interface
controller = accepts order & delivers
model = gets order packaged etc in backend
There are times when the controller may not need a view (for example, if you update your order with specific dietry requirements), and thus the notion that every controller action has to have a view is false.
It's really about making your controller versatile enough to manage your objects correctly.
Shared controller methods can be placed in ApplicationController. Also, in Rails 4 there are concerns (app/controllers/concerns/) where you can put the modules with methods that can be used by multiple controllers.
Controller handles request and renders corresponding view template. So controller without view is absolutely nonsense.
Every time request will execute this controller, it will just end with missing template error, so you will need to create view folder and put empty files with action name inside of it, which is obviously stupid.

Package instance variables in rails controllers?

I'm overwhelmed by managing instance variables in controllers so am thinking if there's a better way to manage them.
My situation is, I'm having a PagesController that handles the front page rendering. In the front page, I have multiple small forms that originally belong to different controllers (For example, make a new post form, and there's a PostsController dedicated for it but for convenience you can make an easy post just at the front page.) and they all need their corresponding instance variable to hold the form (e.g. new post form needs a #post object).
It turns out to me, that I have to manually add these instance variables into my PagesController#index in order to make the forms work, so many lines become just
#post = Post.new # similar for other objects
#some_other_var = OtherController.new # another one
#one_more = AnotherController.new # again
# even more #variables here when the website is big
If this doesn't seem bad enough, think about when create or edit action fails (e.g. does not pass validation) and we need to render the previous page. We need to add these lines AGAIN. Actually we need to include ALL THESE VARIABLES whenever there's a render.
It seems very cumbersome to manually type such code to every action that needs them and it's so easy to just miss one or two of them when the website gets complicated.
So I'm wondering if there's a better way to manage such variables so that we only need to include them once instead of writing the same code every time.
You can create a before_filter something like:
class ApplicationController < ActionController::Base
...
...
protected
def instance_variables_for_form
#post = Post.new # similar for other objects
#some_other_var = OtherController.new # another one
#one_more = AnotherController.new # again
# even more #variables here when the website is big
end
end
and use it like:
class PagesController < ApplicationController
before_filter :instance_variables_for_form, only: [:action]
...
...
end
and then you can call it explicitly too from any action whenever needed.
If those variables can be logically grouped, you should consider putting them into Presenter objects.
Here is a good blog post explaining the idea: http://blog.jayfields.com/2007/03/rails-presenter-pattern.html

Getting the current request in rails from a file in lib/

I've put all of my user-authentication code in one place, namely lib/auth.rb. It looks like this:
lib/auth.rb
module Admin
def do_i_have_permission_to?(permission)
# Code to check all of this goes here
end
end
I include this module as part of the application helper, so these functions are available in all the views:
application_helper.rb
require 'auth'
module ApplicationHelper
include Admin
# other stuff here
end
And I also include it as part of the application controller, so the controllers likewise can call the functions:
application.rb
require 'auth'
class ApplicationController < ActionController::Base
include Admin
end
So far, so good.
The problem is that my application is not like a normal web app. Specifically, more than one user can be logged into the system from the same computer at the same time (using the same browser). I do authentication for actions by looking at all the people who are logged in from that IP and if they can all do it, it passes.
What this means is that, if an admin wants to do something, that admin has to log everyone else out first, which is annoying. But we want the admin seal of approval on everything the admin does. So the suggestion given to me was to have it so the admin can supply a username/password combo on any page they would not normally have access to (e.g. an 'edit user' page would have these extra input fields) and the authentication routines would check for that. This means
Admin::do_i_have_permission_to?(permission)
needs to get at the current request parameters. I can't just use params[:foo] like I would in a controller, because params isn't defined; similarly request.parameters[:foo] will also not work. My searching has revealed:
The current search parameters are in the current request,
The current request is in the current controller,
The current controller is in the current dispatcher, and
I'm not sure the current dispatcher is kept anywhere.
That said, experience tells me that when I'm jumping through this many hoops, I'm very probably Doing It Wrong. So what is the right way to do it? Options I've considered are:
Just move all the functions currently in auth.rb into the ApplicationHelper where (I think) they'll have access to the request and such. Works, but clutters the hell out of the helper.
Move all the functions somewhere else they'll see those methods (I don't know where)
I'm just plain missing something.
In a typical Rails application, authentication information is stored in the active session, not the parameters. As such, it's pretty straightforward to write a helper that does what you want.
It seems rather unorthodox to create a module that is then included in ApplicationHelper. The traditional approach is to create a separate helper which in this case would probably be called AuthenticationHelper. This can then be included in any required controllers, or if you prefer, loaded into ApplicationController to make it available universally.
In general terms, Helpers should not include other Helpers. It is better to simply load multiple helpers into a given Controller.
Helper methods have full access to any instance variables declared within the controller context they are operating from. To be specific, these are instance variables only (#name) and not local variables (name). Helper methods are executed for a particular view as well.
Further, I'm not sure why a user would be providing credentials and performing an operation in the same step, at least for traditional web-based apps. Usually the process is to log in and then perform an action separately.
However, in the case of an API where each transaction is an independent operation, the most straightforward approach is to do is pull out the relevant request parameters that deal with authentication, establish some controller instance variables, and then proceed to perform the particular request given the constraints that the credentials impose.
The approach I usually follow for this sort of thing is to layer in an authentication structure in the ApplicationController itself which can perform the required checks. These are protected methods.
While it's tempting to roll in a whole heap of them such as can_edit_user? and can_create_group? these very quickly get out of hand. It is a simpler design to put in a hook for a general-purpose can_perform? or has_authority_to? method that is passed an operation and any required parameters.
For example, a very rough implementation:
class ApplicationController < ActionController::Base
protected
def has_authority_to?(operation, conditions = { })
AuthenticationCheck.send(operation, conditions)
rescue
false
end
end
module AuthenticationCheck
def self.edit_user?(conditions)
session_user == conditions[:user]
end
end
class UserController
# ...
def edit
#user = User.find(params[:id])
unless (has_authority_to?(:edit_user, :user => #user))
render(:partial => 'common/access_denied', :status => :forbidden)
end
rescue ActiveRecord::RecordNotFound
render(:partial => 'users/not_found')
end
end
Obviously you'd want to roll a lot of the authority checks into before_filter blocks to avoid repetition and to promote consistency.
A full framework example might be of more help, such as the Wristband user authentication system:
http://github.com/theworkinggroup/wristband/tree/master

Resources