stringify_keys error after supplementing session variables in functional tests - devise

I'm in the process of upgrading to Rails 3.1.0 from 3.0.10, and I'm using Devise for authentication.
I have a number of functional tests that require me to set a single session variable. Stuff along the lines of:
test "new clears current_lesson_id from session" do
get :new, nil, {'current_lesson_id' => '234234'}
assert_response :success
assert_nil session[:current_lesson_id]
end
This was failing as my session info was clobbering the devise authentication session data, so my previous solution was to merge with the default session:
test "new clears current_lesson_id from session" do
get :new, nil, authenticated_sesion_with({'current_lesson_id' => '234234'})
assert_response :success
assert_nil session[:current_lesson_id]
end
def authenticated_session_with(hash)
session.merge(hash)
end
All of this worked fine with rails 3.0.10 (with warden 1.0.4 and devise 1.4.2), but no longer with rails 3.1.0 (and warden 1.0.5, devise 1.4.4). Now I'm getting the following error:
NoMethodError: private method `stringify_keys' called for <ActionController::TestSession:0x000001060db590>
I gather this is because the 'session' object is an instance of ActionController::TestSession, and in rails 3.1.0 there are a bunch of instance variables that can't and shouldn't be 'stringified'.
How should I properly access the devise user information (preferably dynamically) so I can add 'current_lesson_id', etc.?
Thanks much,

try this to fix your error in Rails 3.1
sign_in user
hashy = session['warden.user.user.key'][2]
get :action, nil, {"warden.user.user.key"=>["User", [user.id],hashy]}, nil
Worked for me. Seems to not like the new way Rails handles TestSessions.

I think you better do:
def valid_session
my_session_values = {:some_key => :some_value}
session.to_hash.merge my_session_values
end

Related

Devise Parameter Sanitizer "For" Method Not Found Rails 5

I have just added devise to my shiny new Rails 5 app. All's good and dandy until I try to add a username to the Devise user model. Everything worked until I ran it and went to localhost:3000/users/sign_up, where I was greeted by this error:
undefined method `for' for #<Devise::ParameterSanitizer:0x007fa0dc31c1b0> Did you mean? fork
I have searched the wonderful place of Google for any results, only being given outdated, Rails 4 errors and solutions, the same with searching Stack Overflow itself. I cannot get my mind to find a working solution. I would appreciate help very much. Here is how I prepared for this:
Create the migration: rails generate migration add_username_to_users username:string:uniq
Migrate the database rake db:migrate
Add strong parameters to the application controller devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(..) }
Add username parameters to the Devise views
Restart the server
Is there anything I missed or did wrong?
The .for method is deprecated, from devise 4.1+ .permit method is available
Try .permit. It should work.
devise_parameter_sanitizer.permit(:my_action) { |u| u.permit(..) }
Hope this will help you :)
The problem was well mentioned by #Shadow but this syntax worked for me:
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name, :email])
devise_parameter_sanitizer.permit(:account_update, keys: [:first_name, :last_name, :phone, :email, bank_attributes:
[:bank_name, :bank_account]])
end

Devise sign_in_params method missing

I'm attempting to use Devise (2.2.4), which I'm new to, with the Rails 3.2.13/Ruby 2.0.0p195 app I'm building. I turned scoped_views on because I want to have my own separate users and admins views. And I created my own Users::RegistrationsController which seems to be doing what I want it to. I've just added my own Users::SessionsController, which is where I've hit problems.
I straight copied over a couple of action methods from the Devise::SessionsController source as a first step, planning to modify them once they were working (my controller code is at the bottom of this post). But my 'new' method is failing, when called, with a NameError because `sign_in_params' is apparently undefined.
Well, that seems pretty strange because I'm inheriting from Devise::SessionsController, and when I look at the source for that on GitHub, there's the sign_in_params defined in the protected section at the bottom. So I decided to investigate whether my controller is inheriting correctly from Devise::SessionsController - and it certainly seem to be. I can list out all the inherited methods, just not that one missing one. So I ended up running the following piece of code in the Rails Console:
(Devise::SessionsController.new.methods - DeviseController.new.methods).each {|m| puts m}
And it produces the following output:
_one_time_conditions_valid_68?
_one_time_conditions_valid_72?
_callback_before_75
_one_time_conditions_valid_76?
new
create
destroy
serialize_options
auth_options
If I ignore the underscored methods, the remainder are all those methods defined in the Devise::SessionsController source except sign_in_params. I can't see how anything I've written can be deleting that method, and I can't think what else to try. Google is silent on this problem, so I assume I'm doing something uniquely foolish, but I can't work out what. Any suggestions please? And might someone else try running that bit of Rails Console code to see what they get?
class Users::SessionsController < Devise::SessionsController
prepend_before_filter :require_no_authentication, :only => [ :new, :create ]
prepend_before_filter :allow_params_authentication!, :only => :create
prepend_before_filter { request.env["devise.skip_timeout"] = true }
# GET /resource/sign_in
def new
self.resource = resource_class.new(sign_in_params)
clean_up_passwords(resource)
respond_with(resource, serialize_options(resource))
end
# POST /resource/sign_in
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(resource_name, resource)
respond_with resource, :location => after_sign_in_path_for(resource)
end
end
I think you are using code from a devise version compatible with Rails 4 on a rails 3 application.
sign_in_params is a method to be used with strong parameters. A gem used in rails 4.
If you check the controller on devise version 2.2. https://github.com/plataformatec/devise/blob/v2.2/app/controllers/devise/sessions_controller.rb
You will see that there is no sign_in_params method.
Check which version of devise you are using and copy the code based on that devise version in your controller, rather than the latest code from github.

Rails undefined method 'to_i'

When the user creates a new worequest, I want to set the worequest.statuscode_id to the first entry in the statuscodes table.
The following (from worequest.rb) was working in Rails 3.1 but now I've upgraded to 3.2, it's not working.
after_initialize :defaults
def defaults
self.statuscode_id ||= Statuscode.first
end
I get
undefined method `to_i' for #<Statuscode:0x007fe934b67bd0>
Any idea why this doesn't work now? Do you know something that will work?
Thanks!

Failing to test Devise with Capybara

I'm building a Rails 3 app using Devise, with Capybara for UI testing. The following test is failing:
class AuthenticationTest < ActionController::IntegrationTest
def setup
#user = User.create!(:email => 'test#example.com',
:password => 'testtest',
:password_confirmation => 'testtest')
#user.save!
Capybara.reset_sessions!
end
test "sign_in" do
# this proves the user exists in the database ...
assert_equal 1, User.count
assert_equal 'test#example.com', User.first.email
# ... but we still can't log in ...
visit '/users/sign_in'
assert page.has_content?('Sign in')
fill_in :user_email, :with => 'test#example.com'
fill_in :user_password, :with => 'testtest'
click_button('user_submit')
# ... because this test fails
assert page.has_content?('Signed in successfully.')
end
end
... but I have no idea why. As you can see from the code, the user is being created in the database; I'm using the same approach to create the user as I did in seeds.rb.
If I run the test through the debugger, I can see the user in the database and verify that the page is loading. But still the authentication fails; I can verify this because if I change the assertion to test for the failure case, the test passes:
# verify that the authentication actually failed
assert page.has_content?('Invalid email or password.')
I'm used to Rails 2, & using Selenium for this sort of testing, so I suspect I'm doing something daft. Could someone please point me in the right direction here?
I was having the same issue and found a thread with a solution:
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
For the DatabaseCleaner stuff to work you'll need to include the database_cleaner gem. If you haven't used it before, you may need to rake db:test:prepare before rerunning your tests. I hope this works for you, too!
I've run into a similar problem before. Setting the password directly has some weird effects because it's supposed to be encrypted and stored with a salt--sometimes it works for me and other times it doesn't. I have a hard time remembering which specific cases were problematic. I'd recommend the following, in this order (for simplicity)
Verify that the password field is getting filled in properly and passed as the right param (not necessary if you're using Devise's autogenerated view and haven't touched it)
if your site can run in development mode (i.e. no log in bugs), then just boot it up and log in manually
If not, insert debugger as the first line in your sessions_controller. Then check params and make sure the password is correct and in params[:user][:password].
If you didn't override Devise's sessions_controller, then you can find your Devise path with bundle show devise. Then look for the create action within (devise path)/app/controllers/devise/sessions_controller.rb
Change your test setup to create a user through the web interface, to ensure the password gets set properly, then try running your test again
I had the same issue with a setup fairly similar to yours. In my case, switching to ActiveRecord sessions in the initializer solved the problem.
Additionally, make sure you call #user.skip_confirmation! if you are using the "confirmable" module in devise.

FactoryGirl + RSpec + Rails 3 'undefined method <attribute>='

I'm fairly new to rails and TDD (as will no doubt be obvious from my post) and am having a hard time wrapping my brain around Rspec and FactoryGirl.
I'm using Rails 3, rspec and factory girl:
gem 'rails', '3.0.3'
# ...
gem 'rspec-rails', '~>2.4.0'
gem 'factory_girl_rails'
I have a user model that I've been successfully running tests on during development, but then needed to add an attribute to, called "source". It's for determining where the user record originally came from (local vs LDAP).
In my factories.rb file, I have several factories defined, that look something like the following:
# An alumnus account tied to LDAP
Factory.define :alumnus, :class => User do |f|
f.first_name "Mickey"
f.last_name "Mouse"
f.username "mickeymouse"
f.password "strongpassword"
f.source "directory"
end
I have a macro defined (that's been working up until now) that looks like this:
def login(user)
before(:each) do
sign_out :user
sign_in Factory.create(user)
end
end
I'm calling it in multiple specs like so (example from users_controller_spec.rb):
describe "for non-admins or managers" do
login(:alumnus)
it "should deny access" do
get :index
response.should redirect_to(destroy_user_session_path)
end
end
If I don't specify the "source" attribute, everything works OK, but as soon as I do, I get an error like so when running the test
12) UsersController for non-admins or managers should deny access
Failure/Error: Unable to find matching line from backtrace
NoMethodError:
undefined method `source=' for #<User:0x00000100e256c0>
I can access the attribute no problem from the rails console and the app itself, and it's listed in my attr_accessible in the user model. It's almost as though Rspec is seeing an old version of my model and not recognizing that I've added an attribute to it. But if I put the following line into my user model, the error disappears
attr_accessor :source
... which indicates to me that it is actually looking at the correct model.
Help!
How about running this?
rake db:test:load
[If you added a new attribute you'd need to migrate it to the test database.]
if you don't use schema.rb (e.g. you have set config.active_record.schema_format = :sql)
you should run
rake db:test:prepare