I am trying to generate mails with rails action mailer, but it seems like it is not doing everything completely right:
Here's where I create my mail:
class UserNotifier < ActionMailer::Base
default from: 'mail#mail.com'
def forgot_password(user)
setup_email(user)
#subject += "Password restoration"
#url = url_for :controller => 'user_session', :action => 'reset_password',
:id => user.pw_reset_code, :only_path => true
end
protected
def setup_email(user)
#subject = "[MY APP] "
#sent_on = Time.now
#user = user
#content_type = "text/html"
mail to: user.email
end
end
And here's the html.erb that contains the mail.
<%= #user.name %>,
<br/><br/>
Restore password:
<%= #url %>
However, the subject of the mail is not what I said it should be.
But most importantly, #url is nil in the html.erb, however it is generated correctly in forgot_password, I tested it.
Why is it nil? And what can I do to render the URL?
Mails are sent when you call method deliver on ActionMailer::Base object.
Your method forgot_password does not return this object.
the line mail(to: .....) should be the last one in the forgot_password routine
Run rails console and type this to see what returns
ActionMailer::Base::mail(to: 'example.com', subject: 'hello')
then call #deliver on it.
The line
mail to: user.email
Is actually causing your email to send.
Because you are calling this in setup_email, you are actually sending the email AND THEN trying to change the subject and URL after it is sent.
If you ignore the setup method that you have for a second, this is what your code would look like in the order you currently have it:
#subject = "[MY APP] "
#sent_on = Time.now
#user = user
#content_type = "text/html"
mail to: user.email << MAIL IS SENT HERE
#subject += "Password restoration"
#url = url_for :controller => 'user_session', :action => 'reset_password',
:id => user.pw_reset_code, :only_path => true
Update your code to call the mail command last, for example:
def forgot_password(user)
setup_email(user)
#subject += "Password restoration"
#url = url_for :controller => 'user_session', :action => 'reset_password',
:id => user.pw_reset_code, :only_path => true
mail to: user.email
end
protected
def setup_email(user)
#subject = "[MY APP] "
#sent_on = Time.now
#user = user
#content_type = "text/html"
end
Related
I have 2 user-like models in my app: 'Participant' and 'Member'.
I'm trying to allow them to include a custom message when they invite other members/participants through Devise Invitable. However, I can't make it work.
I'm following this official tutorial so I've made the following changes to override Devise Invitable Controller but when using pry it seems that this custom controller goes untouched when sending an invite. What am I doing wrong:
controllers/participants/invitations_controller.rb
class Participants::InvitationsController < Devise::InvitationsController
before_action :update_sanitized_params, only: :update
def create
binding.pry
#from = params[:from]
#subject = params[:invite_subject]
#content = params[:invite_content]
#participant = Participant.invite!(params[:user], current_member) do |u| #XXX Check if :user should be changed
u.skip_invitation = true
end
ParticipantInvitationNotificationMailer.invite_message(#participant, #from, #subject, #content).deliver if #participant.errors.empty?
#participant.invitation_sent_at = Time.now.utc # mark invitation as delivered
if #participant.errors.empty?
flash[:notice] = "successfully sent invite to #{#participant.email}"
respond_with #participant, :location => root_path
else
render :new
end
end
def update
respond_to do |format|
format.js do
invitation_token = Devise.token_generator.digest(resource_class, :invitation_token, update_resource_params[:invitation_token])
self.resource = resource_class.where(invitation_token: invitation_token).first
resource.skip_password = true
resource.update_attributes update_resource_params.except(:invitation_token)
end
format.html do
super
end
end
end
protected
def update_sanitized_params
devise_parameter_sanitizer.permit(:accept_invitation, keys: [:password, :password_confirmation, :invitation_token, :username])
end
end
config/routes.rb
Rails.application.routes.draw do
devise_for :members, controllers: { invitations: "members/invitations" }
devise_for :participants, controllers: { invitations: "participants/invitations" }
end
models/participant.rb
class Participant < ApplicationRecord
attr_reader :raw_invitation_token
end
mailers/notification_mailer.rb
class NotificationMailer < ApplicationMailer
def invite_message(user, from, subject, content)
#user = user
#token = user.raw_invitation_token
invitation_link = accept_user_invitation_url(:invitation_token => #token)
mail(:from => from, :bcc => from, :to => #user.email, :subject => subject) do |format|
content = content.gsub '{{first_name}}', user.first_name
content = content.gsub '{{last_name}}', user.last_name
content = content.gsub '{{full_name}}', user.full_name
content = content.gsub('{{invitation_link}}', invitation_link)
format.text do
render :text => content
end
end
end
end
If I send an invitation:with Participant.invite!({:email => 'example#email.com'}, Member.first) the invitation is sent through the default mailer as shown in the console but not through my new mailer. why?
Rendering /Users/andres/.rvm/gems/ruby-2.4.0#pixiebob/gems/devise_invitable-1.7.1/app/views/devise/mailer/invitation_instructions.html.erb
Rendered /Users/andres/.rvm/gems/ruby-2.4.0#pixiebob/gems/devise_invitable-1.7.1/app/views/devise/mailer/invitation_instructions.html.erb (0.6ms)
Rendering /Users/andres/.rvm/gems/ruby-2.4.0#pixiebob/gems/devise_invitable-1.7.1/app/views/devise/mailer/invitation_instructions.text.erb
Rendered /Users/andres/.rvm/gems/ruby-2.4.0#pixiebob/gems/devise_invitable-1.7.1/app/views/devise/mailer/invitation_instructions.text.erb (0.8ms)
Finally, I could solve this issue.
It ended up being a rookie mistake I was thinking that calling the invite! method would have anything to do with the custom create method in the custom invitations controller.
I had of course to reach the create method through the specified route and within that method prevent the invite! method to send the email through the default mailer using code below (as established clearly in the Devise Invitable Documentation):
#participant = Participant.invite!({:email => #invitation_draft.email}, current_member) do |u|
u.skip_invitation = true
end
After this we can call any custom mailer in the create method.
I'm trying so send an email like this
mail(:to => #user.email, :from => from_email, :subject => t('orders.invoice.email_subject'), :content_type => "text/html") do |format|
format.html { render partial: "notifier/follow_up_email.#{I18n.locale}.html.erb", locals: {storefront: storefront, order: order} }
end
Unfortunately, rails is only looking for follow_up_email.en.html and not follow_up_email.en.html.erb - What am I doing wrong?
render partial: ... should not contain file extensions such as en.html.erb since they are automagically added.
http://api.rubyonrails.org/classes/ActionView/PartialRenderer.html
But why do you use partials for mails, couldn't you create a proper view?
UPDATE
It's all described in the guide on http://guides.rubyonrails.org/v3.2.16/action_mailer_basics.html
app/mailers/user_mailer.rb:
class UserMailer < ActionMailer::Base
default from: "no-reply#memyselfandi.com"
def notification(user, storefront, order)
#user, #storefront, #order = user, storefront, order
I18n.locale = #user.locale # see note below
mail to: #user.email, subject: I18n.t('orders.invoice.email_subject')
end
end
app/views/user_mailer/notification.en.html.erb:
<html><body>
This is a mail for <%= #user.email %> yadda yadda. Use #storefront and #order here.
</body></html>
app/views/user_mailer/notification.de.html.erb:
<html><body>
Das ist ein mail für <%= #user.email %> bla bla.
</body></html>
The line I18n.locale = #user.locale is only necessary if you want to send async mails e.g. when triggering rake tasks from a cronjob.
I want to be able to send a new user's ip address to my admin account when a new user signs up. I have:
class UserMailer < ActionMailer::Base
default :from => '"Admin" <support#mysite.com>'
def registration_confirmation(user)
#user = user #needed in order to have access to user variables
def client_ip
#client_ip = request.remote_ip
end
mail(:to => "#{user.name} <#{user.email}>", :subject => "Welcome to MySite").deliver!
mail(:to => '"Admin" <support#mysite.com>',
:subject => "New Member",
:body => "New member #{user.name} with email #{user.email} and ip: #{#client_ip} has just signed up!",
:content_type => "text/html")
end
end
I'm getting the error:
NameError in UsersController#create
undefined local variable or method `request' for #
users_controller.rb
def create
#user = User.new(params[:user])
if #user.save
UserMailer.registration_confirmation(#user).deliver
sign_in #user
redirect_to #user
else
render 'new'
end
end
Something like:
def create
#user = User.new(params[:user])
if #user.save
UserMailer.registration_confirmation(#user, request.remote_ip).deliver
sign_in #user
redirect_to #user
else
render 'new'
end
end
def registration_confirmation(user, client_ip = '0.0.0.0')
#user = user #needed in order to have access to user variables
mail(:to => "#{user.name} <#{user.email}>", :subject => "Welcome to MySite").deliver!
mail(:to => '"Admin" <support#mysite.com>',
:subject => "New Member",
:body => "New member #{user.name} with email #{user.email} and ip: #{client_ip} has just signed up!",
:content_type => "text/html")
end
You only have access to the request object in the controller/view. So you need to pass the value along to the mailer if that is where you want to have access to it.
I am attempting to create beta invitations using the structure from railscasts episode 124, updated for rails 3.2.8.
Currently, the invitation email gets sent, but does not contain the url (which includes the invitation token) for users to follow to sign up because the instance variable I am creating in ActionMailer (#invitation_link) is nil in the view. Inspecting #invitation_link in the ActionMailer controller shows that it is pointing to the correct url, but it is nil in the view.
I have also checked out the following questions and none of the solutions have worked for me:
How do you use an instance variable with mailer in Ruby on Rails?
https://stackoverflow.com/questions/5831038/unable-to-access-instance-variable-in-mailer-view
Actionmailer instance variable problem Ruby on Rails
ActionMailer pass local variables to the erb template
Relevant code snippets below:
invitations_controller.rb
class InvitationsController < ApplicationController
def new
#invitation = Invitation.new
end
def create
#invitation = Invitation.new(params[:invitation])
#invitation.sender = current_user
if #invitation.save
if signed_in?
InvitationMailer.invitation(#invitation).deliver
flash[:notice] = "Thank you, invitation sent."
redirect_to current_user
else
flash[:notice] = "Thank you, we will notify when we are ready."
redirect_to root_url
end
else
render :action => 'new'
end
end
end
in invitation_mailer.rb file
class InvitationMailer < ActionMailer::Base
default from: "holler#thesite.com", content_type: "text/html"
def invitation(invitation)
mail to: invitation.recipient_email, subject: "Invitation"
#invitation_link = invited_url(invitation.token)
invitation.update_attribute(:sent_at, Time.now)
end
end
views/invitation_mailer/invitation.text.erb
You are invited to join the site!
<%= #invitation_link %> # INSTANCE VARIABLE THAT IS NIL IN VIEW
routes.rb (only showing relevant line)
match '/invited/:invitation_token', to: 'users#new_invitee', as: 'invited'
try this way
This is your InvitationMailer
def invitation(invitation)
#invitation = invitation
mail(:to => #invitation.recipient_email, :subject => "Invitation")
end
now, in your InvitationsController
if signed_in?
#invitation.update_attribute(:sent_at, Time.now)
InvitationMailer.invitation(#invitation).deliver
...
else
...
end
now, views/invitation_mailer/invitation.text.erb
You are invited to join the site!
<%= invited_url(#invitation.token) %> # INSTANCE VARIABLE THAT IS NIL IN VIEW
try this...
#invitation_link = invited_url(invitation.token, :host => "localhost:3000")
In my ROR app, I am trying to send confirmation emails to my registered users when they signup, my website is on localhost currently. I am getting this error:
"undefined method `recipients' for #<UserMailer:0x3d841a0>"
Here is my code;
development.rb
config.action_mailer.delivery_method = :smtp
config.action_mailer.default_url_options = { :host => "localhost:3000"}
config.action_mailer.smtp_settings = {
:address => "smtp.gmail.com",
:port => "587",
:authentication => :login,
:user_name => "myemailid#gmail.com",
:password => "myrealpassword"
}
Users_controller.rb
def new
UserMailer.registration_confirmation(#user).deliver
end
def create
#user = User.new(params[:user])
if #user.save
UserMailer.registration_confirmation(#user).deliver
sign_in #user
flash[:success] = "Welcome!"
redirect_to #user
else
render 'new'
end
end
user_mailer.rb
class UserMailer < ActionMailer::Base
def registration_confirmation(user)
recipients user.email
from "myemailid#gmail.com"
subject "Thank you for registration"
body :user => user
end
end
** development.rb**
config.action_mailer.delivery_method = :sendmail
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
** Users_controller.rb **
def new
UserMailer.registration_confirmation(#user).deliver
end
def create
#user = User.new(params[:user])
if #user.save
UserMailer.registration_confirmation(#user).deliver
sign_in #user
flash[:success] = "Welcome!"
redirect_to #user
else
render 'new'
end
end
** User_mailer.rb **
def registration_confirmation(user)
#message = 'whatever you want to say here!'
mail(:from => "myemailid#gmail.com", :to => user.email, :subject => "Thank you for registration")
end
**/app/views/user_mailer/registration_confirmation.text.erb *
<%= #message %>
That's what I've done in my development mode, and it works
What version of Rails are you using?
Sending of email changed in version 3.2 (I believe)
http://api.rubyonrails.org/classes/ActionMailer/Base.html
Try:
UserMailer.registration_confirmation(#user).deliver
This is your user_mailer.rb
user_mailer.rb
class UserMailer < ActionMailer::Base
def registration_confirmation(user)
recipients user.email
from "myemailid#gmail.com"
subject "Thank you for registration"
body :user => user
end
Try instead:
class UserMailer < ActionMailer::Base
default from: "myemailid#gmail.com"
def registration_confirmation(user)
mail(to: user.email, subject: "Thank you for registration")
end
end
And set up the appropriate view in views/user_mailer e.g. registration_confirmation.html.erb