Send email after attribute updated Rails - ruby-on-rails

I would like to send an email to a user once the status of their pdform is updated. I already have some stuff written out on how I want this done.
In my pdform.rb model
after_update :sendemail
def sendemail
if status_changed?
end
end
I already have emails being sent out when the user creates a new form, however, I am not sure how to send an email in the model.
The controller has this mailer function that works correctly. How could I send this in this model?
NewPdform.notify_user(current_user, #pdform).deliver
Any help would be greatly appreciated. Still getting the hang of ActiveRecord.
Update:
In my pdforms_controller update method I have added the following variable.
update_user = #pdform.user
I added an attr_accessor in pdform.rb (the model)
attr_accessor :update_user
after_update :sendemail
def sendemail
NewPdform.notify_update(update_user).deliver
end
And in my mailer
def notify_update(user)
#user = user
mail(to: #user.email, subject: "some change occured")
end

I solved my own issue after using my brain more extensively.
In the call to the mailer function instead of passing the parameter of pdform, which is the name of the class anyways, just pass self.
def sendemail
NewPdform.notify_update(self).deliver
end

Related

Rails Controller runs update function anyway even though the form submit returns devise error message and nothing updated

Environment:
rails 4.2.6
devise 4.1.1
I am using a rails app, and there is a form to update user's profile. By default, devise asks the user to input user's password to update the user's data. I have put the <%=devise_error_messages! %> in the form, of course there is a update function in the controller, which looks like
def update
super
#email = resource.email
#event = resource.event
#name = resource.name
NoticeMailer.notice_confirm(#email, #name, #event).deliver_later
end
Here comes the problem. When I am editing the user's profile data, by default, devise asks the user to input the password to update the data and save it to the database. If I input the wrong password or leave the password field blank, and press the submi button(form.submit), there will be an error message, and I am still in the form. However even though there is an error message in the form, the update function in the controller still runs anyway. I think the logic is that the update function should not run if the update is failed.
Try01:
Try to input the data without password. I use the method
protected
def resource_update(params, resource)
resouce.update_without_password(params, resource)
end
in the controller,but it threw error message.
Try02
I am thinking using ajax to catch the submit click action and pass the password field to backend to check password. however i don't know how to implement this.
Try03
I tried to put a after_update filter function to do the mail sending function. However the result is the same, the mail function is sending no matter what.
Any suggestion?
I would expect the resource to be not valid? if the update failed. Therefore I would try:
def update
super
NoticeMailer.notice_confirm(
resource.email, resource.name, resource.event
).deliver_later if resource.valid?
end
Btw unless you use the instance variables somewhere else in the same
controller or its view then it should not be required assigning value to them first but you could pass the values directly to the mailer.
The correct update function in the controller:
def update
super
#email = resource.email
#event = resource.event
#name = resource.name
unless resource.errors.any?
NoticeMailer.notice_confirm(#email, #name, #event).deliver_later
end
end
Update02
def update
super
NoticeMailer.notice_confirm(
resource.email, resouce.name, resouce.event
).deliver_later unless resource.errors.any?
end

Undefined method for UserMailer:Class

I've got an app where users submit weeks which can be approved or denied, and in my weeks controller I have the following lines meant to iterate over the selected weeks, find their corresponding users and send each user an email:
elsif params[:commit] == "Reject selected weeks"
user_week = Week.where(id: params[:weeks_ids])
user_week.update_all(approved?: false)
# fetch the set of user_emails by converting the user_weeks to user_ids
users = User.find(user_week.pluck(:user_id))
users.each do |user|
#iterate over the users and send each one an email
UserMailer.send_rejection(user).deliver
end
flash[:info] = "Selected weeks were Rejected."
end
redirect_to weeks_path
When I attempt to reject a week, I receive the following error message:
undefined method `send_rejection' for UserMailer:Class
I'm adding on to pre-existing code and have little knowledge of MVC, so the only issues I can think of would be with placing the mailer method in the wrong file or sending an incorrect type of arg to the mailer method.
Here is "send_rejection", the mailer contained in my user model.
def send_rejection(user)
UserMailer.reject_timesheet(user).deliver_now
end
The corresponding method in my user_mailer.rb file:
def reject_timesheet(user)
#greeting = "Hi"
mail to: user.email, subject: "Rejected Timesheet"
end
New to rails and not sure where I'm going wrong.
This is not a problem of MVC, one question I'd probably ask is why are you not calling the reject_timesheet directly instead of send_rejection.
You're getting the error because as you said the method is defined in the user model, so in order to call the method, you'd need to do:
user.send_rejection
In which case I doubt you'd be needing to pass a user argument to the send_rejection, as you could just do:
class User
def send_rejection
UserMailer.reject_timesheet(self).deliver_now
end
end
then in your controller:
...
users.each do |user|
#iterate over the users and send each one an email
user.send_rejection
end
...
I believe you could also clean up your codebase a bit and possibly refactor some logic, but basically this approach should resolve your errors.
Let me know if that helps

How can I call a controller action from ActiveAdmin?

I have this method in my reports_controller.rb, which allows an user to send a status.
def send_status
date = Date.today
reports = current_user.reports.for_date(date)
ReportMailer.status_email(current_user, reports, date).deliver
head :ok
rescue => e
head :bad_request
end
How can I call this action from ActiveAdmin, in order to check if a User sent this report or not? I want it like a status_tag on a column or something.
Should I do a member action?
Thanks!
I'll address the issue of checking if a report has been sent later, but first I'll cover the question of how to call the controller action from ActiveAdmin.
While you can call ReportsController#send_status by creating an ActionController::Base::ReportsController and then calling the desired method, e.g.
ActionController::Base::ReportsController.new.send_status
this isn't a good idea. You probably should refactor this to address a couple potential issues.
app/controllers/reports_controller.rb:
class ReportsController < ApplicationController
... # rest of controller methods
def send_status
if current_user # or whatever your conditional is
ReportMailer.status_email(current_user).deliver
response = :ok
else
response = :bad_request
end
head response
end
end
app/models/user.rb:
class User < ActiveRecord::Base
... # rest of user model
def reports_for_date(date)
reports.for_date(date)
end
end
app/mailers/reports_mailer.rb
class ReportsMailer < ActionMailer::Base
... # rest of mailer
def status_email(user)
#user = user
#date = Date.today
#reports = #user.reports_for_date(#date)
... # rest of method
end
end
This could obviously be refactored further, but provides a decent starting point.
An important thing to consider is that this controller action is not sending the email asynchronously, so in the interest of concurrency and user experience, you should strongly consider using a queuing system. DelayedJob would be an easy implementation with the example I've provided (look into the DelayedJob RailsCast).
As far as checking if the report has been sent, you could implement an ActionMailer Observer and register that observer:
This requires that the User model have a BOOLEAN column status_sent and that users have unique email address.
lib/status_sent_mail_observer.rb:
class StatusSentMailObserver
self.delivered_email(message)
user = User.find_by_email(message.to)
user.update_attribute(:status_sent, true)
end
end
config/intializer/setup_mail.rb:
... # rest of initializer
Mail.register_observer(StatusSentMailObserver)
If you are using DelayedJob (or almost any other queuing system) you could implement a callback method to be called on job completion (i.e. sending the status email) that updates a column on the user.
If you want to track the status message for every day, you should consider creating a Status model that belongs to the User. The status model could be created every time the user sends the email, allowing you to check if the email has been sent simply by checking if a status record exists. This strategy is one I would seriously consider adopting over just a simple status_sent column.
tl;dr ActionController::Base::ReportsController.new.send_status & implement an observer that updates a column on the user that tracks the status. But you really don't want to do that. Look into refactoring like I've mentioned above.

Devise Confirmable - Welcome Message

So I am setting up a welcome message when a user signs up the website - previously I had set it up using gmail (http://stackoverflow.com/questions/5793296/rails-actionmailer-w-devise-google-apps-in-development-mode), but it's going to be using google apps - so if I'm correct another stackoverflow user claimed the set up is similar so that's not a problem. But since I only want a welcome email, I was thinking can I just use the confirmable set up so they get an email, and then in the config set it so that the user doesn't have to confirm till after say 1000 years or something large so basically it's not really a confirmation email? (If there is a better way to do this I'd appreciate such input)
you don't need to twist the Confirmable feature to achieve this, you can do it more elegantly with an ActiveRecord::Observer. Basically when you register/save a user the observer will get notified and from there you can call a mailer. You can see an example below.
app/mailers/user_mailer.rb
class UserMailer < ActionMailer::Base
default from: "something#something.com"
def welcome_mail(email)
mail(:to => email, :subject => "Welcome to Something").deliver
end
end
app/models/user_observer.rb
class UserObserver < ActiveRecord::Observer
# We check if it's a new user
def before_save(user)
#is_new_record = user.new_record?
true
end
def after_save(user)
# If it's not a new user we don't want to send them another welcome email
if #is_new_record then
UserMailer.welcome_mail(user.email)
end
end
end
Finally you need to configure rails to register the observer.
config/application.rb (just a extract)
config.active_record.observers = :user_observer
it's probably awfully late to answer, but i think there's after_create callback to shrink the solution above since you don't need to check if it's a new record!

Need help with sending email

I have a table of emails. And i need that Each user received email.
SO i made:
script/generate mailer Notifier
Next.
class Notifier < ActionMailer::Base
def newgrants_notification(respondent)
recipients user.email
from "lala#lala.com"
subject "Hi!"
body (:respondent => respondent)
end
end
In app/views/notifier/newgrants_notification.erb
wrote : Hello!
and this my controller where i create question
#question = Question.create(:text => params[:question][:text], :security => rand(888).to_i)
if success = #question.save
respondents = Respondent.find(:all)
respondents.each do |res|
Inquiry.create(:question_id=>#question.id.to_i, :respondent_id=>res.id.to_i)
Notifier.newgrants_notification(respondents).deliver #this is right??
end
what mistakes i did? messages aren't coming ;(
HI
respondents.each do |res|
Inquiry.create(:question_id=>#question.id.to_i, :respondent_id=>res.id.to_i)
Notifier.newgrants_notification(res).deliver
end
When you are sending mail,the mail id is passed as a parameter so respondents is replaced with res.
You are passing through your array of respondents, when you use each, the variable in the pipes (|res|) is the one to use to refer to the singular object in the loop.
Notifier.newgrants_notification(res).deliver
In development mode all email are not send. It's all log only in your log file. So if you test on this environment is normal. Check on your log if you see it :)

Resources