So I need my mailer to send attachments that the user uploads in the form upon creation. I used cocoon and paperclip to attach multiple files in the form.
Here is my object_controller:
class RfqsController < ApplicationController
...
def create
#object= Rfq.new(rfq_params)
respond_to do |format|
if #object.save
Object_mailer.object_message(current_user, #object).deliver
format.html { redirect_to #object, notice: 'object was successfully created.' }
format.html { render :new }
end
end
end
...
This will send the email with multiple attachments
class ObjectMailer < ApplicationMailer
default from: "test#test.com"
def placeholder_message(user, rfq)
#user = user
object.object_attachments.each do |attachment|
attachments[attachment.attachment_file_file_name] = File.read(attachment.attachment_file.path)
end
mail to: user.email, subject: "test"
end
end
Related
I am implementing a new app with following business process:
User fill in a registration form.
Once registration form is being saved, a new Training Company is created
User get an e-mail with a pdf with his registration form and unique url
User uses unique url to attach signed registration form Admin can accept or reject
What is the best approach to Training Company creation?
First solution: new service that creates a TrainingCompany
class TrainingCompanyService
def initialize(company_name)
#name = company_name
end
def create_new_training_company
TrainingCompany.new(company_name: #name).save
end
end
create action in RegistrationFormController:
def create
#registration_form = RegistrationForm.new(registration_form_params)
respond_to do |format|
if #registration_form.save
format.html { redirect_to #registration_form, notice: 'Registration form was successfully created.' }
TrainingCompanyService.new(#registration_form.company_name).create_new_training_company
RegistrationFormMailer.with(registration_form: #registration_form).after_registration_email.deliver_later
else
format.html { render :new }
end
end
end
Second solution: new method inside TrainingCompany model:
class RegistrationForm < ApplicationRecord
belongs_to :training_company, optional: true
has_one_attached :registration_form
has_secure_token :signed_form_upload_token
def create_new_training_company
TrainingCompany.new(company_name: self.company_name, registration_form_id: self.id).save
end
end
create action in RegistrationFormController:
def create
#registration_form = RegistrationForm.new(registration_form_params)
respond_to do |format|
if #registration_form.save && #registration_form.create_new_training_company
format.html { redirect_to #registration_form, notice: 'Registration form was successfully created.' }
RegistrationFormMailer.with(registration_form: #registration_form).after_registration_email.deliver_later
else
format.html { render :new }
end
end
end
Which solution would you choose and why? Personally i prefer the second one (new method inside the model)...
I have a model for a client, when I create a new client it creates a User with the client email. The same thing happens when I create an Affiliate. Can I use validates_uniqueness_of the email in both Client and user at the same time?
Or should I do something like, before save check if there is a User with the same email, and print an error?
I tried this, but it doesn't work
validate :uniqueness_of_user
private
def uniqueness_of_user
#user = User.find_by_email(:email)
if #user.present?
errors.add(:email, "Bang!")
end
end
Edit:
This is the controller:
def create
#affiliate = Affiliate.new(affiliate_params)
respond_to do |format|
if verify_recaptcha(model: #affiliate) && #affiliate.save
#user = User.create!(user_parameter)
pplicationMailer.confirmation(#affiliate).deliver_now
format.html {redirect_to :back, notice: 'Thanks for your submission, we will be in touch shortly. Check your email for your affiliate number and password.' }
format.json { render :show, status: :created, location: #affiliate }
else
format.html { render :signup, layout: "sign-ups" }
format.json { render json: #affiliate.errors, status: :unprocessable_entity }
end
end
end
I would have preferred to save the email_address in a different table. for example: address
class Address < ApplicationRecord
belongs_to :affilat
belongs_to :client
validates :email,
presence: true
uniqueness: true
end
and use nested form to save date here.
Check below code for a good article about this case, I copied the code but for full explanation check the article link :
# app/models/concerns/validate_identifier_uniqueness_across_models.rb
module ValidateIdentifierUniquenessAcrossModels
extend ActiveSupport::Concern
##included_classes = []
included do
##included_classes << self
validate :identifier_unique_across_all_models
end
private
def identifier_unique_across_all_models
return if self.identifier.blank?
##included_classes.each do |klass|
scope = klass.where(identifier: self.identifier)
if self.persisted? && klass == self.class
scope = scope.where('id != ?', self.id)
end
if scope.any?
self.errors.add :identifier, 'is already taken'
break
end
end
end
end
# app/models/product.rb
class Product < ActiveRecord::Base
include ValidateIdentifierUniquenessAcrossModels
end
# app/models/category.rb
class Category < ActiveRecord::Base
include ValidateIdentifierUniquenessAcrossModels
end
Reference:
https://www.krautcomputing.com/blog/2015/03/29/rails-validate-uniqueness-across-models/
UPDATE:
Solution 1 If data are saved at the same time, then the best thing is to include the data saved together in a Transaction as below:
def create
email_validity
#affiliate = Affiliate.new(affiliate_params)
respond_to do |format|
ActiveRecord::Base.transaction do
if verify_recaptcha(model: #affiliate) && #affiliate.save
#user = User.create!(user_parameter)
if #user.valid?
ApplicationMailer.confirmation(#affiliate).deliver_now
format.html {redirect_to :back, notice: 'Thanks for your submission, we will be in touch shortly. Check your email for your affiliate number and password.'}
format.json {render :show, status: :created, location: #affiliate}
else
email_validity = false
raise ActiveRecord::Rollback
end
else
format.html {render :signup, layout: "sign-ups"}
format.json {render json: #affiliate.errors, status: :unprocessable_entity}
end
end
if email_validity == false
respond_to do |format|
format.html {redirect_to :back, notice: 'Sorry, email is in use!'}
# you can add your json return as you like
end
end
end
end
Reference:
http://api.rubyonrails.org/classes/ActiveRecord/Rollback.html
Solution 2 before saving to affiliate or creating a user, check in both tables for email existence in your controller.
I want to send a email to user after create something via rails admin.
I know I can call it in model callback but it's not considered as a good pratices
the best way is to put the actionmailer action after model save in the controller but I don't know how to do it in rails_admin controller
class UsersController < ApplicationController
# POST /users
# POST /users.json
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
# Tell the UserMailer to send a welcome email after save
UserMailer.welcome_email(#user).deliver_later
format.html { redirect_to(#user, notice: 'User was successfully created.') }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
end
What you want to do is not easy on rails admin because you cannot modify the controllers nor do you have access to them without monkey patching them.
I actually made a fork of rails admin for this functionality checkout the commit with the changes:
https://github.com/aliada-mx/rails_admin/commit/6251554efd1d83cdb418f42683ee55a4e27c2474
Just touched two files
And example usage
class User
after_save :on_admin_updates
attr_accessor :edited_in_rails_admin
def on_admin_updates
return unless edited_in_rails_admin
self.edited_in_rails_admin = false
UserMailer.welcome_email(self.id)
end
end
A bit clunky i know, PR´s welcome.
Have you tried to include your Mailer in admin_controller?
include UserMailer
Then in your create action UserMailer.some_mailer_action.deliver_now
i have a rails model registrations that has the following fields
attr_accessible :address, :company, :name, :phone, :email
i have successfully been able to send a mail to the user via the email fielded in by the user and that works succesfully using action mailer
def create
#registration = Registration.new(params[:registration])
respond_to do |format|
if #registration.save
UserMailer.registration_confirmation(#registration).deliver
format.html { redirect_to root_path, notice:" Thanks! #{#registration.name}, Your registration have been
confirmed & your seat reserved" }
format.json { render :show, status: :created, location: #registration }
else
format.html { render action: "new" }
format.json { render json: #registration.errors, status: :unprocessable_entity }
end
end
end
and the registration mailer is as thus
def registration_confirmation(registration)
#registration = registration
#greeting = "Hi"
mail(to: #registration.email, subject: 'Welcome')
end
which works very well...
All i want to achieve is to be able to send a mail to another email address e.g (admin#gmail.com) stating that a user as registered and also showing the registration details ... thanks
I would generate a new mailer specifically for notifications that should be sent to the administrator.
rails g mailer AdminMailer registration_notice
You could then edit the AdminMailer registration_notice to be similar to your UserMailer, but with a different recipient:
def registration_notice(registration)
#registration = registration
mail(to: 'admin#gmail.com', subject: 'A new user has registered')
end
Put whatever registration details you would like to include into the views for registration_notice.html.erb (or text).
Then just add the call to the mailer in the create action of the controller, right after the call to the UserMailer:
def create
#registration = Registration.new(params[:registration])
respond_to do |format|
if #registration.save
UserMailer.registration_confirmation(#registration).deliver
AdminMailer.registration_notice(#registration).deliver
# etc
end
end
end
You'd probably also want to consider sending the mails in the background instead of making the user wait for the create request to finish, but that's beyond the scope of this question.
Here is a brief snippet from the guide on ActionMailer
class UserMailer < ActionMailer::Base
default :from => "notifications#example.com"
def welcome_email(user)
#user = user
#url = "http://example.com/login"
mail(:to => user.email,
:subject => "Welcome to My Awesome Site")
end
end
And in the controller
class UsersController < ApplicationController
# POST /users
# POST /users.xml
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
# Tell the UserMailer to send a welcome Email after save
UserMailer.welcome_email(#user).deliver
format.html { redirect_to(#user, :notice => 'User was successfully created.') }
format.xml { render :xml => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
end
So why is Rails trying to confuse rubyist with instance methods as class methods? I assume they've overridden missing method, but it just serves to confuse! Or am I missing something here?
ie why not define welcome_email as def self.welcome_email(user)
If it was #self.welcome_email you'd have to create an instance of the class yourself, which requires some configuration for all the default params etc. Rails is just providing factory methods of the same name.
From a quick look at the source code, you're right, it does seem to use method_missing, where the mailer is actually created with:
mailer = TheMailer.new(:welcome_email, *args)
Rails does a lot of "voodoo" things like this, generally just to save the amount of code you write. Just changing #welcome_email to be a class method would not give you an instance.