I was pulling my hair out trying to figure out why my call to Warden::Manager.before_logout was throwing a NoMethodError for NilClass when I tried to call 'user.my_method'. Then I added a debug puts call to the before_logout block and discovered that it was being called TWICE on each logout - the first time with the user being nil, and then immediately after, with the user object supplied. So I was able to inelegantly get around the exception by changing the call to 'user.my_method if user', but I'm still not comfortable with not knowing why before_logout is getting called twice. Has anyone else seen this? Is it perhaps one of those happens-in-development-only environment anomalies?
Devise.setup do |config|
Warden::Manager.after_authentication do |user,auth,opts|
user.update_attributes(is_active: true)
end
Warden::Manager.before_logout do |user,auth,opts|
user.update_attributes(is_active: false) if user
end
This is old, but you probably have two models (scopes in Warden's case): one for User and another for AdminUser. You can use an if statement for just the model/scope you want:
Warden::Manager.before_logout do |user, auth, opts|
if opts[:scope] == :user
user.current_sign_in_at = nil
user.save!
end
end
solve it by adding this in the config/initializers/devise.rb. Add code for what ever you want to do on logout.
Warden::Manager.before_logout do |user,auth,opts|
# store what ever you want on logout
# If not in initializer it will generate two records (strange)
end
Related
I am setting session[:return_to] for a lot of my routes to take users back to where they were before. I'm trying to create a generic checker to make sure that the link is valid, not the format, (http://somevalidurl) I don't care about that but that the actual link exists.
The main problem is when they are on a show page and then go to the edit page and delete an entry, the return_to takes them back to show page and we get a routing error because the entry no longer exists.
I would think that Rails had some sort of system for this in place.
I have something like this:
Net::HTTP.get_response(URI.parse(session[:return_to])) rescue false
But that takes forever to check and the page ends up taking a long time to refresh.
Ideas are welcome.
Checking if a previous url is valid is unnecessary, because such cases are not common routes to use your app. They are just exceptions. You only need a plan when exceptions happens, instead of dealing with it in every common route.
Simple solution: redirect to root
class ApplicationController
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
private
def record_not_found
redirect_to root_path, alert: "The record does not exist"
end
end
Advanced solution: redirect to controller's index page
class ApplicationController
rescue_from ActiveRecord::RecordNotFound do |exception|
# The message like: "Couldn't find foo with id=123"
klass = exception.message.split(' ')[2]
if klass
# suppose your index path is conventional foos_path
path = send "#{klass.pluralize.underscore}_path"
else
path = root_path
end
redirect_to path
end
end
I'm new to RSpec and my controllers're using inherited_resources, I have this mock/stub setup like:
describe MarketsController do
def mock_market(stubs={})
#mock_market ||= mock_model(Market, stubs).as_null_object
end
describe "GET index" do
it "assigns all markets as #markets" do
Market.stub(:all){ [mock_market] }
get :index
assigns(:markets).should eql([mock_market])
end
end
end
And this spec fails because there's nothing in the assigns(:markets). After I added:
class MarketsController
def index
#markets = Market.all
end
end
it'll pass so I guess that's because the inherited_resources doesn't call Market.all to get all of the Market instance and thus bypass the stub for Market.stub(:all). The index method I added above is obviously redundant and shouldn't exist at all, so the question is, without call Market.all explicitly, what should I do in my spec to complete the tests? Thanks in advance!
If I am reading the code correctly, inherited_resources first tries to use Market.scoped if it exists. So do you have a scoped scope?
Even though I'm pretty sure I know why this error gets raised, I don't seem to know why or how my session is exceeding the 4KB limit...
My app was working fine, but once I deliberately started adding bugs to see if my transactions were rolling back I started getting this error.
To give some background, I'm busy coding a tournament application that (in this section) will create the tournament and then add some tournament legs based on the number of teams as well as populate the the tournament with some 'ghost fixtures' once the legs have been created.
The flash[:tournament] was working correctly before; using a tournament object, I have access to any AR validation errors as well as data that has been entered on the previous page to create the tournament.
TournamentController.rb
begin
<other code>
Tournament.transaction do
tournament.save!
Tournament.generate_legs tournament
Tournament.generate_ghost_fixtures tournament
end
flash[:notice] = "Tournament created!"
redirect_to :action => :index
rescue Exception => e
flash[:tournament] = tournament
redirect_to :action => :new, :notice => "There was an error!"
end
Tournament.rb
self.generate_ghost_fixtures(tournament)
<other code>
#Generate the ghost fixtures
#tournament_legs is a has_many association
tournament_legs_array = tournament.tournament_legs
tournament_legs_array.each do |leg|
number_of_fixtures = matches[leg.leg_code]
#For the first round of a 32 team tournament, this block will run 16 times to create the matches
number_of_fixtures.times do |n|
Fixture.creatse!(:tournament_leg_id => leg.id, :match_code => "#{leg.leg_code}-#{n+1}")
end
end
end
I can do nothing but speculate as to why my session variable is exceeding 4KB??
Is it possible that the tournament object I pass through the flash variable contains all the associations as well?
Here is the dump of my session once I get the error.
Hope this is enough info to help me out :)
Thanks
Session Dump
_csrf_token: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
flash: {:tournament=>#<Tournament id: nil, tournament_name: "asd", tournament_description: "asdasd", game_id: 1, number_of_teams: 16, start_date: "2011-04-30 00:00:00", tournament_style: "single elimination", tournament_status: "Drafting", active: true, created_at: "2011-04-30 10:07:28", updated_at: "2011-04-30 10:07:28">}
player_id: 1
session_id: "4e5119cbaee3d5d09111f49cf47aa8fa"
About dependencies, it is possible. Also save an ActiveRecord instance in the session is not a recommended aproach. You should save only the id. If you need it in all your requests use a before filter to retrieve it.
You can read more why is a bad idea at: http://asciicasts.com/episodes/13-dangers-of-model-in-session
The generally accepted and recommended approach is to not use a redirect on error, but a direct render instead. The standard "controller formula" is this:
def create
#tournament = Tournament.new(params[:tournament])
if #tournament.save
redirect ...
else
render 'new' # which will have access to the errors on the #tournament object and any other instance variable you may define
end
end
class Tournament < ActiveRecord::Base
before_create :set_up_legs
end
On successful saving, you can drop all instance variables (thereby wiping the in-memory state) and redirect to another page. On failure (or exception) you keep the object in memory and render a view template instead (typically the 'new' or 'edit' form page). If you're using standard Rails validation and error handling, then the object will have an errors array that you can just display.
I'd also recommend you use ActiveRecord associations which automatically give you transactions. If you push all this into the model, e.g. a "set_up_legs" method or something, then you can use ActiveRecord error handling. This is part of the "skinny controller, fat model" paradigm.
in session_store.rb, uncomment the last line with :active_record_store
Now restart the server
I would convert the exception to string before assigning it to flash[:tournament] with 'to_s'.
I had the same error and it seems assigning an exception object to a session variabla like flash means it takes the whole stack trace with it into the session. Try it, worked for me.
I'm writing a rails3 app using authlogic and authlogic-oid to allow the user to login and register using their LinkedIn account. I'm able to call out to LinkedIn to authenticate but the issue I'm having is that when the call returns to my rails app, it is calling a GET on /user_sessions and invoking the index controller instead of executing the remainder of the create controller. Here's the controller:
# POST /user_sessions
def create
#user_session = UserSession.new(params[:user_session])
#user_session.save do |result| # <-- redirects to api.linkedin.com here
if result
flash[:success] = "Login successful!"
redirect_back_or #user_session.user_path
else
flash.now[:error] = "Invalid username/password combination."
#title = "Sign in"
render 'new'
end
end
end
Everything works great until if result which never gets called because the program resumes execution in the index controller instead of picking up where it left off. Any ideas on how to fix this would be greatly appreciated.
Edit: it seems my assumption that the controller was not completing execution was wrong. I've put in a bunch of debug statements and learned that the the program does resume execution in this controller after #user_session.save but it is not executing either condition on the if statement. I'm very confused on this one.
if you don't want to use index method in your UserSessionsController then write this: resources :user_session in your route.rb . If you'll use singular form then route can map CRUD (create, read, update, delete) and if you'll use plural of it then it will bind CRUD with index method of your controller.
I have been working with Rails 3.0.5 and Ruby 1.9.2 and I have noticed that a new record doesn't get saved or isn't available for use instantly.
For example
def create
#some_record = Pool.new(params[:pool])
#some_record.users.push(current_user)
if params[:commit] == "Add More"
#some_record.save
#some_record.do_something
elsif params[:commit] == "Save"
do_something_else(params)
elsif params[:commit] == 'Cancel'
redirect_to user_url(current_user)
end
redirect_to some_other_url(current_user)
end
So when I save the record and call some_record.do_something the saved object isn't available instantly. current_user.some_records doesn't contain the newly added record but current_user.some_records.all displays the newly saved record. However on the console I am able to view the newly created record with current_user.some_records.
I'm sure I am missing something fundamental to Rails 3. I have also tried the same with current_user.some_records.build(params[:some_record] and I have the same problem. Does Rails 3 save the object instantly or is there some kind of delayed write/save because the same problem does not occur with Rails 3.0.3.
Also I am not using an authentication plugin like authlogic/devise and I simply save the current_user object to the session. I am not sure what I am doing wrong. WOuld appreciate any help?
Its also a many-to-many association between some_record and users
current_user.some_records
does not contain the newly added record because you did not save the operation after assigning #some_record.users.push(current_user).
All you have to do is to add .save after the assignment and it should work.
The model structure is not clear from your question but let's assumed that current_user belongs_to some_records
To force a database read try this:
current_user.some_records(true)
By default forcereload = false, to override this you should pass true