Devise testing expired reset token - ruby-on-rails

I need some help here
I'm testing weather a expired reset_password_token should update or not a user account. I'm setting reset_password_sent_at attribute in User model to a expired value, but the user's password are been updated anyway. I'm using Devise's recoverable module.
factories/user.rb
factory :user_expired_unconfirmed_password do
email { Faker::Internet.email }
password { default_password }
password_confirmation { default_password }
confirmed_at { 2.days.ago }
reset_password_token { nil }
reset_password_sent_at { nil }
updated_at { 2.hours.ago }
end
passwords_spec.rb
RSpec.describe Devise::PasswordsController, type: :request do
it "creater users with expired reset_password_token (6 hours max.) shouldn't update password" do
user = FactoryBot.create(:user_expired_unconfirmed_password)
reset_password_token = user.send_reset_password_instructions
old_passw = user.encrypted_password
new_passw = 'test_new_passw_123'
# expire token
user.reset_password_sent_at = 7.hours.ago
#### debbug ###
# user.reload # if uncommented, got true in the below line
puts user.reset_password_period_valid? # got false
put user_password_path,
:params => {
"user" => {
"reset_password_token" => reset_password_token,
"password" => new_passw,
"password_confirmation" => new_passw
}
}
expect(user.reload.encrypted_password).to eq old_passw # got false here
end
end
P.s: Using the method reset_password_period_valid? I got false and true if I reload the user, but independent of that it's not passing the assertion.
Any idea what would be? I tested these helpers methods in Model tests with valid and expire reset_password_token to change the password and it worked right.

Try saving the user with the new value of the reset_password_token
RSpec.describe Devise::PasswordsController, type: :request do
it "creater users with expired reset_password_token (6 hours max.) shouldn't update password" do
user = FactoryBot.create(:user_expired_unconfirmed_password)
reset_password_token = user.send_reset_password_instructions
# expire token
user.reset_password_sent_at = 7.hours.ago
user.save
#### debbug ###
user.reload
puts user.reset_password_period_valid? # You should get false
old_passw = user.encrypted_password
new_passw = 'test_new_passw_123'
put user_password_path,
:params => {
"user" => {
"reset_password_token" => reset_password_token,
"password" => new_passw,
"password_confirmation" => new_passw
}
}
expect(user.reload.encrypted_password).to eq old_passw # got false here
end
end

Related

Rails 4 user model will not save with hash data from oauth

I am trying to add oauth to an existing login for my project, but when I retrieve the hash data and try to save the user params with user.save!, the validation rules fail.
user.rb
has_secure_password
validates :email, :format => { :with => /\A[^# ]+#[^# ]+\.[^# ]+\Z/ },
:uniqueness => { :case_sensitive => false }
validates :password, :presence => true, :on => :create
validates :username,
:format => { :with => /\A[A-Za-z0-9][A-Za-z0-9_-]{0,24}\Z/ },
:uniqueness => { :case_sensitive => false }
...
class << self
def from_omniauth(auth_hash)
user = find_or_create_by(uid: auth_hash['uid'], provider: auth_hash['provider'])
user.name = auth_hash['info']['name']
user.email = auth_hash['info']['email']
user.username = auth_hash['info']['email']
user.save!
user
end
end
The output of user.errors.full_messages gives me ["Password can't be blank", "Password can't be blank", "Email is invalid", "Username is invalid"].
What I don't understand is why the validations are failing if the data parameters have been defined (i.e. user.email) and hold the correct values.
What am I missing?
your problem is the find_or_create_by method.
this will looking for the user with uid and provider otherwise try to create it.
but without vaild username, and so on, it will always fail if there is no user with uid and provider
update:
you try to find a user with an uid and a provider. if
find_or_create_by find a valid user, it will return it. with this
you can update the data.
BUT if find_or_create_by did not find a valid user, it will create a user with the given parameter uid and provider. but to
create a valid user, your model needs a valid username, a valid
password, and a valid email
you could do something like this
def from_omniauth(auth_hash)
user = User.find_by(uid: auth_hash['uid'], provider:auth_hash['provider']) || User.new(uid: auth_hash['uid'], provider:auth_hash['provider'], password: 'your password methods')
user.name = auth_hash['info']['name']
user.email = auth_hash['info']['email']
user.username = auth_hash['info']['email']
user.save!
user
end

How to write Rspec Testing for devise authenticate methods

def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
else
where(conditions).first
end
end
Above is the method for authenticate and that code is from Model.
I unable to understand how to pass warden_conditions as parameter in this method for testing.
Can you please help me how to pass warden_condition as parameter for Rspec (Unit) Testiong?
Thanks
That seems to be a class method, and warden_conditions seems to be just a hash, so you can use something like this
let(:email) { "foo#bar.com" }
let(:warden_conditions) { { login: email } }
it "finds user by email" do
user = User.create(email: email)
authenticated = User.find_for_database_authentication(opts)
expect(authenticated).to eql user
end
it "finds user by username" do
user = User.create(username: email)
authenticated = User.find_for_database_authentication(opts)
expect(authenticated).to eql user
end

Rails: Shoulda Matchers and validates username on update

Model Validation:
validates :username, uniqueness: true, format: { with: /\A[a-zA-Z0-9_.-#]+\Z/i, message: "must contain only letters, numbers or _*-#" }, on: :update, :if => :username_changed?
Rspec:
require 'spec_helper'
describe User, "references" do
it { should have_and_belong_to_many(:roles) }
it { should belong_to(:account_type) }
it { should belong_to(:primary_sport).class_name("Sport") }
it { should belong_to(:school) }
it { should belong_to(:city) }
it { should validate_presence_of(:email) }
it { should validate_uniqueness_of(:email) }
it { should allow_value("test#test.com").for(:email) }
it { should_not allow_value("test.com").for(:email) }
describe "validation of username", focus: true do
before(:each) do
#user = User.new(email: Faker::Internet.email, password: "password", password_confirmation: "password", username: "test123", agreed_to_age_requirements: true)
end
it "should be valid" do
#user.save
#user.should be_valid
end
it "should not be valid with incorrect characters in username" do
#user.username = "test###!!!"
#user.should_not be_valid
end
end
end
FactoryGirl:
FactoryGirl.define do
factory :user do
email Faker::Internet.email
password "password"
password_confirmation "password"
agreed_to_age_requirements true
username Faker::Internet.user_name
end
end
I am basically just trying to test against the custom validation for the uniqueness of and with the specified format of the username

How am I supposed to use Devise and Omniaauth in Database Mongodb?

I did look Ryan Bates episodes to use devise with omniauth. Problem is that I am able to sign up with linkdin. My code
In my user.rb
field :provider, :type => String
field :uid, :type => String
field :name, :type => String
#has_many :authentications
def self.from_omniauth(auth)
where(auth.slice("provider", "uid")).first || create_from_omniauth(auth)
end
def self.create_from_omniauth(auth)
create! do |user|
user.provider = auth["provider"]
user.uid = auth["uid"]
user.name = auth["info"]["nickname"]
end
end
I add this and in my create controller for authentication I did
user = User.from_omniauth(env["omniauth.auth"])
session[:user_id] = user.id
redirect_to root_url, notice: "Signed in!"
I am succeded to put the value of linkdin in my user database as
{ "_id" : ObjectId("50b2f4e66d7ab88ac7000003"), "email" : "", "encrypted_password" : "", "sign_in_count" : 0, "provider" : "linkedin", "uid" : "wuBFLcbDyB", "name" : null, "updated_at" : ISODate("2012-11-26T04:49:42.549Z"), "created_at" : ISODate("2012-11-26T04:49:42.549Z") }
But as I login from linkdin it does not signup through linkdin else it redirects to
http://localhost:3000/users/sign_in
How can I login through that linkdin?
If you have something like this in your user model
validates :username, presence: true
Then you must know that linked in does not provide you any username. Since that, to complete your authentication / registration, your user has to add explicitly his username.
Make sure that your registrations_contreoller.rb looks like this
class RegistrationsController < Devise::RegistrationsController
def create
super
end
private
def build_resource(*args)
super
if session[:omniauth]
#user.apply_omniauth(session[:omniauth])
#user.valid?
end
end
end

Michael Hartl's Ruby on Rails 3 Tutorial: Chapter 6 Section 6.3.2 Password and Confirmation (Rails 3.2)

I am followed Michael Hartl's http://ruby.railstutorial.org until Chapter 6.3.2 where I stuck at Password and Confirmation.
( http://ruby.railstutorial.org/chapters/modeling-users#sec:adding_a_secure_password )
I have added "attr_assessor :password, :password_confirmation' to User.rb from what I understand after reading the instruction stated below:
"As seen in the mockup in Figure 6.1, we expect to have users confirm their passwords, a common practice on the web meant to minimize typos. We could enforce this at the controller layer, but it’s conventional to put it in the model and use Active Record to enforce the constraint. The method is to add password and password_confirmation attributes to the User model, and then require that the two attributes match before the record is saved to the database. Unlike the other attributes we’ve seen so far, the password attributes will be virtual—they will only exist temporarily in memory, and will not be persisted to the database."
I get 11 failures on bundle exec guard on user_spec.rb after adding:
password: "foobar", password_confirmation: "foobar" to #User.new in models/user_spec.rb
Something like "virtual" attributes (password, password_confirmation) that do not exist in db:development.sqlite3. This is what I am trying to do with no success. I even tried all possible methods such as hashes with #User in user.rb
What did I do wrong here?
Thanks kindly in advance
file: spec/user_spec.rb
require 'spec_helper'
describe User do
before do
# #user = User.new(name: "Example User", email: "user#example.com")
#user = User.new(name: "Example User", email: "user#example.com",
password: "foobar", password_confirmation: "foobar")
end
subject { #user }
it { should respond_to(:name) }
it { should respond_to(:email) }
it { should respond_to(:password_digest) }
it { should respond_to(:password)}
it { should respond_to(:password_confirmation) }
describe "when name is not present" do
before { #user.name = " " }
it { should_not be_valid }
end
describe "when email is not present" do
before { #user.email = " " }
it { should_not be_valid }
end
describe "when name is too long" do
before { #user.name = "a" * 51 }
it { should_not be_valid }
end
describe "when email format is invalid" do
it "should be invalid" do
addresses = %w[user#foo,com user_at_foo.org example.user#foo.]
addresses.each do |invalid_address|
#user.email = invalid_address
#user.should_not be_valid
end
end
end
describe "when email format is valid" do
it "should be valid" do
addresses = %w[user#foo.com A_USER#f.b.org frst.lst#foo.jp a+b#baz.cn]
addresses.each do |valid_address|
#user.email = valid_address
#user.should be_valid
end
end
end
describe "when email address is already taken" do
before do
user_with_same_email = #user.dup
user_with_same_email.save
end
it { should_not be_valid }
end
end
.
file: models/user.rb
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# name :string(255)
# email :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# password_digest :string(255)
#
class User < ActiveRecord::Base
attr_accessor :password, :password_confirmation
attr_accessible :email, :name
# attr_accessible :email, :name
# attr_accessible :email, :name, :password, :password_confirmation
before_save { |user| user.email = email.downcase }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
#validates :password, length: { minimum: 6 }
#validates :password_confirmation, presence: true
end
If you are only on section 6.3.2 then the tests should be failing. You will be correcting that in the following sections.
Adding has_secure_password to the model fixes the problem. It's in the book (later part) too.
I would guess the errors are complaining about "Could not find table 'users'"
Try:
rake db:migrate
rake db:load:test

Resources