How to validate existing surveys with rails 6 - ruby-on-rails

I'm working on a polls module where the user can fill in a form the name of the poll, url, start_date and expiration_date, the user can schedule their polls.
i made a simple validation to change their status like this.
validate :check_status
def check_status
unless self.start_date == nil || self.expiration_date == nil
if Date.today.between?(self.start_date, self.expiration_date)
self.poll_active = true
else
self.poll_active = false
end
end
end
all this validations in my Polls model, and its working perfectly like this, once i create or update a poll it checks this range and if its true it set the status to active.
but now i need one thing.
I can only have 1 poll with status active and once the poll meet the due date set the next poll to active if its other one
How can i do that?

Related

Is there a possible way to track when a boolean initially turn true in rails?

I have a boolean column in my table and a datetime related to it. I want to be able to track down when the boolean initially turns true. In the model I have tried
def example
if boolean_field == true
datetime_field = time.now
end
end
but the problem with that is when the boolean is set to true, the datetime_field will keep updating everytime i reload the page or database since the boolean will always be in a constant state of true. I have also try to use rails dirty on it with:
boolean_field_changed?
but that method doesn't seems to update the datetime column at all.
P.S i do have a before_save callback on the method.
def returned_time
if self.returned?
returned_at = Time.now
end
end
before_save :returned_time
any help on how i can save the initial time once the boolean_field changes from false to true will be much appreciated. thanks in advance
If returned is a boolean column in your table, then you should not need ActiveModel::Dirty. That module is for adding change detection for non-database attributes. You should be able to use Active Record's built-in changed? method:
class MyModel < Application Record
before_save :returned_time
def returned_time
if self.returned? and self.returned_changed?
self.returned_at = Time.now
end
end
end
This will update the returned_at time if returned is true and if that field has changed. This may suit your business logic.
However, if your goal is to only update the returned_at field when a book has been returned, you may want to check for the presence of a returned_at date instead:
def returned_time
if self.returned? and self.returned_at.blank?
self.returned_at = Time.now
end
end
This will only update the date if the book has been returned and there is no return date.
One final note, the self before returned_at in self.returned_at = Time.now is important. Otherwise, the field may not get updated.

Ruby on rails. Callbacks, specifying changed attribute

I'm trying to send emails when a certain attribute changes in my model.
My model has a string which I set to hired reject seen and notseen.
For example, If the attribute gets changed to reject I want to send an email, and if it's changed to hired I want to send a different one.
In my model I have:
after_update :send_email_on_reject
def send_email_on_reject
if status_changed?
UserMailer.reject_notification(self).deliver
end
end
Which sends the email when the status gets changed regardless of what the status is. I don't know how to specify this. I have tried something like:
def send_email_on_reject
if status_changed?
if :status == "reject"
UserMailer.reject_notification(self).deliver
end
end
end
which just doesn't send the email.
I have been searching but cannot find any up to date similar questions/examples.
Thanks in advance.
def send_email_on_reject
if status_changed? && status == "reject"
UserMailer.reject_notification(self).deliver
end
end

Rails: how to show user's "last seen at" time?

I'm using devise which stores current_sign_in_at and last_sign_in_at datetimes.
But lets say a user logged in a month ago but last viewed a page 5 minutes ago?
Is there a way I can display that ("User last seen 5 minutes ago").
How about this:
Create a migration to add a new field to users to store the date and time the user was last seen:
rails g migration add_last_seen_at_to_users last_seen_at:datetime
Add a before action callback to your application controller:
before_action :set_last_seen_at, if: proc { user_signed_in? }
private
def set_last_seen_at
current_user.update_attribute(:last_seen_at, Time.current)
end
This way, on every request (i.e. activity) that the current user performs, his/her last seen at attribute is updated to the current time.
Please note, however, that this may take up some of your app's resources if you have many users who are logged in, because this will execute before every controller action requested by someone who is logged in.
If performance is a concern, consider adding the following throttle mechanism to step 2 (in this example, throttling at 15 minutes):
before_action :set_last_seen_at, if: proc { user_signed_in? && (session[:last_seen_at] == nil || session[:last_seen_at] < 15.minutes.ago) }
private
def set_last_seen_at
current_user.update_attribute(:last_seen_at, Time.current)
session[:last_seen_at] = Time.current
end
To improve performance of the previous answer:
don't use session, as user already loaded with warden and all the attributes are accessible
update_attribute runs callbacks and updates updated_at attribute, and update_column not
to improve performance, better to use background workers, like ActiveJob/Resque/Sidekiq
to prevent from the high DB locking, better to create a seperate table, associated with users table, and write accesses there
Updated code:
before_action :set_last_seen_at, if: proc { user_signed_in? && (user.last_seen_at.nil? || user.last_seen_at < 15.minutes.ago) }
private
def set_last_seen_at
current_user.update_column(:last_seen_at, Time.now)
end
Devise plugin makes similar behaviour happen (just last seen, without optimizations): https://github.com/ctide/devise_lastseenable

How to trigger a "completed" attribute when a form is complete?

I have a rails model that is filled by a very long form (split using the wicked-wizard gem).
There are some validations but I allow blank in most of the fields.
I need to take certain actions if the model is saved but some of the fields remain blank (for example remember the user to complete the form)and some other actions if the form 100% complete (for example sending the user an email to let him know the form is complete).
My idea is to trigger a virtual attribute such as :complete if there are not blank fields in my model, but I'm not sure how and where to do that.
Any hints?
=========================
EDIT
Thanks to #Kzu suggestion I've found this to work on my wizard controller (but could also work on the object controller itself)
def update
#customer = current_user.customer
params[:customer][:complete] = #customer.attributes.select{|key,value| value.nil? or !value.present? }.any? ? false : true
#customer.attributes = params[:customer]
render_wizard #customer
end
For example you can use an ActiveRecord callback and a complete boolean field for this form.
before_save :check_if_complete
def check_if_complete
# self.attributes returns a hash including the attribute name as key and its value as value
completion = self.attributes.select{|key,value| value.nil? or value.blank?} ? false : true
self.complete = completion
end
This solution could work but take care of the different attribute types you have in database.

Rails 3, I need to save the current object and create another

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.

Resources