Thursday 26 October 2017

MS SQL Server on Ubuntu with Rails 5 + TinyTDS & activerecord-sqlserver-adapter

Run SQL Server on your favorite platform Im choosing Linux - ubuntu

Start by going to the below page
By clicking Try now will take it to below url
choose Install on Ubuntu Linux 16.04 ->
follow the steps given below the “ Install SQL Server and create a database on Ubuntu “

Prerequisites

You must have a Ubuntu 16.04 machine with at least 3.25 GB of memory.
Same step listing here as well.
  1. Import the public repository GPG keys:
curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -


2. Register the Microsoft SQL Server Ubuntu repository:
sudo add-apt-repository “$(curl https://packages.microsoft.com/config/ubuntu/16.04/mssql-server-2017.list)"


the4.After the package installation finishes, run mssql-conf setup and follow the prompts to set the SA password and choose your edition.
sudo apt-get update
sudo apt-get install -y mssql-server
a. Choose respective edition
b. Choose respective language
c. Set password


5. Once the configuration is done, verify that the service is running:
sudo /opt/mssql/bin/mssql-conf setup


At this point, SQL Server is running on your Ubuntu machine and is ready to use!
systemctl status mssql-server
At this point, SQL Server is running on your Ubuntu machine and is ready to use!
In rails application add list of gems into Gemfile and bundle it.
gem 'tiny_tds', '~>2.0.0'gem 'activerecord-sqlserver-adapter'
if fails and ask for
“ An error occurred while installing tiny_tds (2.0.0), and Bundler cannot continue. Make sure that `gem install tiny_tds -v ‘2.0.0’` succeeds before bundling.
then do the listed below to solve the issue
sudo apt-get install wget
sudo apt-get install build-essential
sudo apt-get install libc6-dev
sudo wget http://www.freetds.org/files/stable/freetds-1.00.21.tar.gz
sudo tar -xzf freetds-1.00.21.tar.gz
cd freetds-1.00.21
sudo ./configure — prefix=/usr/local — with-tdsver=7.3
make
sudo make install
Few Reference link:
when you get error like below run the below command
/var/lib/gems/2.3.0/gems/tiny_tds-2.0.0/lib/tiny_tds.rb:41:in `require': libsybdb.so.5: cannot open shared object file: No such file or directory - /var/lib/gems/2.3.0/gems/tiny_tds-2.0.0/lib/tiny_tds/tiny_tds.so (LoadError)
 from /var/lib/gems/2.3.0/gems/tiny_tds-2.0.0/lib/tiny_tds.rb:41:in `<top (required)>'
/sbin/ldconfig /usr/local/lib
Now setup the database.yml
default: &default
  adapter: sqlserver
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000
  host: localhost
development:
  <<: *defaultYes !!! you are done!!
  database: rails_sample_development
  username: sa 
  password: password given while setting up the mssql server
run rake db:create
start the rails server
Yes!! you are done

Sunday 8 October 2017

Handling email scheduling by day, time and timezone

I’m going to share my experience of scheduling task using


a. cron job
b.sidekiq
c.sidekiq-scheduler
d.redis
Triggers every hour and look for the day, time and start schedule by timezone.
In detail i’m sharing my problem statement to understand better.
There is a TV channel and its subscribers. The subscriber will be receiving email at starting of the program and ending of the program. My Job is to trigger two emails which are at start time and end time of a particular day, time and location by considering the timezone.
Example
User : John,
Timezone : Asia/Singapore,
start time : 21:02:55 SGT +08:00
end time : 22:02:55 SGT +08:00
days : Monday, TuesDay, Friday

User : Alice
Timezone : Asia/Calcutta
start time : 18:31:13 IST +05:30
end time : 19:31:13 IST +05:30
days : Friday, Sunday



John is at Singapore timezone and he should be receiving the start time email at 21:02 and end time email at 22:02 on Monday, Tuesday, Friday. Similar for Alice.
a. cron to schedule jobs that run every hour
b. Group the list of data by timezone. Result looks like key and values. Key is timezone and values are subscriber list.
c. Loop through the list(timezone), again loop the values and get current dayat time zone, check it for days include current day.
For example days to send email for John is [Monday, Tuesday, Friday]. So current day is Friday look for Friday inside John’s day list.
d. If it does n’t include the day, skip it.
e. If it includes then look for (current_time start_time) leave it if false. If true then look for the status. Here we have status to tract the job has scheduled or started or completed.
f. If status is scheduled or started then leave it. Meaning is that job has already scheduled. Remember cron runs for every hour.
g. If status is completed which means it’s ready for scheduling.
h. Now we are ready to schedule a new job and executing at background using gem ‘sidekiq and gem ‘sidekiq-scheduler’.
Worker.perform_in(start_time, 'send_start_email')
Scheduling the stop email at same time.
Worker.perform_in(end_time, 'send_stop_email')
Updating the status and job id for future reference. It’ll be helpfull if scheduling is changed once Job is scheduled.

Handling the job once job is Scheduled.



Scenario one : Job is scheduled and didn’t start
I mentioned that each job id is stored for future reference.
By using the job ids (start and end job ids) we ‘ll able to find the scheduled job and delete it. Again look for updated days, time and same process mentioned above.
Scenario two : Job is scheduled and started (start email has been sent)
By using the job id (end job id) we’ll able to find the end scheduled job,delete it and send the email at same time saying ended now. Again look for updated days, time and same process mentioned above.
Scenario three : Job is scheduled, started and ended.
No need to look for job ids. It’ll be updated and scheduled.
Scenario four : Job is not scheduled.
No need to look for job ids. It’ll be updated and scheduled.

Must Have Ruby Gems and setups

Production Environment
For database/codebase backup
gem backup - Easy full stack backup operations on UNIX-like systems
For Log file backup
Log Rotate - Keep your log files in check as time goes on and make sure they don’t fill up your server’s disk space (log rotate)
For Exception tracking and logging
gem rollbar - Exception tracking and logging from Ruby to Rollbar
Rack middleware for blocking & throttling abusive requests
gem rack-attack - Rack::Attack is a rack middleware to protect your web app from bad clients. It allows safelistingblocklistingthrottling, and trackingbased on arbitrary properties of the request.
Development Environment
For debugger
gem pry - An IRB alternative and runtime developer console
For N+1 queries
gem bullet - help to kill N+1 queries and unused eager loading
For soft delete
gem Paranoia - When your app is using Paranoia, calling destroy on an ActiveRecord object doesn't actually destroy the database record, but just hides it.
For security vulnerability
gem brakeman - Brakeman is an open source static analysis tool which checks Ruby on Rails applications for security vulnerabilities.
List of things to be cared before going live
  • Tests passing?
  • SSL Certificates
  • Check it through webpagetest.org for problematic load times
  • Set up any workers and autoscalers
Listed few and I’m planning to add more when I come across with useful gems.
Readers please comment with the gem list, which you feel like must have.

Why rails5 update_attributes doesn’t but Update method does?

Rails version:
Rails 5.1.1
Ruby Version:ruby-2.4.0 [ x86_64 ]
Local Server:Puma starting in single mode…
* Version 3.9.1 (ruby 2.4.0-p0), codename: Private Caller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
I have a existing model called User and later I added the attribute last_name.
Then trying to update the newly created field(last_name) with other fields by rails method called

 User.update_attributes(first_name: ‘praaveen’, last_name:’vr’)
For update_attributes
This updates only first_name field and leave the last_name attribute.
rails log:
UPDATE “users” SET “updated_at” = $1, “first_name” = $2 WHERE “users”.”id” = $3 [[“updated_at”, “2017–09–20 14:19:26.174311”], [“first_name”, “praaveen”], [“id”, 156]]
Then tried with
User.update(first_name: ‘praaveen’, last_name:’vr’)
 User.update_columns(first_name: ‘praaveen’, last_name:’vr’)
These methods updates first_name and last_name as expected.
rails log:
 UPDATE “users” SET “updated_at” = $1, “first_name” = $2, “last_name” = $3 WHERE “users”.”id” = $4 [[“updated_at”, “2017–09–20 14:15:23.623292”], [“first_name”, “praaveen”], [“last_name”, “vr”], [“id”, 156]]
Any idea what’s going?

Pushmeup gem for IOS push notification rails5

This gem is a wrapper to send push notifications to devices. Currently it only sends to Android or iOS devices, but more platforms will be added soon. With APNS (Apple Push Notifications Service) you can send push notifications to Apple devices. With GCM (Google Cloud Messaging) you can send push notifications to Android devices.
Im not going to cover the Android part.
add it to Gemfile
gem ‘pushmeup’
APNS (Apple iOS)
Configure (mobile side)
In Keychain access export your certificate and your private key as a p12.
![Keychain Access](
https://raw.github.com/NicosKaralis/pushmeup/master/KeychainAccess.jpg)
Run the following command to convert the p12 to a pem file
$ openssl pkcs12 -in cert.p12 -out cert.pem -nodes -clcerts
Configure (server(rails) side)
a. After you have created your pem file.
b.Set the host, port and certificate file location on the APNS class. You just need to set this once:
create a file called push_me_up.rb and env.yml(files names are not mandatory to be same name and check if you already have the file for environment variable)

push_me_up.rb

 APNS.host = ENV[“APNS_HOST”]
APNS.port = 2195
 # this is also the default. Shouldn’t ever have to set this, but just in case Apple goes crazy, you can.
APNS.pem = Rails.root/ENV[“APNS_PEM”]
 # this is also the default. Shouldn’t ever have to set this, but just in case Apple goes crazy, you can.
APNS.pass = ENV[“APNS_PASS”]

 env.yml
APNS_HOST: gateway.push.apple.com
 # gateway.sandbox.push.apple.com is default and only for development
 # gateway.push.apple.com is only for production
APNS_PEM: pem_file.pem

 APNS_PASS: password
 # Just in case your pem need a password
Now, configurations are over and we will start using it
Usage
Sending a single notification(inside controller or service or worker any where*):
device_token = ‘123abc456def’
 APNS.send_notification(device_token, ‘Hello iPhone!’ )
 APNS.send_notification(device_token, :alert => ‘Hello iPhone!’, :badge => 1, :sound => ‘default’)
Sending multiple notifications and other options please refer the link (pushmeup)