I have a Rails 3 app sending emails to multiple (2) recipients. The first recipient is required, but the second is not required. I get an error if the second recipient is null. How do I bypass the secondary email if null without getting an error?
def email_approvers(invoice)
#subject = 'Invoice Approval Request'
#body["invoice"] = invoice
#recipients = invoice.approver_email, invoice.alternate_approver_email
#from = "..."
#sent_on = Time.now
#headers = {}
end
You should see http://edgeguides.rubyonrails.org/action_mailer_basics.html#complete-list-of-action-mailer-methods (2.3.4 Sending Email To Multiple Recipients). You can make an array with the emails (maybe in the class Invoice you can create a method that returns an array of valid emails).
In the mailer:
default :from => "..."
def email_approvers(invoice)
#data = invoice
mail :to => #data.recipients, :subject => 'Invoice Approval Request'
end
In the Invoice model:
def recipients
return alternate_approver_email.nil? ? [approver_email] : [approver_email, alternate_approver_email]
end
--
For your case (it will set the property to nil if there is no value, so the previous code will work):
def alternate_approver_email
self.alternate_approver_email = !self.alternate_approver_username.nil? ? self.alternate_approver_username + "#email.com" : nil
end
Related
I have these two tables - User, Accounts.
User contains an authentication key,
Accounts contains the list of accounts.
I am trying to get the list of accounts for the user if the authentication key is correct.
So in the controller I have -
def show
#user = User.where(authentication_token: params[:authentication_token])
render json: #user.as_json(
only: [:email, :id, :authentication_token]
),
status: :created
end
This would just return the user details. How can i edit it so it first checks if the user exists with that Authentication_token, and then uses the UserID, in the accounts table to get the list of accounts ?
Your question is a little unclear: What is the desired behaviour if the authentication_token is not correct? Raise an exception? Redirect somewhere? Display a flash message? ...
You could, for example, do something like this:
def show
if authenticated_user
render json: authenticated_user.accounts.as_json(
only: [:id, :foo, :bar]
),
status: :ok
else
render json: { errors: { authentication_token: 'Invalid' } },
status: :unauthorized
end
end
private
def authenticated_user
#authenticated_user ||= User.find_by(
authentication_token: params[:authentication_token]
)
end
I am trying to integrate Twilio with my Rails 4 app. I followed a tutorial, but I keep getting an error. Right now I am getting an Uninitialized Constant Error. I provided the code below. Thanks in advance.
Routes.rb
get '/share_over_sms' => 'listing_collections#share_over_sms'
Listing Collection Model
require "messenger"
def clean_number
client_number = self.client_number.scan(/\d+/).join
client_number[0] == "1" ? client_number[0] = '' : client_number
client_number unless client_number.length != 10
end
Messenger Module
module Messenger
def send_sms(number)
twilio_sid = "ENV['TWILIO_ACCOUNT_SID']"
twilio_token = "ENV['TWILIO_AUTH_TOKEN']"
#twilio_client = Twilio::REST::Client.new twilio_sid, twilio_token
from = '+1xxxxxxxxxx'
message = #twilio_client.account.sms.messages.create(
:from => from,
:to => "+1"+number,
:body => "This is a test message."
)
end
end
Listing Collections Controller
def share_over_sms
#client_phone = ClientPhone.new(listing_collection_params)
#client_phone.send_sms(#client_phone.clean_number)
redirect_to :back
end
I have a table called Materials and I have created a search form. In the form I want to have select boxes containing the names of the search options. So for example, if you want to search by subject, I want a dropdown with one of each of the subjects. I have code for this that works:
#subject = Material.unscoped.select(:subject).where("materials.subject IS NOT NULL
and materials.subject != '' ").uniq
This gives me what I want with the following form helper:
<%= select_tag "subject", options_from_collection_for_select(#subject, "subject",
"subject"), :include_blank => true, :class => "input_field" %>
BUT - I now want to select only those subjects from Materials that are shared. So I selected the shared Materials using:
#shared = Material.where(:status => 'shared')
And then ran this code:
#subject = #shared.unscoped.select(:subject).where("#shared.subject IS NOT NULL
and #shared.subject != '' ").uniq
Which doesn't work. I assume it's because the sql code can't understand the #shared object. But how to do this?
Note:
I tried using:
#subject = #shared.uniq.pluck(:subject).reject! { |s| s.empty? }
This gives an array of the right fields but then that doesn't work with options_from_collection_for_select.
You can create a scope for the shared query like this:
scope :shared, where(:status => 'shared')
And then you can chain ActiveRecord methods to your liking:
#subject = Material.select(:subject).where("materials.subject IS NOT NULL
AND materials.subject != '' ").shared.uniq
More on scopes here: http://guides.rubyonrails.org/active_record_querying.html#scopes
Try this
#subject = Material.unscoped.select(:subject).where("subject IS NOT NULL and materials.subject != '' and status = 'shared'").uniq
I would like to add an optional text_field to add an optional message to the invitation email. So if nothing put into the message then the standard message from invitation_instructions.html.erb should be send otherwise the message of the text_field.
How to do this in devise?
To accomplish this you can use your own mailer instead of having devise email things for you.
Here is how to do it:
class User < ActiveRecord::Base
attr_reader :raw_invitation_token
end
class InvitationsController < Devise::InvitationsController
def create
#from = params[:from]
#subject = params[:invite_subject]
#content = params[:invite_content]
#user = User.invite!(params[:user], current_user) do |u|
u.skip_invitation = true
end
#user.deliver_invitation
email = NotificationMailer.invite_message(#user, #from, #subject, #content)
end
end
class NotificationMailer < ActionMailer::Base
def invite_message(user, venue, 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.first_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
The raw_invitation_token only exists in newer versions of devise_invitable (compatible with devise >= 3.1).
We are essentially skipping the devise invitation process all together and using our own mailer. We take the content as a parameter and send it as the body of the email. We even substitute placeholders with their actual values.
This solution will give you a lot of flexibility to whatever you want with emails. You can even add a tracking pixel to it if you would like.
I am creating users from emails.
If an email exists I want to skip creating that user.
Here is my model method:
def invite_users(emails, board)
invalid_emails =[]
emails.each do |email|
user = User.new(:email => email)
user.save ? Participant.make(user, board) : invalid_emails << email unless user.errors.each {|key, msg| msg == "has already been taken"}
end
invalid_emails if invalid_emails.any?
end
I want to check if the error generated from user.save is a duplicate email error. If so I don't want to put that email in the invalid_emails array.
How can I do this?
validates_uniqueness_of is useless for such purposes.
The canonical thing to do is to add a unique index on email to the users table, and use code like:
begin
-- do stuff that creates records --
rescue ActiveRecord::StatementInvalid => e
raise unless /Mysql::Error: Duplicate entry/.match(e)
end
if you want to emulate create or find, you do something like
result = nil
begin
result = User.create(:email => xxxx)
rescue ActiveRecord::StatementInvalid => e
if /Mysql::Error: Duplicate entry/.match(e)
user = User.find_by_email(xxx)
else
raise
end
end
just change
user = User.new(:email => email)
user.save ? Participant.make(user, board) : invalid_emails << email unless user.errors.each {|key, msg| msg == "has already been taken"}
to
user = User.new(:email => email)
if User.find_by_email( email ).blank?
Participant.make(user, board)
else
invalid_emails << email
end
Since errors is basically an array you could just change each to any to get a boolean value for your condition.