Have to add a simple condition in Rails - ruby-on-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

Related

Scanning phone number for format to send SMS messages

I have code for scanning phone numbers to put into the correct format and then have the SMS sent to the phone number. Although, I don't know how to apply this the "best" way.
In my create method I have:
if #order.phone_number.present?
account_sid = '1234567890'
auth_token = '1234567890'
client = Twilio::REST::Client.new(account_sid, auth_token)
message = client.messages.create(
from: '+12017541209',
to: '+120188854064',
body: "You received Order from #{#order.listing.name} - View it here: localhost.com/order/#{#order.order_token}/order_confirmation" )
end
I then have this code for scanning:
def clean_number
number = self.phone_number.scan(/\d+/).join
number[0] == "1" ? number[0] = '' : number
number unless number.length != 10
end
The format I need is 11231234567
Whether the text_input is:
1-123-123-1234
123-123-1234
+1(123)-123-1234
etc.
Now, the SMS works but I haven't applied the clean_number method yet. Should i be putting this in my model, and then call it in the controller, or have it in the private within the controller?

Send sender name with email SendGrid - Rails

I am using SendGrid to send emails from my application. I want to send sender name along with sender email e.g. from: 'Maxcreet <contact#maxcreet.com>'
It is working fine using Letter Opener and MailTrap but SendGrid only show sender email.
Here is my SendGrid functionto send emails.
def deliver!(mail)
email.from = SendGrid::Email.new(email: mail[:from].addrs.first.address)
email.subject = mail.subject
email.add_personalization(build_personalization(mail))
build_content(mail)
send!(email)
end
I have checked mail[:from] values using puts it gives following values:
puts mail[:from] => Maxcreet <support#maxcreet.com>
puts mail[:from].addrs => Maxcreet <support#maxcreet.com>
puts mail[:from].addrs.first => Maxcreet <support#maxcreet.com>
puts mail[:from].addrs.first.address => support#maxcreet.com
Above 3 seems OK for me but when I use any of them in
email.from = SendGrid::Email.new(email: mail[:from].addrs.first.address)
It does not sent my email and even I do not find my email in sendgrid dashboard.
Following this also tried email.fromname but this even did not work.
SendGrid's ruby API has this option with name name and not fromname.
So the following should solve your problem.
email.from = SendGrid::Email.new(
email: mail[:from].addrs.first.address,
name: mail[:from].addrs.first.name
)
I concluded this by trying it from this doc.
It looks like you're mixing gems or objects. SendGrid::Email.new just needs a from String, and might support a name String. You're extracting the address from your mail[:from] Hash with mail[:from].addrs.first.address, but you need to provide the name as a distinct Key.
In the SendGrid Ruby gem 'kitchen sink" example, they don't show a name on the From argument, but they do on the personalization.
Try: email.from = SendGrid::Email.new(email: 'support#maxcreet.com', name: 'Maxcreet'))
or dynamically: email.from = SendGrid::Email.new(email: mail[:from].addrs.first.address, name: mail[:from].addrs.first.name))
if your mail Object recognizes that Key.
Otherwise, you'll need to look at your mail gem's documentation for how to extract a Friendly/Display Name from that mail[:from].addrs Object.

Ruby on rails. Add facebook.com/ to URL if not present

my users have the option to add their website, facebook and twitter URL's to their profile.
I want to let them enter either the full URL (http://www.facebook.com/USERNAME) or part of the URL Eg. www.facebook.com/USERNAME or just USERNAME, and then have the https://facebook.com/ added automatically if needed. I want the http:// as then the entered URL will link directly to their website/facebook etc.
For the website URL I have:
before_validation :add_url_protocol
def add_url_protocol
if self.website && !url_protocol_present?
self.website = "http://#{self.website}"
end
end
def url_protocol_present?
self.website[/\Ahttp:\/\//] || self.website[/\Ahttps:\/\//]
end
There is then further regex validation.
This works fine.
The thing is I don't have much of an idea about regex and I am unsure on how to add the facebook.com/ part to this before_validation code.
Any help would be greatly appreciated, thanks.
UPDATE:
def add_url_protocol
if self.website && !url_protocol_present?
self.website = "http://#{self.website}"
end
if self.facebook && !url_facebook_present?
self.facebook = "http://facebook.com/#{self.facebook}"
end
end
This almost works. If a user inputs USERNAME then the output is good. If the user inputs www.facebook.com/USERNAME then the ouput becomes http://facebook.com/www.facebook.com/USERNAME
The best way to do this would be to collect user input in a form model, you can roll your own with by including ActiveModel::Model or use something like Reform.
The easiest thing you can do is simply treat their input as a string containing their facebook username separated by "/" so whatever the string they enter you can get the username by
"https://www.facebook.com/their.username".split('/')[-1] # 'their.username'
"www.facebook.com/their.username".split('/')[-1] # 'their.username'
"their.username".split('/')[-1] # 'their.username'
Simply declare a username attribute in your form model and overwrite the setter to extract the facebook username. Then only save the facebook username in your database, and write a method such as
def facebook_profile_url
"www.facebook.com/#{fb_username}"
end
No need to persist the redundant facebook url part.
I would try
match = /^(https?:\/\/)?((www\.)?facebook\.com)?(.*)/.match(self.website)
self.website = match[1] || 'http://'
self.website << match[2] || 'facebook.com'
self.website << match[3]
You can create capture groups by using parentheses. The ? means that group or char before it is optional (so I was able to condense your protocol search)
You may need to check my indexes into the match array...
Sorry this is untested as it is from a phone...

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 ?

Getting First Name/Last Name/Email from Twitter using OAuth

I'm using omniauth exclusively to allow login to my website with facebook/google/twitter.
I store first name, last name, and email. However, when I raise the twitter auth hash from oauth I only get nickname, name, location, image, description and urls in the auth hash.
Is there a scope I can pass in my initializer to get the user's email and break name out into the first_name, last_name fields?
Twitter does not give out user emails so you will not be able to get that information from the Twitter API. Instead, you have to ask the user to type in their email address on your sign up form.
As far as splitting the name up, you'd do that once you have the hash returned using something like:
social_params ||= request.env["omniauth.auth"]
fullname = social_params["user_info"]["name"].split(' ')
first_name, last_name = fullname[0], fullname[1]
puts "first name is #{first_name} and last name is #{last_name}"
Just keep in mind that last_name could be nil if they don't have a space in their name or they didn't give a last name. This also doesn't consider the fact that many people have multiple last names in other cultures.
Using the current Twitter API is possible getting the email. You have to fill a form requesting that permission. The process is easy and quick, it is explained here.
Requesting a user’s email address requires your application to be whitelisted by Twitter. To request access, please use this form.
Once whitelisted, the “Request email addresses from users” checkbox will be available under your app permissions on apps.twitter.com. Privacy Policy URL and Terms of Service URL fields will also be available under settings which are required for email access. If enabled, users will be informed via the oauth/authorize dialog that your app can access their email address.
Well Twitter by Design will not pass you use email id.This is a deliberate design decision by the API team.
Here is same thread for your refrence
Is there a way to get an user's email ID after verifying her Twitter identity using OAuth?
If you have integration with FB , Google and Twitter than you will need to have a first and last in your DB (if your UI requires it > my case). This is what I came up with as some countries have people with more than 2 tokens for their names ex: (Marco De Franca Solis) or (Marco, De Franca Solis)
// + TEST CASES
var name1 = handleName("Marco De Franca Solis")
var name2 = handleName("first,last wer wer")
var name3 = handleName("aName")
var name4 = handleName("")
// - TEST CASES
handleName = function(input) {
var n=input.indexOf(" ");
n += input.indexOf(",");
var result = {};
if(n < 0){
result.first = input
result.last = ""
}
else{
arr = input.split(/[ ,]+/);
result.first = arr[0]
result.last = ""
if(arr.length > 1)
{
arr[0] = ""
result.last = arr.join(" ");
}
}
return result
}
OmniAuth is giving you all the names combined in one string. But, some people have more than two-word names, such as "John Clark Smith". You can choose to treat those in three different ways:
(1) first_name: "John", last_name: "Smith"
def first_name
if name.split.count > 1
name.split.first
else
name
end
end
def last_name
if name.split.count > 1
name.split.last
end
end
(2) first_name: "John Clark", last_name: "Smith"
def first_name
if name.split.count > 1
name.split[0..-2].join(' ')
else
name
end
end
def last_name
if name.split.count > 1
name.split.last
end
end
(3) first_name: "John", last_name: "Clark Smith"
def first_name
name.split.first
end
def last_name
if name.split.count > 1
name.split[1..-1].join(' ')
end
end
The above examples assume that if the name contains less than 2 words then it is a first name. This question is similar to this one
for php use:
$names = explode(' ',$socialData->firstName);
$socialData->firstName=array_shift($names);
$socialData->lastName=implode(' ',$names);
Be aware the name could have multiple surnames and possibly multiple firstnames, this deals with multiple surnames but not firstnames.

Resources