How to keep a variable handy across a number of controllers - ruby-on-rails

I've moved an application to using ActiveResource and I'm finding that I need to rethink the way I've taught myself to do some things, and I'm searching for the best way to go about this.
For example, I need to keep a query handy say #current_account which I've done as
#current_account ||= Account.where(etc etc)
in an applicationcontroller.rb for a certain scope. This isn't all that useful with AR, because the call to the API is made each time. I'd like to minimize calls to the api (especially where I have other more expensive calls I don't want run on every query, I want to run them once and keep them handy)
So, what is the Rails way? I have to keep a variable with an AR call to an API handy from the ApplicationController in a certain scope, across several other controllers without having to write it out each time (or call the API each time, or put it in a user accesible session because it isn't exactly text/strings, it is objects I need to use).
I'm curious about how others do this, if I should or should not be doing this, what is the right DRY way, etc. So this is somewhat open-ended.
Any input appreciated.

It's best to create a module for this kind of behavior:
module CustomAuth
def self.included(controller)
controller.send :helper_method, :current_account, :logged_in?
end
def current_account
# note the Rails.cache.fetch. First time, it will
# make a query, but it caches the result and not
# run the query a second time.
#current_account ||= Rails.cache.fetch(session[:account_id], Account.where(...))
end
def logged_in?
!current_account.nil?
end
end
Then, make sure that Rails loads up this file (I put mine in ./lib/custom_auth.rb), so add that to the config.autoload_paths in ./config/application.rb:
# ./config/application.rb
...
config.autoload_path += %W(#{config.root}/lib)
...
Import the CustomAuth module into your application_controller.rb:
class ApplicationController < ActionController::Base
include CustomAuth
protect_from_forgery
...
end
Finally, Crucial: Restart your server
NOTE: You can add additional methods to the custom_auth.rb. If you restart the server, they will be available. These methods are also available in the view, so you can call current_account.name right inside a view.

Related

Rails building an API without duplicating code

Lets say I have a PeopleController which my users can access when they login to my app
class PeopleController < ApplicationController
def create
# stuff here
end
end
And then my boss tells me we need an API, so we go with something like this in addition to what we already have:
class API::V1::PeopleController < ApplicationController
def create
# stuff here
end
end
Is it unusual to have code duplication like this? Should I be looking for a way to DRY this up? I don't mind a bit of duplication but it looks like I'm going to have to make 99% of our existing codebase available through the API.
What your boss is asking of you is to implement versioning. Versioning is quite useful particularly to ensure backward compatibility of API endpoints.
In such situations, the duplication of code might turn out to be a necessary evil since you wouldn't want updated code in later versions that alter functionality to cause issues in earlier versions.
There are gems such as Versionist that help you out with the process of versioning so that much of the process of duplicating the code and adding the required namespacing is done automatically.
The "Rails way" is one controller, which knows how to respond to JSON and HTML. This is why you have respond_to/respond_with/etc.
There's no reason to spin off a second API controller unless you actually want to have your API and non-API controllers diverge.
If you simply want to route /api/v1/people to the same place as /people, that's a job for your config/routes.rb. If you want to add/change behavior in the API on top of the regular controller's behavior, then you can inherit your API controller from your non-API controller:
class API::V1::PeopleController < ::PeopleController
If its basic crud, you can have the same controller respond to html(for your website) and xml or json format(for your api)
class PeopleController < ApplicationController
def create
respond_to do |format|
format.xml {render :xml => #people}
format.html {redirect_to people_path(#people)}
end
end
end
You can adjust your route based on the format if you want your routes to look different for api
If you API might change over the lifetime the application and requires versioning then you need two different controllers.
However, if you API is maybe for the mobile application do not have multiple users and wont require frequent re-visioning then have a simple controllers and simply user respond_with and respond_to.

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

How do I dynamically add an after filter to Rails from within a controller action?

Each time a user accesses a page in my Rails app, the database needs to send them a Thingy. When the database runs out of Thingies, it has to do some expensive processing to generate more. I want to add a controller filter dynamically to generate the thingies after the response has been sent to the user so that it doesn't affect page load times. Here's what my controller looks like:
class ThingyController < ApplicationController
def get_a_thingy
if Thingy.count <= 5
# Only five thingies left! we need to generate some more.
# I want to dynamically send a block to an after_filter: here to
# generate thingies after the controller sends the response
# because generating thingies is really slow
end
# Pop the first thingy from the database and return
thingy = Thingy.first
thingy.delete
return thingy.content
end
What can I add in the get_a_thingy function to make this happen?
You may try some background processing tools( https://www.ruby-toolbox.com/categories/Background_Jobs check this), cause I'm not sure you can do it inside a request handler.
You may also try to return all the content to user (via smthing like http streaming) and only then make your heavy things.
Just put the if statement that checks for the number of thingies in your after_filter code:
class ThingyController < ApplicationController
after_filter :generate_new_thingies
def get_a_thingy
thingy = Thingy.first
thingy.delete
return thingy.content
end
def generate_new_thingies
if Thingy.count <= 5
# Generate thingies
end
end
end
Does using after_filter really prevent long page loads? It may be better to have a look at something like Delayed Job or Whenever.
Probably the best idea will by a gem like delayed_job there is also a railscast for it.
Delayed job is an asynchronously priority queue system.
Install and setup the delayed_job. It is pretty well documented on the github page.
Start the worker with rake jobs:work
Now simply change your code to use the delay job by adding the .delay method
class ThingyController < ApplicationController
after_filter :generate_thingies
.
.
.
def generate_thingies
if Thingy.count <= 5
#change
Thingy.generate_thingies
#to
Thingy.delay.generate_thingies
end
end
end
NOTE: This is a small tutorial and I left out a some of things that you will need to get it working. I recommend you to check the Github page for a full documentation.

Rails Game Loop in Application Controller?

Since i'm writing a game in RoR, i need to have a game loop that is responsible for checking different things every time a page refresh happens. My question is, what is the best way to implement ?
I currently include the game_loop in my application controller. Is this the best practice ?
Executing the game look as a before_filter in your ApplicationController sounds reasonable, although you may not wish to put your logic in this class:
class ApplicationController < ActionController::Base
before_filter :do_game_loop
private
def do_game_loop
Game.do_game_loop # the implementation of Game is in another file, maybe in lib
end
end
Do note that this will execute the game loop before every action in your application that involves a controller that extends from ApplicationController, including user login, logout, etc. It may be better to add the before_filter only in the controllers that definitely need to process the game loop.

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