Replacing a substring with a link on the fly - ruby-on-rails

In my app, I store emails.
I want to parse those emails for email addresses in the text, on the fly and replace them with a link (so that we send the email through the app).
e.g.
#email.body = "Hi Tom, Drop me a line at jerry#cheese.com."
I want some sort of helper that will translate that on the fly to:
#email.sanitized_body
"Hi Tom, Drop me a line at #{link_to "Email", email_send_email_path("jerry#cheese.com")}."
I've been around a few circles.
e.g. in a model
Class Email
def sanitized_body
text = self.body
emails = text.scan(/\b[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\b/i)
emails.each do |email|
text.gsub!("jerry#cheese.com", helper.link_to("email", "http://www.google.com"))
end
text
end
I'm sure there's a sensible way of doing this, probably with a helper but can't quite work it out...
module EmailsHelper
def sanitized_body(email_body)
text = email_body
emails = text.scan(/\b[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\b/i)
emails.each do |email|
text.gsub!("jerry#cheese.com", "#{link_to("email", "http://www.google.com")}")
end
text
end
end
Gets me almost there. But the text comes out as text in the string when displayed.
Any help much appreciated.

You should use html_safe for your text to be rendered as HTML code instead of a simple string.
module EmailsHelper
def sanitized_body(email_body)
text = email_body
emails = text.scan(/\b[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\b/i)
replace_text = "You text %s" % helper.link_to("email", "http://www.google.com")
emails.each do |email|
text.gsub!("jerry#cheese.com", replace_text.html_safe)
end
text
end
end

Related

How to filter out inactive emails from an array of emails in a rails application?

I am currently working on a ticket where it asks me to filter out any inactive email to be sent to the recipient. Here is the method I am working on:
def self.delivering_email(message)
return if email_to_be_delivered?(message.subject)
email_list = message.to
if email_list.is_a?(String)
email_list = email_list.split(",").map(&:strip)
end
email_list.each { |email|
identity = Identity.find_by(email: email)
next if identity.nil?
# email_list.delete(email) unless identity.try(:preferred_user).active?
email_list.select(email) if identity.try(:preferred_user).active?
}
message.to = email_list
message.perform_deliveries = !email_list.empty?
end
the "# email_list.delete(email) unless identity.try(:preferred_user).active?" I commented out because the QA mentioned that ONLY one inactive email filters out and does not fully filter other inactive emails in the array. I assumed instead of .delete I have to use .select but don't know if it works because I don't have any way to test and reproduce the error on my end, or how to implement it the right way.
Any help will be appreciated.
You're trying to modify an array while you're iterating over it, that may lead to weird behavior. One option is to just use a separate array.
Since you are already iterating with email_list.each you can call next if the current email does not satisfy you, like you already do for identity.nil?.
So it may look smth like
valid_emails = []
email_list.each { |email|
identity = Identity.find_by(email: email)
next if identity.nil? || !identity.try(:preferred_user).active?
valid_emails << email
end
message.to = valid_emails

Have to add a simple condition in Rails

I have to setup my rails project to send a confirmation SMS to new users. I have a table phone_calling_codes which has a column sms_enable_flag. In my DB this field has to be checked or not, so it's boolean.
I use Twilio to send SMS but I want to add a condition to send SMS only to the numbers where this sms_enable_flag is checked.
I also use phonelib to parse the number and take the country code from it.
def perform(phone_number, confirmation_code)
logger.info("Job started sending confirmation code")
overrideToPhone = [ "development","upgrade"].include? Rails.env
deliverSMS = !([ "development", "upgrade"].include? Rails.env)
phone=''
if overrideToPhone
e164Prefix = '+'
phone_number = e164Prefix + "17782002024"
else
phone = Phonelib.parse( phone_number)
phone_number = phone.e164
end
sms=phone_calling_codes.find_by calling_code: phone.country_code
if sms
if sms.sms_enabled_flag
from_phone_number = Rails.application.secrets.twilio_number
body = "Valorbit.com - your phone verification code is: #{confirmation_code}"
logger.info("From #{from_phone_number} to #{phone_number} : #{body}")
twilio_client.messages.create(
to: phone_number ,
from: from_phone_number ,
body: body
) if deliverSMS
logger.info("Sent sms to #{phone_number}") if deliverSMS
else
logger.info("SMS is not enabled for #{phone_number}")
end
end
end
Please help me to this. I am a beginner to OOP and I want to understand if it is ok how I have thought.
Thanks! :D
change line
sms=phone_calling_codes.find_by calling_code: phone.country_code
to
sms=PhoneCallingCode.find_by calling_code: phone.country_code
PhoneCallingCode is the model name present in /app/models folder
Below is the query to find data from model:
ModelName.find_by column_name: parameter

How to create a multipart ical email? [Rails]

What I want to achieve is the following:
Send an email with delayed_job containing:
plain-text
html (will be displayed by regular clients which don't understand the inline ical)
"inline" ical which is recognized by Outlook and Thunderbird (with Lightning).
a "regular" ical attachment (for #2)
What works so far/what does'nt:
I am able to send the email via delayed_job with all parts, however:
in Apple's Mail 2 attachments show up (instead of one):
(the html is displayed fine)
in Thunderbird (Lightning) I do get an invitation, just like I want. But the Alarm does not show up.
I have to do some REALLY disgusting gsubs on the rendered iCal in order for the ATTENDEES to show up. (see code snippet)
My thinking:
The first thing to keep in mind is: in order to send an email with attachments from delayed_job
To fix this, remember to add this line to your mailer: content_type "multipart/mixed"
As far as I understand the correct MIME-Type hierarchy would therefore be:
multipart/mixed
multipart/alternative
text/plain
text/html
text/calendar (with: method=REQUEST)
application/ics
Warning! code incoming.
I currently construct this email in the following manner:
Edit: I updated the mailer for Rails 4.2 (attachments must be placed before mail)
in my mailer.rb
def invitation_email(...)
subject = "I suck at email..."
attachments["invite.ics"] = { mime_type: "application/ics",
content: ical_attachment }
email = mail(from: me, to: you, subject: subject)
add_ical_part_to(email)
email
end
def add_ical_part_to(mail)
outlook_body = ical_attachment
mail.add_part(Mail::Part.new do
content_type "text/calendar; method=REQUEST"
body outlook_body
end)
end
and this is how I construct the ical attachments:
def ical_attachment
params_participant = {
"ROLE" => "REQ-PARTICIPANT",
"RSVP" => "FALSE",
"PARTSTAT" => "ACCEPTED"
}
params_invite = {
"CUTYPE" => 'INDIVIDUAL',
"ROLE" => "REQ-PARTICIPANT",
"PARTSTAT" => "NEEDS-ACTION",
"RSVP" => "TRUE"
}
cal = Icalendar::Calendar.new
event = Icalendar::Event.new
event.dtstart #party.from.to_datetime, { "VALUE" => "DATE" }
event.dtend #party.to.to_datetime, { "VALUE" => "DATE" }
event.summary #party.title
event.description #party.description
event.klass "PRIVATE"
event.organizer "cn=#{#user.name} #{#user.surname}:mailto:#{#user.email}"
# THIS DOES NOT WORK
event.alarm.trigger = "-PT5M" # 5 Minutes before...
#party.participations.each do |participation|
str = "cn=#{participation.user.name} #{participation.user.surname}:mailto:#{participation.user.email}"
event.add_attendee(str, params_participant)
end
#party.invitations.each do |invitee|
event.add_attendee("mailto:#{invitee.email}", params_invite)
end
cal.add_event(event)
cal.publish
# I KNOW THIS IS HORRIBLE AND I HATE IT, BUT OTHERWISE THE ATTENDEES DO NOT SHOW UP
cal.to_ical.gsub("ORGANIZER:", "ORGANIZER;").gsub("ACCEPTED:", "ACCEPTED;").gsub("TRUE:", "TRUE;").gsub("PUBLISH", "REQUEST")
end
Any help would be really appreciated!
The email that is being generated: http://pastebin.com/patf05zd
Oh and I'm on:
Rails 3.2.13
The Icalendar gem I'm using
In case someone else happens to come across this, here is what I did:
Instead of the icalendar gem I now use ri_cal. Although I was skeptical because the last commit to that repo was 3 years ago, the google group was a very helpful resource.
Here is how I generate the ical attachment (both inline and normal), which seems to be working fine (although it obviously needs some refactoring :))
def to_ical
# this is horrible
klass = self
cal = RiCal.Calendar do
event = event do
organizer "CN=#{klass.user.name} #{klass.user.surname}:mailto:#{klass.user.email}"
summary klass.party.title
description klass.ical_description
dtstart klass.party.from.utc.to_datetime
dtend klass.party.to.utc.to_datetime
location "See url in description"
security_class klass.security_class
# this is horrible
h = self
klass.party.participations.each do |participation|
h.add_attendee klass.prepare_participant(participation)
end
klass.party.invitations.each do |invitee|
h.add_attendee klass.prepare_invitee(invitee.email)
end
unless klass.party.reminder == 0
alarm do
description "Alarm description"
trigger klass.convert_trigger # -PT1H
action "DISPLAY"
end
end
end
end
# THE HORROR
cal.to_s.gsub("ATTENDEE:", "ATTENDEE")
.gsub("ORGANIZER:", "ORGANIZER;")
.gsub("CALSCALE:GREGORIAN", "CALSCALE:GREGORIAN\nMETHOD:REQUEST\n")
end
The 2 Attachments in Apples Mail still show up, I don't think that can be fixed.
Your second B64 encoded attachment contains a lot of garbage towards the end (attendee field).
That would explain the Thunderbird issue.
Please note that some clients will ignore any alarm you may set on a REQUEST: As an organizer, you should not dictate when each attendee should be reminded of the meeting. That would be a rather rude thing to do.
Regarding the Apple iCal issue, there is not much you can do I'm afraid: Some clients want the ics within, some as an attachment so you have to provide both. Does it show the accept/decline panel on iCal ?

Rails 3.0.7 ActionMailer attachment issue

I'm trying to attach a file to an outgoing email but the attachment size ends up being 1 byte. It doesn't matter what attachment I'm forwarding it always ends up in the email 1 byte in size (corrupt). Everything else looks ok to me.
The email information is pulled from an IMAP account and stored in the database for browsing purposes. Attachments are stored on the file system and it's file name stored as an associated record for the Email.
In the view there's an option to forward the email to another recipient. It worked in Rails 2.3.8 but for Rails 3 I've had to change the attachment part of the method so now it looks like...
def forward_email(email_id, from_address, to_address)
#email = Email.find(email_id)
#recipients = to_address
#from = from_address
#subject = #email.subject
#sent_on = Time.now
#body = #email.body + "\n\n"
#email.attachments.each do |file|
if File.exist?(file.full_path)
attachment :filename => file.file_name, :body => File.read(file.full_path)
else
#body += "ATTACHMENT NOT FOUND: #{file.file_name}\n\n"
end
end
end
I've also tried it with...
attachments[file.file_name] = File.read(file.full_path)
and adding :mime_type and :content_type to no avail.
Any help would be a appreciated.
Thanks!
This is what I tried and worked for me
attachments.each do |file|
attachment :content_type => MIME::Types.type_for(file.path).first.content_type, :body => File.read(file.path)
end
Is the file readable? Can you debug the issue by placing something like this?
logger.debug "File: #{file.full_path.inspect} : #{File.read(file.full_path).inspect[0..100]}"
Is there anything in your development.log?
Well, someone from the rails team answered my question. The problem lies with adding body content (#body) other than the attachment inside the method. If you're going to attach files you have to use a view template.

ruby/rails receiving plain text email with pop

I have used the pop mailer for ruby (net/pop)
The problem I am having is that some of the emails are in HTML format is there a way to specify that I want plain text ?
Thanks, Alex
Emails can come in different formats. The most common is MIME which allows an email to contain multiple "parts". Commonly an HTML and a plain-text part. However, you can not control which parts the email actually contains. This can only the sender for obvious reasons.
You can however use ruby to get the plain text part if one is present or try to generate some representation of that from the HTML part.
The following condensed example to get the plain text part of an email is from the MailHandler model and the POP3 module of Redmine (licensed under GPLv2).
def plain_text_body(email)
parts = email.parts.collect {|c| (c.respond_to?(:parts) && !c.parts.empty?) ? c.parts : c}.flatten
if parts.empty?
parts << email
end
plain_text_part = parts.detect {|p| p.content_type == 'text/plain'}
if plain_text_part.nil?
# no text/plain part found, assuming html-only email
# strip html tags and remove doctype directive
plain_text_body = strip_tags(email.body.to_s)
plain_text_body.gsub! %r{^<!DOCTYPE .*$}, ''
else
plain_text_body = plain_text_part.body.to_s
end
plain_text_body.strip
end
pop = Net::POP3.APOP(true).new(host,port)
pop.start(username, password) do |pop_session|
if pop_session.mails.empty?
puts "No email to process"
else
puts "#{pop_session.mails.size} email(s) to process..."
pop_session.each_mail do |msg|
message = msg.pop
plain_text = plain_text_body(message)
#
# Now do something with the plain text body
#
end
end
end

Resources