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
Related
I am on ch11 of Hartl's rails tutorial, section 11.2.1 Mailer Templates, The preview for the password reset mailer works fine but the account_activation preview does not. the error actually changed even though i didn't make any changes to the code, which was confusing. However the error that I am currently receiving is
NoMethodError in Rails::Mailers#preview
Showing /home/ubuntu/workspace/sample_app/app/views/user_mailer/account_activation.html.erb where line #3 raised:
undefined method `name' for nil:NilClass
Extracted source (around line #3)
<h1>Sample App</h1>
<p>Hi <%=#user.name %>,</p>
<p>
Welcome to the Sample App! Click on the link below to activate your account:
here is my user_mailer.rb
class UserMailer < ApplicationMailer
def account_activation(user)
#user = user
mail to: user.email, subject: "Account activation"
end
def account_activation
#greeting = "Hi"
mail to: "to#example.org"
end
def password_reset
#greeting = "Hi"
mail to: "to#example.org"
end
end
account_activations_controller.rb (no code has been specified so far in the tutorial)
class AccountActivationsController < ApplicationController
end
and the source of the error account_activation.html.erb
<h1>Sample App</h1>
<p>Hi <%=#user.name %>,</p>
<p>
Welcome to the Sample App! Click on the link below to activate your account:
</p>
<%= link_to "Activate", edit_account_activation_url(#user.activation_token,
email: #user.email) %>
it seems to not be recognising the name of the user. why could this be? (Note: all code is copied from the tutorial so i am at a loss as to the reason for the error)
thanks.
EDIT:As per the comment there wer indeed 2 account_activation methods. i have deleted the second one and kept the first. Now the error has changed to an argument error.
ArgumentError in Rails::MailersController#preview
wrong number of arguments (given 0, expected 1)
def account_activation(user)
#user = user
mail to: user.email, subject: "Account activation"
end
This method seems to be used in the following file without an argument.
/sample_app/test/mailers/previews/user_mailer_preview.rb
class UserMailerPreview < ActionMailer::Preview
# Preview this email at http://localhost:3000/rails/mailers/user_mailer/account_activation
def account_activation
user = User.first
user.activation_token = User.new_token
UserMailer.account_activation(user)
UserMailer.account_activation
end
# Preview this email at http://localhost:3000/rails/mailers/user_mailer/password_reset
def password_reset
UserMailer.password_reset
end
end
In your UserMailer you currently have 2 versions of the account_activation method - one that takes a user parameter and a second one that doesn't. In Ruby you can't have 2 methods in a class with the same name so that second method will be replacing the earlier one.
I'm not familiar with with all the contents of this tutorial, but it seems likely the method without the parameter is from earlier in the tutorial and should have been removed now.
Then you will need to check the code where you're calling UserMailer.account_activation.deliver... and update it to be passing a user.
Update
In user_mailer_preview.rb you are calling account_activation twice:
...
UserMailer.account_activation(user)
UserMailer.account_activation
...
The call without user should be removed.
I'm trying to figure out how to setup a mailer class in my Rails 4 app.
I have made a mailer called admin_notes. I want to use it to send emails to the internal team when certain actions are taken across the site.
In my mailer/admin_note.rb, I have:
class AdminNote < ApplicationMailer
def unknown_organisation(organisation_request, user_full_name, name)
#organisation_request =
#user_full_name =
#organisation_request.name =
# #greeting = "Hi"
mail( to: "test#testerongmail.com",from: "test#testerongmail.com", subject: "A new organisation")
end
end
I have an organisation_requests model. It has:
class OrganisationRequest < ActiveRecord::Base
belongs_to :profile
delegate :user_full_name, to: :profile, prefix: false, allow_nil: true
The organisation request table has an attribute called :name in it.
When a new organisation request is created, I want to send an admin note to the internal team, alerting someone to start a process.
I'm struggling to figure out how I define the three variables in the mailer method.
I plan to add the send email call to the create action in the organisation requests controller.
How can I set these variables?
Form to create an organisation request is:
<%= simple_form_for(#organisation_request) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :organisation_id, collection: #all_organisations << ['other', nil] %>
</div>
<div class="form-inputs">
<%= f.input :name %>
</div>
<div class="form-actions">
<%= f.button :submit, "Create", :class => 'formsubmit' %>
</div>
<% end %>
NEW ATTEMPT:
I have a create action in my organisation controller, I added this service class request for an email:
def create
#organisation_request = OrganisationRequest.new(organisation_request_params)
#organisation_request.profile_id = current_user.profile.id
if #organisation_request.save
NewOrgRequestService.send_unknown_organisation_requested_flag(organisation_request)
return redirect_to(profile_path(current_user.profile),
flash[:alert] => 'Your request is being processed.')
else
# Failure scenario below
#all_organisations = Organisation.select(:title, :id).map { |org| [org.title, org.id] }
render :new
end
end
I then have a services/organisations requests/NewOrgRequestService.rb
class OrganisationRequest < ActiveRecord::Base
class NewOrgRequestService
attr_accessor :organisation_request
def self.send_unknown_organisation_requested_flag(organisation_request)
if #organisation_request.name.present?
AdminNote.unknown_organisation_requested(organisation_request, user_full_name, name).deliver_later
end
end
end
end
The AdminNote mailer has:
class AdminNote < ApplicationMailer
layout 'transactional_mailer'
def unknown_organisation_requested(organisation_request, user_full_name, name)
#organisation_request = #organisation_request
#user_full_name = #organisation_request.user_full_name
#name = organisation_request.name
# #greeting = "Hi"
mail
to: "test#testerongmail.com",from: "test#testerongmail.com", subject: "A new organisation"
end
end
This doesnt work, but I'm wondering if Im on the right track? Im not sure if the create action in the controller needs to have some kind of reference to the services/organisation_requests/ path that gets to the file??
I think I may have made a bigger mess than I started with - but I'm out of ideas for things to try next.
This may help you.
In your mailer method
def unknown_organisation(org,user)
#org = org
#user = user
mail(to: "test#testerongmail.com",from: "test#testerongmail.com", subject: "A new organisation")
end
In your controller method after saving organization_request and this is how you set your variable. You can pass variable you want.
AdminNote.unknown_organization(#organization_request, current_user).deliver_now
In your mailer template access passed value as you do in action view. And this is how you use your variable.
<%= #org.name %>
<%= #org.full_name %>
Hope this helps
If you want to queue message or send later you can use ActiveJob to send mails in the background.
For more, see http://guides.rubyonrails.org/active_job_basics.html
I know I am super late but here I go.
I understand that you are trying to send in some parameters (values) to mailer so that you can use it while sending an email.
To do so you just need to define a mailer method that accepts some parameters. What you have done is right in your AdminNote Mailer unknown_organization method.
Let's get to your NEW ATTEMPT.
Everything you have done there seems about right except you are passing an undefined variable organization_request. You have created an instance variable #organization_request but you are passing something that is not defined. Here
NewOrgRequestService.send_unknown_organisation_requested_flag(organisation_request)
That is your first problem. This can be improved as:
Your Organizations#create
def create
#organisation_request = OrganisationRequest.new(organisation_request_params)
#organisation_request.profile_id = current_user.profile.id
if #organisation_request.save
#organisation_request.send_unknown_organisation_requested_flag
redirect_to(profile_path(current_user.profile),
flash[:alert] => 'Your request is being processed.')
else
# Failure scenario below
#all_organisations = Organisation.select(:title, :id).map { |org| [org.title, org.id] }
render :new
end
end
And your model can be as follows:
class OrganisationRequest < ActiveRecord::Base
def send_unknown_organisation_requested_flag
if self.name.present?
AdminNote.unknown_organisation_requested(self).deliver_later
end
end
end
I don't know why you are defining a class inside your model class.
Your Mailer should look like below:
class AdminNote < ApplicationMailer
layout 'transactional_mailer'
def unknown_organisation_requested(organisation_request)
#organisation_request = organisation_request
#user_full_name = #organisation_request.user_full_name
#name = organisation_request.name
# #greeting = "Hi"
mail
to: "test#testerongmail.com",from: "test#testerongmail.com", subject: "A new organisation"
end
end
There are a lot of typos and method implementation errors here.
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?
I am new to Rails and struggling with how to implement dynamic values in my mailer.
The below code all works fine apart from the reply_to which I want a dynamic value but I don't know how to do this.
The params #name, #email, #message are captured on a form and I want the reply_to values to be the same as the params passed from #email.
So, essentially the point of this is someone can book an event and then it will email their details to the event manager who can then just press "reply" and it will reply back to the email the user filled out on the form.
class BookingMailer < ActionMailer::Base
default from: "notifications#example.com"
default reply_to: #email
def contact_mailer(name,email,message)
#name = name
#email = email
#message = message
mail(to: 'info#example.com', subject: 'Event Booking', reply_to: #email)
end
end
I looked on the API docs but they seem to reference users in a database when using dynamic values.
Any help is much appreciated, thanks!
You only set a default value if you wanted to use something for methods that DON'T have an option set (for example, you've set a default from:, so you don't need to set mail(from: "notifications#example.com"...) each time, it'll use the default if not set).
Providing your controller is passing the email address as the second argument then your code should work, although usually I'd pass a booking:
class BookingController < ApplicationController
def create
#booking = Booking.new(safe_params)
if #booking.save
BookingMailer.contact_mailer(#booking).deliver
else
# alarums!
end
end
end
Then extract the info you want from that in your mailer:
class BookingMailer < ActionMailer::Base
default from: 'blah#blah.com'
def contact_mailer(booking)
#booking = booking
mail(to: 'info#example.com', subject: 'Event booking', reply_to: #booking.email)
end
end
Ideally you should remove the line default reply_to: #email as it's trying to use a class level instance variable #email, instead of the instance variable #email that you intended. For examples on the differences between class variables, instance variables and class instance variables, see here: http://www.railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/
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.