I need to do some stuff when ever a new session starts for a user. Which is that is the right place to do it in rails?
I am looking for something similar to session_start for asp.net in global.asax.
In ASP.net there is handler
session_start()
{
// This will be executed everything when a new users visits the site very first time.
}
I don't there is a corresponding method like ASP, you would need to do conditional setting of session values depending on whether they exist, perhaps in an application controller method (so run on all pages). E.g:
/controllers/application_controller.rb
def set_session
session[:var1] ||= "x"
session[:var2] ||= "y"
end
Then at the top of the file:
class ApplicationController < ActionController::Base
before_filter :set_session
Sounds like your needs might best be met by setting the session variable in application_controller.rb with a before_filter:
before_filter :set_session_thing
def set_session_thing
session[:your_variable] ||= "your_value"
end
That will run before every request. Is that what you're looking for?
You should check out the docs here:
http://guides.rubyonrails.org/action_controller_overview.html#accessing-the-session
Related
Is it possible to access controller parameters when defining abilities in ability.rb?
I have an event and users that can participate in or create that event. It seems like I could create a different controller action for every possible scenario, e.g. a user signs himself up for an event or a creator deletes someone from the event. However I think it would be a lot easier to read to have less actions and be able to define abilities based on what parameters are being passed in from the client.
Answer
#chumakoff has some good info down below that helped explain how CanCanCan is working. I decided to authorize these actions by default in ability.rb, and then raise an error, e.g. raise CanCan::AccessDenied.new("You cannot delete someone else from this event"), in the controller if I detect incorrect user/event parameter IDs being sent in.
If I understand correctly, you are using cancan's authorize_resource or load_and_authorize_resource controller helper that calculates user abilities based on controller actions names.
But it's not obligatory to use this helper for all actions. You can skip it for actions having complex ability logic and check abilities manually.
For example:
class ParticipationsController < ApplicationController
authorize_resource except: :create # skiping `authorize_resource` for `create` action
# ...
def create
if creator_adds_someone_to_event?
authorize! :add_to, #event
end
if user_signs_up_for_event?
authorize! :sign_up_for, #event
end
# ...
end
So, you can check many different abilities in the same controller action. Just disable default cancancan's behaviour for the action.
Yes there is a debugging tool Named as " pry" . Use that it would help u out. Just use binding.pry wherever u want to check the value of parameters in the code and the console will stop executing at that moment so u can check the value of the parameters.
I haven't used Rails in some time now, but I am aware Rails comes with things like
application_controller.rb
before_filter :login_with_access_token
helper_method :current_user
From my understanding, before_filter will run the aftersaid method before EVERY action in thus controller. And considering this is the ApplicationController it will run it before every action, since everything inherits from the ApplicationController. And I guess a helper_method is a method that we check often and can be accessed in our views.
I guess the reason I am kinda confused is I don't fully see why we would need helper_methods other than the fact you would want you use them in the views. For example, if I just wanna check if a person model is an adult... what would persuade one from choosing a helper_method vs. action method? Ex.
def is_adult?
person.age > 18
end
Now this is where I am getting confused in my specific problem.
There are certain pages that you can only view if you have a Food object selected. Meaning, my route:
get '/user/:user_id/food/:food_id', to: 'units#display_user_food', as: 'display_user_food'
I proceeded to add a before_filter :user_has_food
def user_has_food
unless UserFood.where(id: params["user_id"]).empty?
true
else
unit_id = params["unit_id"]
false
puts "------------ User does not have food :("
redirect_to "/user/new-food/#{unit_id}"
end
end
But... now the problem is... I have a very thick controller... there are many actions... and if it hits another action, it just fails, and will attempt to redirect me since user_has_food turns out false. Looking at this... it doesn't seem right. What is the ideal and optimal solution to properly address this problem?
I would like to do something with the /app/helpers folder, but I can't seem to find updated tutorials on how to go about using them.
You can call before_filter only for some specific controller action like following
before_filter :user_has_food, only: [:display_user_food]
In rails 5.0 before_filter is deprecated and you should use before_action. And if you have only one action to filtered, you can avoid using array, see the bellow snippet
before_filter :user_has_food, only: :display_user_food
When you use only option in before_filter it will ignored calling while request comes for other action.
Helper method is accessible in any view and controller but action methods are bound to object of that particular class. So something like current_user that doesn't need any object should be a helper method.
Rokibul correctly pointed out about using only: [] syntax to avoid other controller action.
But note that all before_filters syntax are deprecated in Rails 5.0 and will be removed in Rails 5.1, Use before_action instead.
I try to optimise a Rails app with big load that currently hit the databsae on every request. I try now to optimise this by saving some info on the session so I don't need to go the database every time. I'm currently doing something like this.
def set_audience
if current_user
session[:audience] ||= current_user.audience
else
session[:audience] ||= 'general'
end
end
And then calling session[:audience] anywhere on my controller and views. Seems fine except that I'm seeing on the New Relic logs that sometimes the session is not set and therefore the app get a nasty nil.
Im thinking better I should use instance variables, maybe more something like this.
def set_audience
if current_user
session[:audience] ||= current_user.audience
end
#audience = session[:audience]
#audience = 'general' if #audience.empty?
end
And then calling #audience in my app.
Is this correct? I would like to make sure I'm used the preferred approach to this.
I think the standard approach here would be to use a helper method on ApplicationContoller:
class ApplicationController < ActionController::Base
private
def current_audience
#current_audience ||= current_user.audience
end
helper_method :current_audience
end
This will work pretty much exactly like the current_user helper method in your controllers and views. Depending on the specifics of your application, you may want to add some more robust nil handling, but this is the basic idea.
My Rails 3.2 project has a devise-generated user and a set of models that all contain data that's specific to that user. I want a logged-in user to be able to access only his own data through the APIs exposed by the controllers.
Now, a brute-force way to enable this would be to change each and every controller from something like:
def index
#stuff = Stuff.all
to
def index
#stuff = Stuff.find_all_by_user_id current_user.id
And I have to repeat this for every single action of every single controller. Is there perhaps a more succinct and DRY way of achieving the same effect? The amount of boilerplate I have to write feels wrong.
Thanks!
Take a look at the CanCan gem.
a) You can have a before callback in application_controller.rb that looks something like
def find_stuff_from_current_user
#stuff = Stuff.find_all_by_user_id current_user.id
end
And than call this in every controller like this:
before_filter :find_stuff_from_current_user
Now you have #stuff variable available in every controller and in every action.
b) Or you can use scoping in stuff model.rb where you say something like:
scope :stuff_from_current_user, where(:user => current_user)
I have the following in my application controller:
before_filter :set_current_subdomain
protected
def set_current_subdomain
Thread.current[:current_subdomain] = current_subdomain
#account = Account.find_by_subdomain(current_subdomain)
end
def current_subdomain
request.subdomain
end
and then the following in some of my models:
default_scope :conditions => { :account_id => (Thread.current[:account].id unless Thread.current[:account].nil?) }
Now, this works - some of the time. I for instance load up an index method and get back a list of records with the scope applied, but also sometimes get an empty list as Thread.current[:account_id] is coming out as nil, even though queries earlier in the request are working using the same value.
Question is, why is this not working, and is there a better way to set a variable that's global to the current request?
Manipulating the Thread local variables is a really bad idea and is going to lead to nothing but sadness, heartache, and pain. There's no guarantee that different parts of the request processing will be handled by the same thread, and because of this, your variables might end up getting lost.
The Rails convention is to create instance variables in the context of ApplicationController. In simple terms, all you really do is this:
class ApplicationController < ActionController::Base
before_filter :set_current_subdomain
attr_reader :current_subdomain
helper_method :current_subdomain
protected
def set_current_subdomain
#current_subdomain = request.subdomain
#account = Account.find_by_subdomain(#current_subdomain)
end
end
Any #... type variables you create will be attached to the instance of the ApplicationController associated with the current request. It's important to note that each request will be issued a brand-new instance of the appropriate controller class.
You're free to create whatever instance variables you want provided they don't somehow conflict with those used by Rails itself but in general terms this doesn't happen very often and conflicts typically occur on method names instead.
Class-level instance variables will persist between requests in environments where the "cache classes" flag is enabled. In the development environment your controller class is re-loaded each time a request is made to ensure it reflects the current state of your source files.