25
Ruby w/o rails Oleksandr Simonov

Ruby w/o Rails (Олександр Сімонов)

  • Upload
    fwdays

  • View
    222

  • Download
    2

Embed Size (px)

Citation preview

Page 1: Ruby w/o Rails (Олександр Сімонов)

Ruby w/o railsOleksandr Simonov

Page 2: Ruby w/o Rails (Олександр Сімонов)

About me

• Name: Oleksandr Simonov

• Occupation: Founder and Owner of Amoniac

• Hobby: Open Source contribution

• Github: @simonoff

Page 3: Ruby w/o Rails (Олександр Сімонов)

Why Ruby w/o Rails?

• Rails is a monolithic stone

• Rails is slow

• Rails force you to be a lazy

Page 4: Ruby w/o Rails (Олександр Сімонов)
Page 5: Ruby w/o Rails (Олександр Сімонов)

rails is:

• activerecord

• activemodel

• activesupport

• actionmailer

• actionpack

• actionview

• activejob

• railties

Page 6: Ruby w/o Rails (Олександр Сімонов)

benchmarkhttp://www.madebymarket.com/blog/dev/ruby-web-

benchmark-report.html

Page 7: Ruby w/o Rails (Олександр Сімонов)

Lazy Rails developer

Page 8: Ruby w/o Rails (Олександр Сімонов)

Alternatives• Rack

• Sinatra

• Cuba

• Grape (API)

• Reel

• Nahami

• Sequel

• ROM

WEB ORM

Page 9: Ruby w/o Rails (Олександр Сімонов)

Advantages

• Faster then Rails

• Less time for app loading

• New knowledge

Page 10: Ruby w/o Rails (Олександр Сімонов)

Disadvantages• No Rails like console

• No Rails like code autoloading

• No Rails helpers

• No "Magic"

• More code

Page 11: Ruby w/o Rails (Олександр Сімонов)

Practical section

• Download list of Finnish companies

• Insert/Update local DB

• On API call returns e-invoice address

Page 12: Ruby w/o Rails (Олександр Сімонов)
Page 13: Ruby w/o Rails (Олександр Сімонов)

- app - models - services - workers - config - boot.rb - initializers - 01-dotenv.rb - 02-airbrake.rb - 03-sequel.rb - 04-sidekiq.rb - db - migrations - init.rb - config.ru

Structure

Page 14: Ruby w/o Rails (Олександр Сімонов)

require 'rubygems'require 'bundler/setup'require_relative 'init' # Application code loadingrequire 'sidekiq/web'use Rack::ContentLengthuse Rack::CommonLogger, ::NetvisorSpreadsheets.logger # use own loggeruse Rack::ShowExceptionsrun Rack::URLMap.new('/' => ::NetvisorSpreadsheets: :Server, '/sidekiq' => Sidekiq::Web)

config.ru

Page 15: Ruby w/o Rails (Олександр Сімонов)

init.rb# encoding: UTF-8ENV['RACK_ENV'] ||= 'development' # default environmentrequire 'rubygems'

module NetvisorSpreadsheets # Singletone extend self attr_accessor :db

def root # helper for get application root path @root_path ||= ::Pathname.new(::File.join(File.dirname(__FILE__))).expand_path end

def env # helper for get environment @env ||= ENV["RACK_ENV"] || "development" end

def logger # helper for logger @logger ||= ::Logger.new(self.root.join('log', "#{self.env}.log").to_s) endend::NetvisorSpreadsheets.logger.level = if ::NetvisorSpreadsheets.env == 'production' ::Logger::INFO else ::Logger::DEBUG end# require boot filerequire self.root.join('config', 'boot.rb').to_s

Page 16: Ruby w/o Rails (Олександр Сімонов)

$LOAD_PATH.unshift ::NetvisorSpreadsheets.root # add root path to load path

# autoload some initializers, models, workers and servicesdef load_folder(*path) ::Dir.glob(::NetvisorSpreadsheets.root.join(*path)).each { |r| require r }end

load_folder('config', 'initializers', '**/*.rb')load_folder('app', 'models', '**/*.rb')load_folder('app', 'workers', '**/*.rb')load_folder('app', 'services', '**/*.rb')

# require sinatra server coderequire 'config/server'

boot.rb

Page 17: Ruby w/o Rails (Олександр Сімонов)

source 'https://rubygems.org'gem 'sqlite3'gem 'dotenv'gem 'sequel'gem 'sinatra'gem 'sinatra-contrib'gem 'sidekiq'gem 'airbrake'gem 'puma'gem 'sidekiq-cron', '~> 0.3', require: falsegem 'sidekiq-unique-jobs', '~> 4.0'

Gemfile

Page 18: Ruby w/o Rails (Олександр Сімонов)

require 'rubygems'require 'bundler/setup'require 'sequel'require 'dotenv'require 'rake'

env = ENV['RACK_ENV'] || 'development'

namespace :db do desc 'Run migrations' task :migrate, [:version] do |_t, args| ::Dotenv.load(".env", ".env.#{env}") ::Sequel.extension :migration db = ::Sequel.connect(::ENV.fetch('DATABASE_URL')) if args[:version] puts "Migrating to version #{args[:version]}" ::Sequel::Migrator.run(db, 'db/migrations', target: args[:version].to_i) else puts 'Migrating to latest' ::Sequel::Migrator.run(db, 'db/migrations') end endend

Rakefile

Page 19: Ruby w/o Rails (Олександр Сімонов)

::Sequel.migration do transaction up do create_table :companies do primary_key :id String :company_id, null: false, index: true String :name, null: false String :einvoice_address, null: false String :einvoice_operator, null: false end end

down do drop_table :companies endend

db/migrations/001_create_companies.rb

Page 20: Ruby w/o Rails (Олександр Сімонов)

class CompanyUpdaterWorker include ::Sidekiq::Worker sidekiq_options unique: :while_executing URL = "http://verkkolasku.tieke.fi/ExporVLOsoiteToExcel.aspx?type=csv"

def perform path = ::Tempfile.new('vlo').path if http_download_uri(::URI.parse(URL), path) ::NetvisorSpreadsheets::CompaniesFillerService.new(path).import end end

def http_download_uri(uri, filename) begin ::Net::HTTP.new(uri.host, uri.port).start do |http| http.request(Net::HTTP::Get.new(uri.request_uri)) do |response| ::File.open(filename, 'wb') do |io| response.read_body { |chunk| io.write(chunk) } end end end rescue Exception => e return false end true endend

companies_updater_worker.rb

Page 21: Ruby w/o Rails (Олександр Сімонов)

companies_filler_service.rbclass CompanyUpdaterWorker include ::Sidekiq::Worker sidekiq_options unique: :while_executing URL = "http://verkkolasku.tieke.fi/ExporVLOsoiteToExcel.aspx?type=csv"

def perform path = ::Tempfile.new('vlo').path if http_download_uri(::URI.parse(URL), path) ::NetvisorSpreadsheets::CompaniesFillerService.new(path).import end end

def http_download_uri(uri, filename) begin ::Net::HTTP.new(uri.host, uri.port).start do |http| http.request(Net::HTTP::Get.new(uri.request_uri)) do |response| ::File.open(filename, 'wb') do |io| response.read_body { |chunk| io.write(chunk) } end end end rescue Exception => e return false end true endend

Page 22: Ruby w/o Rails (Олександр Сімонов)

require 'sinatra/base'require 'sinatra/json'module NetvisorSpreadsheets class Server < Sinatra::Base configure :production, :development do enable :logging set :json_encoder, :to_json end

get '/' do if params['company_id'] && params['company_id'].length > 0 json ::NetvisorSpreadsheets::CompanyFinderService.find(params['company_id']) else 400 end end endend

server.rb

Page 23: Ruby w/o Rails (Олександр Сімонов)
Page 24: Ruby w/o Rails (Олександр Сімонов)

What we get?

• Only 40Mb RAM

• 1 second app load

• Fast deployment

Page 25: Ruby w/o Rails (Олександр Сімонов)

Questions