Rails increment login counter - ruby-on-rails

In my User model, I have a 'sign_in_count' column which I initially set to 1 when the user is created:
class User < ActiveRecord::Base
before_save { self.sign_in_count = 1 }
end
This works as when I go to the rails console, I can get back 1:
u = User.last
u.sign_in_count
=> 1
Then I created a method in my SessionsHelper:
def sign_in_count(user)
user.sign_in_count += 1
end
Then I call it my SessionsController like so:
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in user
sign_in_count(user)
.
.
.
end
But the sign_in_count never seems to increment. I log in perfectly fine. I get no errors or anything. I inspect the console and the sign_in_count is always 1. Any idea as to what i'm doing wrong here?

Use increment method (detail) instead of, like this:
def sign_in_count(user)
user.increment!(:sign_in_count)
end
And, please change before_save callback to before_create callback. We just initialize sign_in_count only one time when new user is created.
In case of you want to decrease sign_in_count, please use decrement.

Related

Rails Devise limit user sign up per ip

I'd like to limit user sign up per IP to 3!
In User model I have:
class User < ApplicationRecord
validate :validate_ip
def validate_ip
errors[:username] << "My error description" if User.where(last_sign_in_ip: last_sign_in_ip).count > 3
end
end
I do know the problem in this line User.where(last_sign_in_ip: last_sign_in_ip)
"last_sign_in_ip" is empty. That's why my condition doesn't work. I need somehow get IP address of user inside the model.
Any advice how I can achieve it?
You need to pass the ip variable from controller. Model cannot access request variables and on signup devise do not update last_sign_in_ip or last_sign_in_ip so they are null. They are set up only on login.
In your controller before creating the user object pass the ip value as instance variable
#remote_ip = request.remote_ip
And then in your model use the code below:
class User < ApplicationRecord
validate :validate_ip
def validate_ip
errors[:username] << "My error description" if check_multiple_sign_ups
end
def check_multiple_sign_ups
recent_user_count = User.where(last_sign_in_ip: #remote_ip ).count
(recent_user_count > 3 ) ? false : true
end
end
Hope this Helps...

Rails getting access to current user

I'm trying to save in Note which Employee was the last editor of a `Note'
In a View, I'm able to access the current employee like this:
<h4><%= current_user.employee.id%></h4>
But, in a Model, I can't use current_user.employee.id.
So, I'm trying this in the User model:
def self.current
Thread.current[:user]
end
def self.current=(user)
Thread.current[:user] = user
end
And this in the Note model:
before_create :record_update
before_update :record_update
protected
def record_update
self.lasteditor_id = User.current.employee.id unless User.current.employee.id.nil?
end
What I'm getting is the last User in the Users table.
Thanks for the help!
current_user gets the logged in user information from the session. You cannot access session variables from model. If you want to update the Note model with the Last employee who viewed it, do it in your controller(most likely show action of your note or any other action you think would be right)
def show
#note = Note.find(params[:id])
#note.update_atribute(:last_viewed_by, current_user.id)
end
You code might look different from above. But this is the idea

How can I add this transaction to when after email confirmation is completed with Devise?

Assuming that an existing user(ID:1367) can send this url to his friends as an invitation.
http://example.com/users/sign_up?invitation=1367
Then Users table has hidden column called invitation.
and This is procedure how it works that I want.
His friend input information to sign up.
He hits submit button then hidden field 'invitation' will be also sent to form.
1367 will be set in the column called 'invitation' of the record.
He will receive confirmation mail, and when he clicks on the link, I'd like to add this transaction, and execute only once for his account.
Of course, this shouldn't be executed when the existing user tried to re-activate.
Only for the first confirmation for the new user.
code
#user = User.find_by_invitation(current_user.invitation)
#user.friends = #user.friends + 1
#user.save
I already have registration controller that helps adding extra transaction to Devise.
Now I want to know how I can implement this procedure to my app.
Should it be something like this?
registrations_controller.rb
def after_????????
if #user = User.find_by_invitation(current_user.invitation)
#user.friends = #user.friends + 1
#user.save
end
end
You can do this on the user model. Use a callback called after_create which is triggered after a user is created.
# user.rb
after_create :handle_invitation_code
private
def handle_invitation_code
# do something with invitation here
# i'm assuming that you want to credit
# whoever it is that invited this user
# assuming that invitation contains the
# id of the referrer
if referrer = User.find_by_id(invitation)
# do something with referrer
end
end
Be warned that if you return false on a callback, it will cause a rollback and the record won't be saved.
UPDATE: callback for after confirmation
instead of using after_create, use before_save with an if option
before_save :handle_invitation_code, if: :just_confirmed?
def just_confirmed?
confirmed_at_changed? && confirmed_at_was.nil?
end
def handle_invitation_code
...
end

Overriding ActiveRecord class method

I am setting up a User model at the moment and I have a setup where a new user is emailed an activation token. When they click on the link the controller method that is called has the line
#user = User.find_by_activation_token! params[:activation_token]
Now my activation token has a 24 hour expiry associated with it and if it has expired I want the user record destroyed. This would be easy enough for me to implement in the controller but I'm trying to be a better Rails developer and a better Ruby programmer so I thought I should put this in the model (skinny controller, fat model!). I thought it would also give me better insight into class methods.
I have made several attempts at this but have been quite unsuccessful. This is my best effort so far;
def self.find_by_activation_token!(activation_token)
user = self.where(activation_token: activation_token).first #I also tried User.where but to no avail
if user && user.activation_token_expiry < Time.now
user.destroy
raise ActivationTokenExpired
else
raise ActiveRecord::RecordNotFound
end
user
end
Do I have to change much to get this to do what I want it to do, or am I on the wrong track entirely?
I think I got this. Your condition logic is a bit off
def self.find_by_activation_token!(activation_token)
user = self.where(activation_token: activation_token).first #I also tried User.where but to no avail
# if this user exists AND is expired
if user && user.activation_token_expiry < Time.now
user.destroy
raise ActivationTokenExpired
# otherwise (user does not exist OR is not expired)
else
raise ActiveRecord::RecordNotFound
end
user
end
I think it should be more like this:
def self.find_by_activation_token!(activation_token)
user = self.where(activation_token: activation_token).first #I also tried User.where but to no avail
raise ActiveRecord::RecordNotFound unless user
if user.activation_token_expiry < Time.now
user.destroy
raise ActivationTokenExpired
end
user
end

rails -- track number of user login

I'd like to track how many times a user logs in to my site which is a Rails app. Is there any other call like "created_on or updated_on" that can make a little counter in my model that tracks that kind of info? I'm using restful-authentication currently.
I would add login_count field to your User/Account model. Then change this method in User/Account model:
def self.authenticate(login, password)
return nil if login.blank? || password.blank?
u = find_by_login(login) # need to get the salt
u && u.authenticated?(password) ? u.increase_login_count : nil
end
and add this method to model:
def increase_login_count
self.login_count += 1
self.save
self
end
You could create a column in the user table called login_count or something and then in the SessionsController.create method
if user
user.login_count += 1
user.save(false) #update without validations.
# .... other RestfulAuthentication generated code ....

Resources