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 ....
Related
I have information in my rails view that I only want to show up if the user has entered all personal details in the database, such as name, firstname, street and city. I could now do this:
if user.name && user.firstname && user.street && user.street
# show stuff
end
but I don't think that is very elegant and "the rails way". Is there an easier and smarter way to do this?
You can use required in your html form tags and validations in Model Class. Also follow links:
http://guides.rubyonrails.org/active_record_validations.html
http://www.w3schools.com/tags/att_input_required.asp
In your model
class User < ActiveRecord::Base
def has_required_fields?
self.name && self.first_name && self.address && ....
end
end
And in your controller
if user.has_required_fields?
# do whatever you want
end
The "rails way" would be thin controller, fat model. So, in your case, you'd want to create a method inside your User model and use it in your controller afterwards.
User model:
def incomplete?
name.blank? or firstname.blank? or street.blank?
end
User controller:
unless user.incomplete?
# Show stuff
end
in model:
ALL_REQUIRED_FIELDS = %w(name surname address email)
def filled_required_fields?
ALL_REQUIRED_FIELDS.all? { |field| self.attribute_present? field }
end
in your controller:
#user.filled_required_fields?
will return true if all fields filled and false if not.
looks very gracefully :)
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.
In controller my code is
query = "insert into users (name, email,updated_at) values (#{name},#{email},now()) ON DUPLICATE KEY UPDATE updated_at=now()"
User.connection.execute(query)
and in model
after_create :change_updated_at
def change_updated_at
if !self.email.blank?
chk_user = User.find_by_id(self.email)
if !chk_user.blank? && chk_user.updated_at.blank?
chk_user.updated_at =Time.now
chk_user.save!
end
end
end
but it's not working please help
Your query should be replaced by something like this. This will provide the same functionality as using ON DUPLICATE KEY UPDATE
user = User.where("name = ? and email = ?", name, email)
if user.nil?
user = User.new
end
user.name = name
user.email = email
user.save
Since you want this function to run even if it is an update. You want to use the after_save callback http://apidock.com/rails/ActiveRecord/Callbacks/after_save
The after_create is called only on creation of brand new objects.
http://apidock.com/rails/ActiveRecord/Callbacks/after_create
List of all callbacks provided by active record are here
http://apidock.com/rails/ActiveRecord/Callbacks
Don't run your query directly, that's VERY un-rails like. Let rails generate the query for you.
By running it yourself, rails has no way of knowing that you've created the record, so the after_create filter isn't be called.
Change your code to something like :
User.create(name: name, email: email)
Then it'll run. Also, don't update the 'create_at' field yourself. If you use rails methods, it'll do this automatically for you as well :)
You need to get with params object input attributes.
So first of all you need new method, and then create method (if you use standart form helper for model):
def create
#user=User.new(params[:user])
#other code
end
I'm building a simple blog-style application. I really only need admin and non-admin users, so it seems like having a simple column in the user model called admin (boolean) will suffice.
I'm using Devise for authorization right now, and I've got the admin column added. I'm trying to set up my default admin user (myself) in seeds.rb, however admin comes out as false unless I add the admin column to attr_accessible. It seems like this would be a security concern, however, and I don't generally want admin users to be able to be created except by another admin. What's the correct, and safe, way to do this?
You want to handle setting the admin boolean internally. Don't expose it to mass-assignment.
Have your user model automatically default the first user (you) to an admin. Use a before_create method for this...
# models/user.rb
before_create :make_first_user_an_admin
def make_first_user_an_admin
self.admin = self.class.count == 0 # sets true if no users exist, false otherwise
end
Then use an instance method to set adminship...
# models/user.rb
def toggle_admin
self.admin = !self.admin
save
end
guard this method in your controller...
# controllers/users_controller.rb
def change_adminship
if current_user.admin
#user.toggle_admin
else
raise "Can't do that."
end
end
You are very correct to leave admin as not attr_accessible, this just disables setting it via mass-assignment. You can still set admin in your seeds by setting it singularly. Example:
user = User.new(:name => 'joe') ...
user.admin = true
user.save
I have
recommendations has_many approvals
Basically a recommendation gets created with an approval. The person who can approve it, comes in and checks an approve box, and needs to enter an email address for the next person who needs to approve (email is an attribute of an approval).
The caveat is that if the current_user has a user_type = SMT, then no more approvals are required. Thats the last approval.
I am using the recommendation/:id/approval/:id/edit action. I think I just need a Class method for the Approval. Something like:
before_save :save_and_create
def save_and_create
Some code that saves the current approval, creates a new one and asks me for the next admins email address, and send that user an email requesting that they approve
end
Any help would be greatly appreciated
# old post
class Recommendation << AR
validate :approval_completed?
def approval_completed?
if self.approvals.last.user.type == "SMT"
return true
else
return false # or a number for needed approvals: self.approvals.count >= 5
end
end
end
# new solution
class Approval << AR
validate :approvals_completed?
def approvals_completed?
if self.recommendation.approvals.last.user.type == "SMT"
return true
else
return false # or a number for needed approvals: self.approvals.count >= 5
end
end
end
I finally figured this one out. I simply created a before_save callback and the following method:
def create_next_approval
next_approval = self.recommendation.approvals.build(:email => self.next_approver_email, :user_id => User.find_by_email(next_approver_email))
next_approval.save if next_approver_email.present? && recently_approved?
end
hope it helps anyone else in my shoes.