Help debugging my session? Rails 3 ActionDispatch::Cookies::CookieOverflow - ruby-on-rails-3

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.

Related

New to Rails 4 Testing - Need help getting started (rSpec and Devise)

I'm relatively new to testing and very new to Rails 4 and rSpec. I am trying to test a controller that uses Devise for authentication and I am stuck. All of the examples I can find are for Rails 3.
I'm using Rails 4.0.3, Devise 3.2.3, rSpec 2.14.1 and FactoryGirl 4.4.0.
class LessonPlansController < ApplicationController
before_action :authenticate_user!
# GET /lesson_plans
def index
#lesson_plans = current_user.lesson_plans.to_a
end
.
.
.
private
# Use callbacks to share common setup or constraints between actions.
def set_lesson_plan
#lesson_plan = LessonPlan.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def lesson_plan_params
params[:lesson_plan]
end
def lesson_plan_params
params.require(:lesson_plan).permit(:title, :synopsis)
end
end
Here are my factory definitions: (Maybe I don't need to define user_id in the lesson_plan factory?)
FactoryGirl.define do
factory :user do
sequence( :username ) { |n| "user#{n}" }
sequence( :email ) { |n| "foo#{n}#example.com" }
password 'foobarbaz'
password_confirmation 'foobarbaz'
created_at Time.now
updated_at Time.now
end
end
FactoryGirl.define do
factory :lesson_plan do
user_id 1
title "The French Revolution"
synopsis "Background and events leading up to the French Revolution"
end
end
And the test part is where I get stuck.
describe LessonPlansController do
let(:valid_attributes) { { } }
let(:valid_session) { {} }
# describe "GET index" do
it "assigns all lesson_plans as #lesson_plans" do
user=FactoryGirl.create(:user)
sign_in user
lesson_plan = LessonPlan.create! valid_attributes
get :index, {}, valid_session
assigns(:lesson_plans).should eq([lesson_plan])
end
end
I'm not sure what to put in valid_attributes and valid_session (or if I even need them). The test will get as far as signing in the user, but will fail on creation of the lesson_plan. Admittedly this is the default/generated test for rSpec, but I am not sure how to proceed.
Examples I have seen use a before block to set up the user. I haven't been able to find anything on the Devise wiki page covering how to write basic rSpec tests for a controller that requires the user to be logged in. Any pointers would be greatly appreciated!
"I'm not sure what to put in valid_attributes and valid_session (or if I even need them)."
Well that depends what you're testing for.. Say you're testing validations & want to ensure that a record not be created if x column is set to null... then you could try to specifically create a record with invalid attributes (e.g. column: nil) and expect the result to not return true; maybe you want to ensure that it IS created with valid attributes.
You can btw, use `attributes_for(:factory_name)`` since you're using FactoryGirl. And no you don't necessarily need to specify the user's id in your lesson plan factory; unless you always want it to reference user 1. You can simply reference user with no value. Check out http://everydayrails.com/2012/03/12/testing-series-intro.html and especially parts 3-5 for an introduction to testing with RSPec.. I found this a pretty easy to follow guide when I was getting started.

Rails Warden before_logout is called twice

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

Rspec controller spec

I am new to Rspec please tell me what would be the controller Spec for the following two methods In index method only login page is seen by entering the username control goes to login method and find the name of person. If person is find then control goes to people path otherwise it goes back to root path that is index page it self.
class HomeController < ApplicationController
def index
end
def login
#person = Person.find(:all, :conditions => ['people.name =?', params[:person][:name]] )
if #person.blank?
redirect_to root_path
else
redirect_to people_path
end
end
end
Please help me.
Thanks.
Your rspec controller tests could be like this:
describe HomeController do
render_views
it "Logs in Person with non-blank name" do
person = Factory(:Person, name: "non-blank name")
get :login
response.should redirect_to(people_path)
end
it "does not log in Person with blank name" do
person = Factory(:Person, name: "") # blank name
get :login
response.should redirect_to(root_path)
end
end
Refer to rails controller specs for details.
EDIT:
Factory: the code that creates objects (test objects in this case). This is a preferred method for creating test objects because you can customize your code to create objects with varying attributes with least duplication.
Fixtures: If you are not using factories, you can specify the attributes for each of the objects you are going to create. For more than 2-3 object, this data quickly becomes unmanageable to maintain (for example, when you add an attribute, you need to make changes for each of these objects).
Stubs: If you prefer not to create database records while creating model objects, you can stub the model code white testing controllers.
For more information, refer:
1. testing guide
2. asciicast (Note: this code refers to an older version of FactoryGirl gem. Refer below for up-to-date API of FactoryGirl)
3. FactoryGirl Readme

Rails - uncached controller action messing with serialized attribute

I have a controller action that calls a model method which generates a serialized list of data pulled from another model database. I need this to be uncached because the SQL queries should be random data pulls.
Here's a general idea of my code (Note that User has_one Foo, Bar is an arbitrary model of data, :data_list is of type text, and the database is SQLite):
# app/models/foo.rb
class Foo < ActiveRecord::Base
serialize :data_list
def generate_data
list = []
for i in 1..4
data = Bar.find(:first, :order => "Random()")
list << data
end
self.data_list = list
end
end
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def generate_action
...
uncached do
#user.foo.generate_data
end
#user.foo.save
end
end
# app/views/user/show.html.erb
...
<% #user.foo.data_list.each do |data| %>
<%= data %><br />
<% end %>
Whenever uncached do ... end is removed, everything works fine and the show view prints out each set of Bar objects in #user.foo.data_list. Unfortunately, because of Rails' SQL caching, it ends up look like this:
RandomDataPoint8
RandomDataPoint8
RandomDataPoint8
RandomDataPoint8
When I need to look like this:
RandomDataPoint7
RandomDataPoint13
RandomDataPoint2
RandomDataPoint21
It should be noted that running user.foo.generate_data from Rails command line works perfectly with the randomization. It is only when being called from the controller that caching starts to occur.
My research suggested I use uncached in the controller to remove caching, however it seems to destroy my data serialization and I receive the error:
undefined method 'each' for #<String:0x007ff49008dc70>
In fact, it does this even if I retroactively add in uncached (having successfully generated a data_plan without uncached prior) and save the controller, but don't call generate_action.
EDIT
I believe this problem is actually related to the fact that I was storing an object in the hash. Switching to the object id fixed this problem. Another SO question of mine regarding this can be found here:
Rails - Accessing serialized data from console
The following has been preserved just because the syntax may still help people, but I don't believe it was the actual cause of the problem.
I solved this by moving uncached to the model. For reference, the source I was using to originally solve this problem was this link: http://railspikes.com/2008/8/18/disabling-activerecord-query-caching-when-needed
What I overlooked is that he puts uncached in the model, not the controller. Also, the syntax needed to be a little different:
# app/models/foo.rb
self.class.uncached do
...
end
instead of
uncached do
...
end
The source for the syntax correction is this SO response: https://stackoverflow.com/a/967690/337903

Datamapper Callback for Forum tripcode

The context: creating a tripcode implementation (http://en.wikipedia.org/wiki/Tripcode) for a forum. Essentially, a weak hash for registrationless identification.
There is one model, 'Post'. Posts are arranged in parent/child format, new post creates parent, replies create child to parent. There is one form, right now has a field that posts to the controller/model, contains a content and password field.
require 'bcrypt'
class Shout
include DataMapper::Resource
include BCrypt
property :id, Serial # unique key
property :content, Text
property :password_hash, String
property :trip, String # trip for display
belongs_to :forum
is :tree, :order => [:created_at]
attr_accessor :password
#before :save do
def password
#password ||= Password.new(password_hash)
end
def password=(new_password)
#password = Password.create(new_password)
self.password_hash = #password
end
def trip
#trip = '!'<<self.password_hash.to_str[20..33]
self.trip = #trip
end
#end
end
DataMapper.finalize
The basic flow is this - post/reply, if there is a password in the password field, take that and run through bcrypt, store that result as password_hash for later comparison, create tripcode for display. But I'm getting errors I've been beating my head against
The primary error I'm getting is
undefined method `primitive?' for nil:NilClass
seemingly emanating from
lib/active_support/whiny_nil.rb:48:in `method_missing'
I don't know how to handle or work around this. I'm not doing something or checking something with the controller, but don't yet know what. The other error I'm getting stems from an invalid bcrypt hash, but not able to duplicate this immediately.
The hook methods are right off the bcrypt-ruby page.
Creating a BCryptHash field works (dm-types) -- but increases the time to process the form by a factor of 10, on a localhost server, and does it for every post so I need a way to tweak the cost of the bcrypt hash (eg. 1 instead of default 10) and only run it when there is a password present, which is why I'm doing this.
But this doesn't work right now, I've rammed my head against it enough and moving on to other problems and coming back to it if I can get some input. I'm working with rails, so I've added that tag although its not primarily a rails issue.
Feel free to review or contribute or use for errors here.
https://github.com/blueblank/Shout/tree/oneshout