Keeping object across controllers - ruby-on-rails

I am playing with the heroku api in Rails and have come across a potential issue.
After submitting a login form i am instantiating the heroku object.
heroku = Heroku::API.new(:username => USERNAME, :password => PASSWORD)
I would then like to use the heroku object in all controllers to further querying the api. I have tried #heroku, ##heroku and $heroku, but none work. Is this possible?
The only solution i have found it to use the api to fetch the users api key, store this in a session then use it to re-instantiate the heroku object within each controller method. Is this the best / only solution?

In general, a before_filter could solve your re-instantiating problem. If you want to set an instance variable that is available to every controller method, do something like this:
class UsersController < ApplicationController
before_filter :get_user
def profile
# #user is accessible here
end
def account
# #user is accessible here
end
private
def get_user
#user = User.find(params[:id])
end
end
You can also user before_filters in the application controller to set instance variables that are accessible in all of your controllers. Read about filters here.
As for storing the API keys to the session, that works, but if you want long term access, you might want to write the API keys to the database. Combined with before filters, you could do something like this:
class ApplicationController < ActionController::Base
before_filter :setup_heroku
def setup_heroku
if current_user && current_user.heroku_api_key
#heroku = Heroku::API.new(:api_key => current_user.heroku_api_key)
end
end
end

Related

Devise not calling overridden function - Ruby on Rails

I'm trying to store a list of permissions within a session variable after a user signs up or logs in to their account. The following code only works when a user logs into a currently saved account. What method do I need to override to save the permissions when the account is created via sign up?
class UserSessionsController < Devise::SessionsController
after_action :after_login, :only => :create
def after_login
session[:permissions] = current_user.list_permissions
end
end
class Users::RegistrationsController < Devise::RegistrationsController
after_action :after_signup, :only => :create
def after_signup
## your data permissions
end
It might be necessary to inject via resource. In this case try (i commented it out quickly, just in case you wondering whats going on):
class Users::RegistrationsController < Devise::RegistrationsController
def create
## GET THE SIGN UP DATA
super do |resource|
##CHECK IF DATA IS VALID
if params[:your_data]
##SET THE RESOURCE TO THE DATA
resource.your_data = params[:your_data]
##CHECK (IF NECESSARY) DATA TO TYPE
if resource.you == 2
## SAVE IT
resource.save_with_your_data
## SAVE WITH STANDARD SETTINGS
else
resource.save
end
end
end
end
end
What method do I need to override to save the permissions when the account is created via sign up?
It seems like you want to store this information in the database when the user is created. Remember that current_user will give you the entire database record in the object, and then you can do whatever you need with it. I wouldn't recommend messing the session directly, instead, work with the current_user object that Devise provides.

Write the cookie in the model method or in the controller?

A controller method calls upon a model method to generate a token. Inside the controller method the generated token is also saved in a cookie: cookies.permanent[:remember_token] = user.remember_token.
Would it not be better to include this last line in the model method that creates the token? It is DRYer since I have more than 1 controller with this same behaviour (using the same model method). And the risk that I would forget these cookies lines is lower. Or is it not possible to execute this command in a model method?
Update: I think it's not possible to do this in a model method because there it's not known to which user/computer to write the cookie to?
Models should have no knowledge about concepts like a user's cookie. It's really a controller thing.
If you're using the line across different controllers, you could move it into the ApplicationController:
class ApplicationController < ActionController::Base
def store_remember_token(user)
cookies.permanent[:remember_token] = user.remember_token
end
end
And then reuse it in your controllers:
class SomethingsController < ApplicationController
def show
#user = # ...
store_remember_token(#user)
end
end

Refactoring editing user in Rails

Im working with a medium sized Rails application and I do this in every controller:
def create
#object = Model.new(params[:model].merge(editing_user: current_user))
...
end
def update
#object = Model.find(params[:id])
#object.editing_user = current_user
...
end
Setting the editing user over and over again is not DRY. I thought about cleaning this up with an observer but it would need access to the current user. Observers do not have access to the current user, neither should they (Law of Demeter).
Any suggestions how to DRY this up between controllers?
class ApplicationController < ActionController::Base
before_filter :init_request
def init_request
params[:editing_user] = current_user
end
end
I like using decent_exposure to dry up my controllers. It automatically finds or initializes a model instance, based on whether an :id was passed as a param, and it assigns the attributes from params[:model].
To finish drying up your code, you could use the new strategy support (see the end of the readme) to automatically set the editing_user attribute on your model.
You could try an after_filter for this. Perhaps something like so:
class ApplicationController < ActionController::Base
after_filter :set_editing_user
def set_editing_user
#object.update_attribute(:editing_user, current_user) if #object && current_user
end
The difficulty, of course, is that you'll be saving the object twice per call. Generally though creations and updates don't happen so frequently that two database commits is a serious problem, but if you expect to be the next Twitter -- with massive database insertion load -- it could be an issue.
You could also possibly set this in a before_filter, but then you'd have to find or set the object in a previous before_filter. Otherwise #object will always be nil and the before_filter will never fire. You can use the filter ordering methods prepend_before_filter and append_before_filter to ensure the correct sequencing of these filters.

Rails: Verify correct user across multiple controllers

I have several controllers that require a correct user for their edit/update/delete actions. What is the Rails-way to accomplish the following:
Currently, in each controller I have the following code:
class FooController < ApplicationController
before_filter :correct_user, :only => [:edit, :update, :destroy]
# normal controller code
private
def correct_user
#foo = Foo.find params[:id]
redirect_to some_path unless current_user == #foo.user
end
end
I have similar code in 3 controllers. I started to bring it out to a helper like this:
module ApplicationHelper
def correct_user( object, path )
if object.respond_to? :user
redirect_to path unless object.user == current_user
end
end
But I'm wondering if this is a good way to do it. What's the accepted way to solve this?
Thank you
EDIT
The correct user check here is because I want to make sure it's only the author who can make edits/deltes to each of the objects.
To clarify, the objects would be things like Questions and Posts. I don't want to use something like CanCan as it's overkill for something simple like this.
I really like using RyanB's CanCan, which allows you to both restrict access to actions based on the user, and centralize such authorization into basically a single file.
CanCan on GitHub: https://github.com/ryanb/cancan
Screencast explaining how to setup/use it: http://railscasts.com/episodes/192-authorization-with-cancan
EDIT
No problem. I hear you on CanCan - it takes a little while to get up and running on it, but it's designed to do exactly what you're asking - per object authorization.
Alternative:
Another way to do this is move your authoriship/current_user check to the ApplicationController class, from which all of your other Controllers inherit (so they will get that code through inheritance - and you don't need to write the same code in multiple Controllers), and it would look something like...
class ApplicationController < ActionController::Base
...
helper_method :correct_user
private
def correct_user( object, path )
redirect_to path unless object.user == current_user
end
end
You should do the following :
def edit
#foo = current_user.foos.find(params[:id])
end
This way, only if the current user is the owner of the Foo he will be able to see it.

preserve object ruby on rails

I have an object in ruby on rails for #user which contains username, password, etc
How can I ensure that the values are kept throughout all views?
Thanks
If you set it up as follows:
class ApplicationController < ActionController::Base
before_filter :set_user
protected
def set_user
#user = User.find_by_id(session[:user_id])
end
end
Then in all of controller, since they all inherits from ApplicationController, will have the #user value set.
Note: this will set the #user to nil if the session[:user_id] as not been set for this session.
For more on filters and the :before_filter, check this link out: Module:ActionController::Filters::ClassMethods
I take it you want some sort of user sustem? logged in and tracking all over your system?
AuthenticatedSystem is something that can help you. there is a lot of documentation out their that will tell you exactly how to setup an environment that uses it. I personally use if for several systems I've made.
In your ApplicationController, add your object to the session and create a variable for it. Add a before_filter that calls the method that does that.

Resources