Invoke action to send email in ruby on rails - ruby-on-rails

I am attempting to send an email to the present borrower of a book. I've created an ActionMailer called ReturnRequestMailer which has a method called please_return.
class ReturnRequestMailer < ActionMailer::Base
def please_return(book_loan)
subject 'Book Return Request'
recipients book_loan.person.email
from 'andrew.steele#west.cmu.edu'
sent_on Time.now
body :book_loan => book_loan
end
end
I am attempting to call this method from an action inside of my BooksController
def request_return
#book = Book.find(params[:id])
ReturnRequestMailer.please_return(#book.current_loan)
end
Which I invoke from my books index with the following link_to (ignoring for the time being that doing this in this manner probably isn't the smartest permanent solution).
<%= link_to 'Request Return', {:action => 'request_return' , :id => book} %>
Everything links up correctly but I get a NoMethodError in BooksController#request_return stating that it cannot find the method please_return for ReturnRequestMailer. What is going on that is preventing the please_return method from being visible to the BooksController?

add a 'deliver_' in front of your method so it will be :
def request_return
#book = Book.find(params[:id])
ReturnRequestMailer.deliver_please_return(#book.current_loan)
end
You don't need to define 'deliver_please_return' method, The method_missing method in ActionMailer will know to call please_return.

The Mailer in rails is usually used like this:
class ReturnRequestMailer < ActionMailer::Base
def please_return(book_loan)
subject 'Book Return Request'
recipients book_loan.person.email
from 'andrew.steele#west.cmu.edu'
sent_on Time.now
body :book_loan => book_loan
end
end
Then in the controller out deliver_ in front of the method name and call it as a class Method:
def request_return
#book = Book.find(params[:id])
NewsletterMailer.deliver_please_return(#book.current_loan)
end

Looking at your code it looks like the please_return method has been called as a class method, but you have defined it as an instance method. (for more detail on this see To use self. or not.. in Rails )
class ReturnRequestMailer < ActionMailer::Base
def self.please_return(book_loan)
...
should fix it.
Note this won't actual make it send the email, but will stop the NoMethodFound error.
As nasmorn states, you need to call ReturnRequestMailer.deliver_please_return to have the mail delivered.

Related

access "self" from view after sending mail (ruby on rails)

After a user signs up (Devise RegistrationController), I want to send them a welcome email.
Inside my User model, I created a function:
def send_welcome_email
UserMailer.welcome(self).deliver
end
Then I've added after_create :send_welcome_email
Inside the email view, I need to access variables.
<p><span><strong>Hi <%= self.name %>,</strong></span></p>
Returns an error:
undefined method `name' for #<#<Class:0x00007fa7d18e13b0>:0x00007fa7e4025358>
It makes sense that this would result in the error above, but I'm not sure how I can access variables from the model (that was just created).
I was following this asnwer: https://stackoverflow.com/a/17480095/9200273
Welcome method:
def welcome(user)
mail(
to: user.email,
subject: 'Welcome to Site!',
from: "support#site.com"
)
end
You can pass objects to the Mailer class using the with method like this:
UserMailer.with(user: self).welcome.deliver
Inside the UserMailer class:
def welcome_email
#user = params[:user]
...
end
In the view:
<%= #user.name %>
Reference: https://guides.rubyonrails.org/action_mailer_basics.html

is it possible to use an instance or variable in the subject of rails mailer and how please :)

I would like to use an instance or variable like below in the mailer subject.
So I would like to get the user name or some other user detail in the subject, I tried several thing but I receive an error every time. I can't find documentation about this either.
mail(:to => "test#gmail, :subject => "current_user.name") or "<%= current_user.name %>"
class PositionMailer < ActionMailer::Base
default from: "test#gmail.com"
layout 'mailer'
def general_message(position, barge_name)
#position = position
#barge_name = barge_name
mail(:to => "1234#gmail.com, :subject => "#{barge_name}")
end
end
controller
def create
#position = Position.new(position_params)
if #position.save!
redirect_to #position
PositionMailer.general_message(#position, #barge_name).deliver
To pass a variable inside quotes you need to do it like this "#{variable.value}
:subject => "#{current_user.name}"
should do it if it has access to current_user
You will have to pass current_user to the mailer along with the position value.
So wherever you are calling that from add current_user, probably looks something like this.
PositionMailer.general_message(position, current_user).deliver

call method from activemailer view

Is there a way to call a method from the actionMailer html file the same way a view can call to a method in a controller?
ActionMailer:
class ModelEmailerMailer < ActionMailer::Base
helper :application
layout 'model_email'
def user_mailer(user)
...
mail(to: user.formatted_email, subject: "email subject")
end
def function_call(user_info)
....
return modified_user_info
end
helper_method :function_call
ActionMailer View file 'model_email':
...
user.each do |a|
modified_user_info = function_call(a)
end
...
right now I don't even get an error message. I get an empty email with the correct subject, but no body.
EDIT 1: If I can't place the function in the actionmailer, can I create and link a separate controller to the view?

rails call method that should send email

So, I have an index page with grid of some students. With a button I would call an email method to send an email at all student in #students = Student.all
How to call the method ?
The params for the method is #students, is it right ?
<%= link_to 'Email', send_to_student_path(#students) %>
As I have seen here
StudentController.rb
def send_to_student()
#binding.pry
#students.each do |student|
StudentMailer.email_recall(student).deliver
end
end
And the Mailer :
class StudentMailer < ActionMailer::Base
def email_recall(student)
#url = 'http://example.com/login'
mail(to: #student.email,
from: current_user.email,
subject: 'Valid your datas')
end
end
In routes.rb I have :
resources :students do
member do
post :send_to_student
end
end
First question :
How can I pass id of each student from #students = Student.all in the method param ?
Second question :
How to call the send_to_student method in the right way ?
Many thanks in advance
Nicolas
1) The way you're using it, you'd pass the ID through the route, like: students/:id/send - you can read more about member routing on the Rails documentation. This will set a parameter of params[:id], which you can use in your action
Alternatively, if you're looking to send a message to all students, you can just use the controller function I created below:
2) I think you can typically use a Model Method for this. This is where you put a function in the model, cleaning up your controller
I don't know if it will work with the mailer, but I'd try this:
#app/controllers/students_controller.rb
def index
#students = Student.all
Student.send_to_students(#students)
end
#app/models/student.rb
def self.send_to_student(students)
students ||= self.all # -> not sure about the self.all call
students.each do |student|
StudentMailer.email_recall(student).deliver
end
end

Rails: Use URL Helper in Observer

I have an observer which looks like this:
class CommentObserver < ActiveRecord::Observer
include ActionView::Helpers::UrlHelper
def after_create(comment)
message = "#{link_to comment.user.full_name, user_path(comment.user)} commented on #{link_to 'your photo',photo_path(comment.photo)} of #{comment.photo.location(:min)}"
Notification.create(:user=>comment.photo.user,:message=>message)
end
end
Basically all I'm using it to do is create a simple notification message for a certain user when someone posts a comment on one of their photos.
This fails with an error message:
NoMethodError (undefined method `link_to' for #<CommentObserver:0x00000102fe9810>):
I would have expected including ActionView::Helpers::UrlHelper would solve that, but it seems to have no effect.
So, how can I include the URL helper in my observer, or else render this some other way? I would happily move the "message view" into a partial or something, but an observer has no associated views to move this to...
Why aren't you building the message when it's rendered out to the page and then caching it using something like this?
<% cache do %>
<%= render user.notifications %>
<% end %>
This would save you having to do a hack in the observer and would be more "standards compliant" in Rails.
To handle this type of thing, I made an AbstractController to generate the body of the email, then I pass that in as a variable to the mailer class:
class AbstractEmailController < AbstractController::Base
include AbstractController::Rendering
include AbstractController::Layouts
include AbstractController::Helpers
include AbstractController::Translation
include AbstractController::AssetPaths
include Rails.application.routes.url_helpers
include ActionView::Helpers::AssetTagHelper
# Uncomment if you want to use helpers
# defined in ApplicationHelper in your views
# helper ApplicationHelper
# Make sure your controller can find views
self.view_paths = "app/views"
self.assets_dir = '/app/public'
# You can define custom helper methods to be used in views here
# helper_method :current_admin
# def current_admin; nil; end
# for the requester to know that the acceptance email was sent
def generate_comment_notification(comment, host = ENV['RAILS_SERVER'])
render :partial => "photos/comment_notification", :locals => { :comment => comment, :host => host }
end
end
In my observer:
def after_create(comment)
email_body = AbstractEmailController.new.generate_comment_notification(comment)
MyMailer.new(comment.id, email_body)
end
So, it turns out this cannot be done for the same reason you can't use link_to in a mailer view. The observer has no information about the current request, and therefore cannot use the link helpers. You have to do it a different way.

Resources