RSpec not doing reload or not saving object - ruby-on-rails

I'm facing a problem with rspec.
This is my test code:
describe "email address with mixed case" do
let(:mixed_case_email) { "Foo#ExAMPle.CoM" }
it "should be saved as all lower-case" do
#user2 = FactoryGirl.create(:user, email: 'aaaa#aaa.com')
#user2.email = mixed_case_email
p #user2.email
p #user2.save!
p #user2.email
p #user2.reload.email
expect(#user2.reload.email).to eq mixed_case_email.downcase
end
end
My terminal outputs:
"Foo#ExAMPle.CoM"
true
"aaaa#aaa.com"
"aaaa#aaa.com"
My user model:
#encoding: UTF-8
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable,
:validatable, :confirmable, :lockable,
:timeoutable, :omniauthable
before_validation { self.email.downcase! if self.email }
validates :email, presence: true, length: {:maximum => 60}
end
Looks like reload or save are not working. Don't know what I can do. Have this same test in other projects but without devise. Can it be the reason of this problem?

It is devise :)
Devise does not allow you to change email without confirmation. When you set another email devise saves it in unconfirmed_email, generates confirmation_token and sends a email to confirm it. So you have a conflict with gem devise functionality.
Not sure but I think you can check that unconfirmed_email is downcased after saving

Related

Devise custom after confirmation action

Switching from my own auth solution to Devise, I'm trying to integrate with my mail service, Convertkit.
I'm trying to make devise call my method after confirming a user but I'm not sure how to call the resource.
I tried both these solutions:
https://stackoverflow.com/a/25336930/6848493
https://stackoverflow.com/a/16423638/6848493
Here's my User model:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :lockable, :lastseenable, :timeoutable
validates :terms_and_privacy_policy,
acceptance: { accept: true }, on: :create, allow_nil: false
validates :first_name, presence: true
validates :last_name, presence: true
def confirm!
super
subscribe self
self.send_convertkit_failure unless #ck_response_code == 200
end
# Send email to admin in case of ConvertKit API failure
def send_convertkit_failure
UserMailer.convertkit_failure(self).deliver_now
end
Here's my user helper:
module UsersHelper
def subscribe(user)
response = HTTParty.post("https://api.convertkit.com/v3/forms/form/subscribe",
query: {email: user.email, first_name: user.name, course_opted: true, api_secret: 'my secret' })
#ck_response_code = response.code
end
end
There is no error message, it confirms the user okay but it doesn't subscribe them to convertkit. I've tried the same code but with resource
as the object but that throws an error.
As for the second method (writing to after_confirmation), it errors saying the user has already been confirmed.
Would really appreciate your input, thanks in advance.
Finally got this to work, in my User model:
# Override Devise::Confirmable#after_confirmation
def after_confirmation
subscribe self
self.send_convertkit_failure unless #ck_response_code == 200
end

how to store ldap data in ruby on rails application database?

i have created a web app with rails4 and authentication system is developed with devise_ldap_authenticable gem.
where i am using username for login not email. but i want to store email in my users table.
My user model is
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
##attr_accessible :email, :password, :password_confirmation
# not required for LDAP :recoverable, :registerable, :validatable
devise :ldap_authenticatable, :rememberable, :trackable
validates_uniqueness_of :email, :allow_blank => true
before_save :get_ldap_email
def get_ldap_email
self.email = Devise::LDAP::Adapter.get_ldap_param(self.username, "mail")
end
end
But in users table of email field its storing data like
`email` = '--- !ruby/array:Net::BER::BerIdentifiedArray\ninternal:\n- !ruby/string:Net::BER::BerIdentifiedString\n str: !binary |-\n cy5naG9zaEBzYW1zdW5nLmNvbQ==\n ber_identifier: 4\nivars:\n :#ber_identifier: 49\n'
My log says
LDAP: Requested param mail has value ["s.ghosh#example.com"]
How i will store this value to my users table. where im doing wrong? please help me out.
Just need to add the following then its totally ok
def get_ldap_email
self.email = Devise::LDAP::Adapter.get_ldap_param(self.username, "mail").first
end

devise invitable do not validate model

First, excuse my poor english, I'm french... it's tricky to explain my problem !
I have a model User model in a Rails application:
class User < ActiveRecord::Base
attr_accessible :email, :gender, :lastname, :firstname
end
And a BackUser model that inherit from User:
class BackUser < User
# Class for Backoffice User
devise :database_authenticatable,
:rememberable,
:trackable,
:lockable,
:invitable,
:confirmable,
:validatable,
:validate_on_invite => true
attr_accessible :password, :password_confirmation, :remember_me, :active, :role
validates :role, presence: true,
inclusion: ["admin", "normal"]
validates :gender, presence: true
validates :firstname, presence: true
validates :lastname, presence: true
def admin?
self.role == 'admin'
end
end
This second class should validate the record before invite!
BUT, when I use the console to do the following:
u = BackUser.new
u.invite!
"u" is saved in database and an invitation is send to a blank email...
Do you know what I have to do?
Thans a lot!
I'm sure you've found a solution or workaround to your problem by now, but for any future SO users who encounter the same problem I found a pretty simple fix.
Devise Invitable's model configuration docs don't fully explain how to implement :validate_on_invite, but you have to set the configuration option to true - :validate_on_invite => true.
Here's what my devise method looks like in my User model for this to work correctly.
models/user.rb
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :invitable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :validate_on_invite => true
Now when I attempt to submit an invitation it is fully validating the record with what the validations I've set up in my User model before allowing the invitation to be sent and the user record to be created. Looking at the docs, I'm guessing you can also enable this setting in the devise initializer, but I haven't tried going that route.
*Second possible option to enable validation if needed
config/initializers/devise.rb
config.validate_on_invite = true
I've never been able to get the validation to work correctly for devise invitable. You can't use RobHeaton's suggestion either because you will receive a validation error on the password. I use this little hack to get validation to work:
def create
#user = User.new(user_params)
#user.valid?
#user.errors.messages.except!(:password) #remove password from errors
if (#user.errors.any?)
render 'new'
else
#user.invite!(current_user)
redirect_to user_path(#user)
end
end
It doesn't solve the mystery of why your behaviour is occurring, but:
if u.save
u.invite!
end
will give the end result you are after.

Devise official wiki for omniauth with facebook not working?

I followed the devise official wiki to integrate devise with facebook through omniauth.
I am able to login with my facebook account but somehow I am unable to save additional data from facebook's omniauth callback.
Note that I literally copied everything on this guide
Please look at my current user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me,
:fb_raw
def self.find_for_facebook_oauth(access_token, signed_in_resource=nil)
data = access_token.extra.raw_info
if user = User.where(:email => data.email).first
user
else # Create a user with a stub password.
User.create!(:email => data.email, :password => Devise.friendly_token[0,20])
end
end
def self.new_with_session(params, session)
super.tap do |user|
if data = session["devise.facebook_data"] && \
session["devise.facebook_data"]["extra"]["raw_info"]
# Here you can save all the info you want including networks and education
user.email = data["email"]
user.fb_raw = data['raw_info']
end
end
end
end
The problem here is that self.new_with_session is never invoked. I placed a throw exception clause right before super.tab to prove that my hypothesis.
Does anyone know a work around this?
The new_with_session is call on DeviseRegistrationController so it's not in OmniauthCallbacksController so it's normal to never be called during the login by Facebook.

Disabling validations when reseting passwords in Devise/Warden

I have a user model as follows:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :invitable,
:recoverable, :rememberable, :trackable, :validatable,
:token_authenticatable, :omniauthable
validates_presence_of :nickname, :unless => :skip_nickname_requirement
end
I have a number of user records in the database with a nil nickname - those individuals were imported from another system and I don't actually have their nickname. Those users are invited to set their passwords via the lost passwords link like http://example.com/users/password/edit?reset_password_token=iAYeQRwWrt8geC8eEXR4, and then when they log in, add their personal details such as nickname, etc.
The problem is that when you go to that reset password you're prompted to enter your password (and again for confirmation). When you submit, validation fails because the nickname is nil.
How do I disable the nickname validation when reseting your password? I don't want to add the nickname textfield on the password reset form.
Thanks in advance for your thoughts!
I don't know if simple validates_presence_of :nickname, allow_blank: true would solve your problem, because you may want it to be blank only for those imported users. Therefore, other way would be to use custom validations.
# app/models/user.rb
class NicknameValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors[attribute] << "validation failed" unless :skip_nickname_requirement?(value)
end
private
def skip_nickname_requirement?(values)
# imported_from_legacy_system? would need to be implemented
value.present? || self.imported_from_legacy_system?
end
end
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :invitable,
:recoverable, :rememberable, :trackable, :validatable,
:token_authenticatable, :omniauthable
validates :nickname, :nickname => true
end

Resources