I'd like to change the application time zone when current_user (Devise) is initialized, like this:
Time.zone = current_user.settings(:main).time_zone
What is the best place in the app to put this code at (application controller, before_filter is not a solution)?
I think the safest approach here would be to use the around_action like such, make sure to specify which action you want this to happen on:
class SomeController < ApplicationController
around_action :set_time_zone, only: :show
private
def set_time_zone
if current_user
Time.zone = current_user.settings(:main).time_zone
end
yield
end
end
Related
I have read this post https://nvisium.com/blog/2014/09/10/understanding-protectfromforgery/ and if I understood correctly, by default in Rails 3 if we have a controller that looks like:
class ApplicationController < ActionController:Base
protect_from_forgery
end
What will end up happening is that (in case of an attacker) the session will be destroyed. That would mean that if we are doing something like checking if the user is authenticated, since there would be no session, it will stop the request.
So, my question is, I believe that this:
class ApplicationController < ActionController:Base
protect_from_forgery
before_action :authenticate_user
private
def authenticate_user
raise NotAuthenticated unless session.key?(:user)
end
end
Is the proper way of doing it, instead of
class ApplicationController < ActionController:Base
before_action :authenticate_user
protect_from_forgery
private
def authenticate_user
raise NotAuthenticated unless session.key?(:user)
end
end
Or in other words, protect_from_forgery should be the first thing that we do in a controller.
Are my assumptions correct, or I am missing something on how the order of operations work in the controller?
The order of those two methods is not important, no.
The reason has to do with when those methods get executed: those are Class-level methods that are executed in the context of the class itself when Ruby loads the file.
Look at the source for protect_from_forgery:
def protect_from_forgery(options = {})
options = options.reverse_merge(prepend: false)
self.forgery_protection_strategy = protection_method_class(options[:with] || :null_session)
self.request_forgery_protection_token ||= :authenticity_token
before_action :verify_authenticity_token, options
append_after_action :verify_same_origin_request
end
These are basically macros that add code to your class when they are invoked, a form of metaprogramming. You could replace the method call in the class with setting those things manually and it would be the same.
This all happens when your code first gets loaded, before the application has booted up.
Ruby 1.9.3 + Rails 3.2.8
I have a view that is rendered on every page in my app inside a partial:
<span id="sync-time">
<%= #sync.dropbox_last_sync.strftime('%b %e, %Y at %H:%M') %>
</span>
In order to use my syncs model and have access to the dropbox_last_sync method, I have to include it in every controller throughout my app. For example:
class EntriesController < ApplicationController
def index
#sync = current_user.sync
end
end
...
class CurrenciesController < ApplicationController
def index
#sync = current_user.sync
end
end
...etc.
Is there a way I can make the syncs model available everywhere by including it in my Application Controller somehow?
You should be able to add a before_filter in your application controller:
before_filter :setup_sync
def setup_sync
if current_user
#sync = current_user.sync
end
end
You need to be careful that your setup_sync filter runs after whatever code you are using to set up your current_user. This is probably another before_filter though so provided you have before_filter :setup_sync declared after your current user filter it will work fine.
This is better:
class ApplicationController < ActionController::Base
before_filter :authenciate_user!
before_filter :index
def index
#sync = current_user.sync
end
end
You're using current_user always, so you need to have before_filter :authenciate_user! here aswell and above the other one.
I'm making a control panel (user accounts) in rails.
in the layout I need to show things like messages or notifications (facebook-like style).
the problem is these things require an access to database and I'm not sure where to put this code because it's not related to a controller, but the layout is shared with multiple controlers.
so where is the best place to put the code to fetch messages from database should I put in the layout itself (I don't think its right), or as helper ?
the best solution was to build a control-panel controller which handles authentication and permissions and loads common user data from database such as messages...
here is an example code
class ControlPanelController < ApplicationController
before_filter :authenticate_user!
before_filter :get_user_data
helper_method :mailbox
authorize_resource
protected
def get_user_data
#header_conversations=mailbox.inbox.limit(3)
#uevents= Event.scoped
#uevents= #uevents.after(Time.now)
end
def mailbox
#mailbox ||= current_user.mailbox
end
end
and then all the classes in my web application extends this class :)
I found a way is to use before_filter. by defining the filter in the ApplicationController (so that you can access it from any controller).
class ApplicationController < ActionController::Base
# ..
protected
def load_messages
#messages = Message.all
end
end
and then in the any controller:
class FooController < ApplicationController
before_filter :load_messages
def index
# #messages is set
end
end
I have the following application_controller method:
def current_account
#current_account ||= Account.find_by_subdomain(request.subdomain)
end
Should I be calling it using a before_filter or a helper_method? What's the difference between the two and what should I consider in terms of the trade-offs in this case?
Thanks.
UPDATE FOR BETTER CLARITY
I'm finding that I can user the before_filter instead of the helper_method in that I'm able to call controller defined methods from my views. Perhaps it's something in how I arranged my code, so here is what I have:
controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
include SessionsHelper
before_filter :current_account
helper_method :current_user
end
helpers/sessions_helper.rb
module SessionsHelper
private
def current_account
#current_account ||= Account.find_by_subdomain(request.subdomain)
end
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def logged_in?
if current_user
return true
else
return false
end
end
end
controllers/spaces_controller.rb
class SpacesController < ApplicationController
def home
unless logged_in?
redirect_to login_path
end
end
end
views/spaces/home.html.erb
<%= current_account.inspect %>
In theory, this shouldn't work, right?
There is no relationship between using before_filter or helper_method. You should use helper method when you have a method in your controller that you would like to reuse in your views, this current_account might be a nice example for helper_method if you need to use it in your views.
They are two very different things. A before_filter is something that you want to be called once before an action starts. A helper method on the other hand gets repeated often, typically in a view.
That method you have there is just fine to stay where it is.
I solved my problem. I'm new to Rails, and didn't know that methods defined in the helpers directory are automatically helper_methods. Now I'm wondering how this effects memory/performance. But at least I have the mystery solved. Thanks everyone for your help!
How can I get values from database in application.html.erb? I need to get those values for whole project. Those values will stay forever to all pages. How can I pass values to application.html.erb?
Is there anything like beforeRender?
Is there anything like appcontroller.rb to override actions?
You could use an application wide before_filter - like so
class ApplicationController < ActionController::Base
before_filter :load_application_wide_varibales
private
def load_application_wide_varibales
#var = Model.where :condition => "whatever"
end
end
#var would then be available in all your views
cheers
you can put method in the application controller
before_filter :load_data
def load_data
#data = Data.all
end
All controllers inherits ApplicationController, so data will be loaded at all actions. Now you can use #data at you application.html.erb file
The best way is probably to create a method in your application controller and declare it a helper method. Then you can call that method in application.html.erb. For example if you want to be able to use the current user throughout your application you'd do something like this:
class ApplicationController
helper_method :current_user
def current_user
#current_user ||= User.find(session[:user_id])
end
end
Then in application.html.erb you can do the following:
Hello <%= current_user.name %>
It's also possible to use before_filter like to other answers suggest, but in this solution the database only gets hit when it's necessary. With before_filter it always gets hit.