Sunday, April 10, 2016

Creating a Rails Engine for jQuery Plugin

Notes from sitepoint.com:


bundle gem pnotifier
Outside the gem directory, create a sample app.

rails new pnotifier

rails g controller site index

gem 'image_zoomer', '0.0.1', path: '/Users/bparanj/work/projects/pnotifier/'

Edit the app/views/site/index.html.erb, replace the content with

<%= Pnotifier::VERSION %>

Start the server and visit http://localhost:3000/site/index. You will see 0.0.1

Create app/assets/javascripts in the gem's root directory. Go to the pnotify plugin Github page https://github.com/sciactive/pnotify/tree/master/dist and grab pnotify.js and place it in the app/assets/javascripts directory.

Create a engine.rb file in lib/pnotifier directory and paste the following code:

module Pnotifer
 class Engine < Rails::Engine
 end
end

In the dummy Rails application open app/assets/javascripts/application.js and append:

//= require pnotifier

Restart the server. Refresh the page.
Open lib/notifier.rb in the gem and paste:

require 'pnotifier/engine'

Restart the server and refresh the browser.
View page source. You will see script tag referencing pnotifier.js.

Create pnotifier_main.js in app/assets/javascripts directory in the gem and paste:

//= require_tree .

Open app/assets/javascripts/application.js in Rails app and replace //= require pnotifier with:

//= require pnotifier_main

Restart the web server, refresh the browser and view page source. Both javascript files from the gem will be there.

Create a file pnotifier_initializer.js in app/assets/javascripts with:


$(function(){
    new PNotify({
        title: 'Regular Notice',
        text: 'Check me out! I\'m a notice.'
    });
});

Refresh the browser. You will the see notifier appear and disappear after some time.

Friday, April 08, 2016

Merge and Reverse Merge

Merge in Ruby works like this:
> options = { buy: true }
 => {:buy=>true}
> options.merge! when: :tomorrow
 => {:buy=>true, :when=>:tomorrow}
> options
 => {:buy=>true, :when=>:tomorrow}
> options.merge! buy: false
 => {:buy=>false, :when=>:tomorrow}
> options
 => {:buy=>false, :when=>:tomorrow}
> options.merge! :when => :today
 => {:buy=>false, :when=>:today}
Reverse Merge in Rails works like this:
 rails c
Loading development environment (Rails 5.0.0.beta3)
 > options = { buy: true }
 => {:buy=>true} 
 > options.reverse_merge! when: :tomorrow
 => {:buy=>true, :when=>:tomorrow} 
 > options
 => {:buy=>true, :when=>:tomorrow} 
 > options.reverse_merge! buy: false
 => {:buy=>true, :when=>:tomorrow} 
 > options
 => {:buy=>true, :when=>:tomorrow} 
 > options.reverse_merge! :when => :today
 => {:buy=>true, :when=>:tomorrow} 

Customize IRB Console

Create ~/.irbrc with:
 IRB.conf[:PROMPT][:MY_PROMPT] = { 
   :AUTO_INDENT => true,
   :PROMPT_I => '> ',               
   :PROMPT_S => nil,              
   :PROMPT_C => nil,             
   :RETURN => " => %s\n"     
 }
 IRB.conf[:PROMPT_MODE] = :MY_PROMPT
This prompt is cleaner. It does not display the ruby version and the line number on each line. Read the Ruby IRB docs.

Thursday, April 07, 2016

Analyzing the Production Log file in Rails 5

Create reports based on your log files. Supports Rails, Apache, MySQL, Delayed::Job, and other formats. 1. gem install request-log-analyzer 2. request-log-analyzer log/production.log Reference Request Log Analyzer

Top Links for Apr 14, 2016

1. Get Your Conference Proposal Accepted by Richard Schneeman.
2. Whitelisting with the lesser-known #presence_in method by Damir Svrtan
3. 9th Rubyconf BrasilRubyconf Brasil has established itself as the largest Ruby conference in Latin America. In 2015 they had more than 1,100 attendees. Well known speakers such as Chad Fowler, David Black, Scott Chacon, Chris Wanstrath, Josh Kalderimis, Koichi Sasada, Charles Nutter, and dozens of others have spoken at our conference. This is your chance to showcase your expertise. Rubyconf Brasil will be at São Paulo, Brazil. The dates are confirmed for September, 23th and 24th so book your flight and hotel right away!
4. Face Recognition using Google Cloud Vision API
5. Ruby Frozen String Literals Do Not Result in Any Performance Improvement by Alexander Dymo  
Reference Prototypical Conference Talks
https://infinum.co/the-capsized-eight/articles/best-ruby-on-rails-refactoring-talks
https://infinum.co/the-capsized-eight/articles/top-8-tools-for-ruby-on-rails-code-optimization-and-cleanup
https://infinum.co/the-capsized-eight/articles/a-gem-for-every-occasion-11-great-ruby-libraries-we-use-on-every-project
https://infinum.co/the-capsized-eight/articles/multiline-strings-ruby-2-3-0-the-squiggly-heredoc

Mountain West  Ruby 2016 videos
Writing a Test Framework From Scratch by Ryan Davis
Drifting Ruby Screencasts

Short URLs Considered Harmful for Cloud Services

Use techniques such as CAPTCHAs to separate human users from automated scanners. I cover how to use Google reCATCHA with Rails 5.

https://www.bitesizebschool.com/ruby-developer-sells-courses-site/

Saturday, April 02, 2016

Specifying Image Dimensions in Markdown

You can use the image tag with custom CSS to specify the width and max-height like this:

<img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvgpngQmOv-WoV_xp18ikS-tCHpL5kOdtkoWJ7mqIdvZ0DIUcFZ_bczOCn62H7fqhZCIG1uWliBl-M5OMzNpqYjHpC0j_gNqUOyukJByBUnro59b2gyjeG9bAm-pjI3zg6I7wT/s1600/color-blind5.png" alt="Ruby Plus" style="border: 1px solid #000; max-width:700px; max-height:600px;"/>
This will work if you are using Markdown to render page in a Rails app.

Throttling Network using Chrome


Thursday, March 31, 2016

Installing libv8 on Mac OS

Problem:

xcode-select: Error: No Xcode folder is set. Run xcode-select -switch to set the path to the Xcode folder.

Resolution:

xcode-select --print-path
sudo xcode-select -switch /Developer-3.2.6/Applications/Xcode.app/Contents/MacOS/
gem install therubyracer -v 0.12.2


Rails 5 Generator Help

$rails g helper --help

Usage:
  rails generate generator NAME [options]

Options:
      [--skip-namespace], [--no-skip-namespace]  # Skip namespace (affects only isolated applications)
      [--namespace], [--no-namespace]            # Namespace generator under lib/generators/name
                                                 # Default: true
  -t, [--test-framework=NAME]                    # Test framework to be invoked
                                                 # Default: test_unit

Runtime options:
  -f, [--force]                    # Overwrite files that already exist
  -p, [--pretend], [--no-pretend]  # Run but do not make any changes
  -q, [--quiet], [--no-quiet]      # Suppress status output
  -s, [--skip], [--no-skip]        # Skip files that already exist

Description:
    Stubs out a new generator at lib/generators. Pass the generator name as an argument,
    either CamelCased or snake_cased.

Example:
    `rails generate generator Awesome`

    creates a standard awesome generator:
        lib/generators/awesome/
        lib/generators/awesome/awesome_generator.rb
        lib/generators/awesome/USAGE
        lib/generators/awesome/templates/
        test/lib/generators/awesome_generator_test.rb

Rails 5 Available Generators

Usage: rails generate GENERATOR [args] [options]

General options:
  -h, [--help]     # Print generator's options and usage
  -p, [--pretend]  # Run but do not make any changes
  -f, [--force]    # Overwrite files that already exist
  -s, [--skip]     # Skip files that already exist
  -q, [--quiet]    # Suppress status output

Please choose a generator below.

Rails:
  assets
  channel
  controller
  generator
  helper
  integration_test
  jbuilder
  job
  mailer
  migration
  model
  resource
  scaffold
  scaffold_controller
  task

Coffee:
  coffee:assets

Js:
  js:assets

Kaminari:
  kaminari:config
  kaminari:views

RailsFootnotes:
  rails_footnotes:install

TestUnit:
  test_unit:generator
  test_unit:plugin

ValidatesTimeliness:
  validates_timeliness:install

Tuesday, March 29, 2016

Generating a URL from non sanitized request parameters is insecure!

Kaminari with Rails 5 use:

gem 'kaminari', :git => "git://github.com/amatsuda/kaminari.git", :branch => 'master'

ive_support/i18n_railtie.rb:45:in `map':

will_paginate 3.0.7 is not compatible with Rails 5. Upgrade to will_paginate 3.1.

Friday, March 25, 2016

How to pass custom variables to a partial in Rails 5

Let's say that you want to render the same form partial for creating and editing a project. You can pass a custom value for the button in the form partial like this:

<%= render 'form', project: @project, button_name: 'Create'  %>



You can use the passed in variable in the form partial like this:



<%= form_for(project) do |f| %>
  <% if project.errors.any? %>
   

     

<%= pluralize(project.errors.count, "error") %> prohibited this project from being saved:



     

          <% project.errors.full_messages.each do |message| %>
           
  • <%= message %>

  •       <% end %>
         

   

  <% end %>

    <% if params[:preview_button] %>
      <%= project.description %>
    <% end %>

 

    <%= f.label :name %>
    <%= f.text_field :name %>
 


 

    <%= f.label :description %>
    <%= f.text_area :description %>
 


 

    <%= f.submit button_name %>
    <%= f.submit 'Preview', name:  'preview_button'  %>
   
 

<% end %>

Wednesday, March 23, 2016

Problem Installing libv8 and therubyracer on El Capitan

Error:

.rvm/gems/ruby-2.3.0@blog/gems/libv8-3.16.14.7/ext/libv8/location.rb:36:in `block in verify_installation!': libv8 did not install properly, expected binary v8 archive '/.rvm/gems/ruby-2.3.0@blog/gems/libv8-3.16.14.7/vendor/v8/out/x64.release/obj.target/tools/gyp/libv8_base.a'to exist, but it was not found (Libv8::Location::Vendor::ArchiveNotFound)

Resolution:

brew install v8
gem install libv8 -v '3.16.14.7' -- --with-system-v8
bundle update therubyracer


Tuesday, March 22, 2016

How to create a new Rails 5 app

1. gem install rails --pre --no-ri --no-rdoc

2. rails new app-name

How to handle routing errors in Rails 4.2.6

    Step 1
   
    In routes.rb:
   
    match '*unmatched_route', :to => 'application#handle_routing_error', :via => :all
   
    Step 2
   
In application_controller.rb:

    rescue_from ActionController::RoutingError, :with => :handle_routing_error

    def handle_routing_error
      logger.info "No route matches #{params[:unmatched_route]}"
      render nothing: true
    end

Turn on logging to see remote calls made in ActiveResource

ActiveResource::Base.logger = ActiveRecord::Base.logger

Sunday, March 20, 2016

Find the most popular end points in your Rails apps


grep "Parameters:" log/production.log | grep -o '".*"' | sed --r 's/[[:digit:]]*/:id/' | sort | uniq -c

to exclude certain things, pipe to grep -v 'string to exclude'

Saturday, March 19, 2016

Rails Footnotes Gem





Cloudfront favicon error in Rails 4.2.6

[Chrome] [2016-03-18 04:19:04.221] [56b01676-4491-4c4e-9458-666168fb7267] [info] [d1b5oz78c0udqh.cloudfront.net] [182.96.98.1] [session_id : None] [PID-12309] 
ActionController::RoutingError (No route matches [GET] "/favicon.ico"):
  actionpack (4.2.6) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call'
  actionpack (4.2.6) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
  railties (4.2.6) lib/rails/rack/logger.rb:38:in `call_app'
  railties (4.2.6) lib/rails/rack/logger.rb:20:in `block in call'
  activesupport (4.2.6) lib/active_support/tagged_logging.rb:68:in `block in tagged'
  activesupport (4.2.6) lib/active_support/tagged_logging.rb:26:in `tagged'
  activesupport (4.2.6) lib/active_support/tagged_logging.rb:68:in `tagged'
  railties (4.2.6) lib/rails/rack/logger.rb:20:in `call'
  actionpack (4.2.6) lib/action_dispatch/middleware/request_id.rb:21:in `call'
  rack (1.6.4) lib/rack/methodoverride.rb:22:in `call'
  rack (1.6.4) lib/rack/runtime.rb:18:in `call'
  activesupport (4.2.6) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
  rack (1.6.4) lib/rack/sendfile.rb:113:in `call'
  actionpack (4.2.6) lib/action_dispatch/middleware/ssl.rb:24:in `call'
  railties (4.2.6) lib/rails/engine.rb:518:in `call'
  railties (4.2.6) lib/rails/application.rb:165:in `call'
  passenger (5.0.25) src/ruby_supportlib/phusion_passenger/rack/thread_handler_extension.rb:97:in `process_request'
  passenger (5.0.25) src/ruby_supportlib/phusion_passenger/request_handler/thread_handler.rb:152:in `accept_and_process_next_request'
  passenger (5.0.25) src/ruby_supportlib/phusion_passenger/request_handler/thread_handler.rb:113:in `main_loop'
  passenger (5.0.25) src/ruby_supportlib/phusion_passenger/request_handler.rb:416:in `block (3 levels) in start_threads'
  passenger (5.0.25) src/ruby_supportlib/phusion_passenger/utils.rb:113:in `block in create_thread_and_abort_on_exception'

Resolution:

In layout file use this:

  <%= favicon_link_tag 'favicon.ico' %>

instead of:

  <%= favicon_link_tag  %>

Thursday, March 17, 2016

SQLite3::ReadOnlyException: attempt to write a readonly database

This happened when the rake tasks were run in one command:

rake db:drop db:migrate db:seed

Solution: Run the commands individually.

List the files that were changed between two branches in Git

 git diff --name-status master..branch-name

Pimp My RailsCasts Series

1. Caching with Instance Variables
2. Dynamic find_by Methods
3. Find Through Association
4. Move Find into Model
5. Using with_scope
6. Shortcut Blocks with Symbol to_proc
7. All About Layouts
8. Layouts and content_for
9. Filtering Sensitive Logs
10. Refactoring User Name Part 1
11. Refactoring User Name Part 2
12. Refactoring User Name Part 3
13. Dangers of Model in Session
14. Performing Calculations on Models
15. Fun with Find Conditions
16. Virtual Attributes
17. HABTM Checkboxes
18. Looping Through Flash
19. Where Administration Goes - Not revised
20. Restricting Access - Not revised
21. Super Simple Authentication - Not revised
22. Eager Loading - Coming soon
23. Counter Cache Column
24. The Stack Trace
25. SQL Injection
26. Hackers Love Mass Assignment
27. Cross Site Scripting
28. in_groups_of
29. group_by Month
30. Pretty Page Title
31. Formatting Time
32. Time in Text Field
33. Making a Plugin
34. Named Routes

Tuesday, March 15, 2016

Rails 5 New Project Options

$ rails new --help
Usage:
  rails new APP_PATH [options]

Options:
  -r, [--ruby=PATH]                                      # Path to the Ruby binary of your choice
                                                         # Default: /Users/bparanj/.rvm/rubies/ruby-2.3.0/bin/ruby
  -m, [--template=TEMPLATE]                              # Path to some application template (can be a filesystem path or URL)
  -d, [--database=DATABASE]                              # Preconfigure for selected database (options: mysql/oracle/postgresql/sqlite3/frontbase/ibm_db/sqlserver/jdbcmysql/jdbcsqlite3/jdbcpostgresql/jdbc)
                                                         # Default: sqlite3
  -j, [--javascript=JAVASCRIPT]                          # Preconfigure for selected JavaScript library
                                                         # Default: jquery
      [--skip-gemfile], [--no-skip-gemfile]              # Don't create a Gemfile
  -B, [--skip-bundle], [--no-skip-bundle]                # Don't run bundle install
  -G, [--skip-git], [--no-skip-git]                      # Skip .gitignore file
      [--skip-keeps], [--no-skip-keeps]                  # Skip source control .keep files
  -M, [--skip-action-mailer], [--no-skip-action-mailer]  # Skip Action Mailer files
  -O, [--skip-active-record], [--no-skip-active-record]  # Skip Active Record files
  -P, [--skip-puma], [--no-skip-puma]                    # Skip Puma related files
  -C, [--skip-action-cable], [--no-skip-action-cable]    # Skip Action Cable files
  -S, [--skip-sprockets], [--no-skip-sprockets]          # Skip Sprockets files
      [--skip-spring], [--no-skip-spring]                # Don't install Spring application preloader
      [--skip-listen], [--no-skip-listen]                # Don't generate configuration that depends on the listen gem
  -J, [--skip-javascript], [--no-skip-javascript]        # Skip JavaScript files
      [--skip-turbolinks], [--no-skip-turbolinks]        # Skip turbolinks gem
  -T, [--skip-test], [--no-skip-test]                    # Skip test files
      [--dev], [--no-dev]                                # Setup the application with Gemfile pointing to your Rails checkout
      [--edge], [--no-edge]                              # Setup the application with Gemfile pointing to Rails repository
      [--rc=RC]                                          # Path to file containing extra configuration options for rails command
      [--no-rc], [--no-no-rc]                            # Skip loading of extra configuration options from .railsrc file
      [--api], [--no-api]                                # Preconfigure smaller stack for API only apps

Runtime options:
  -f, [--force]                    # Overwrite files that already exist
  -p, [--pretend], [--no-pretend]  # Run but do not make any changes
  -q, [--quiet], [--no-quiet]      # Suppress status output
  -s, [--skip], [--no-skip]        # Skip files that already exist

Rails options:
  -h, [--help], [--no-help]        # Show this help message and quit
  -v, [--version], [--no-version]  # Show Rails version number and quit

Description:
    The 'rails new' command creates a new Rails application with a default
    directory structure and configuration at the path you specify.

    You can specify extra command-line arguments to be used every time
    'rails new' runs in the .railsrc configuration file in your home directory.

    Note that the arguments specified in the .railsrc file don't affect the
    defaults values shown above in this help message.

Example:
    rails new ~/Code/Ruby/weblog

    This generates a skeletal Rails installation in ~/Code/Ruby/weblog.

Wednesday, March 09, 2016

Symbol to_proc Hack

Usually, when we create a proc, the proc object captures the variables that is in the creation context. However, in Symbol#to_proc,  the object obj that is in:

Proc.new {|obj| obj.send(self) }

is not in the surrounding context of the proc object. At this point there is no 'obj' object. So, within the Symbol class to_proc method, there is no obj. When the & ampersand trigger is executed, the map method yields a block variable, this block variable gets associated to the obj object. This is a subtle concept. We can bind values to the block variable in the proc object at run-time. This is a very powerful concept we can use when we develop libraries.


Tuesday, March 08, 2016

Trace Route on Mac OS

$ traceroute www.rubyplus.com

traceroute to www.rubyplus.com (198.58.102.13), 64 hops max, 52 byte packets
 1  10.33.0.1 (10.33.0.1)  0.760 ms  0.245 ms  0.252 ms
 2  209.133.4.85 (209.133.4.85)  0.456 ms  0.522 ms  0.516 ms
 3  ae5.cr2.sjc2.us.zip.zayo.com (64.125.26.21)  2.386 ms  4.013 ms  3.053 ms
 4  ae16.mpr4.sjc7.us.zip.zayo.com (64.125.31.15)  1.757 ms  1.909 ms  1.868 ms
 5  209.133.4.46 (209.133.4.46)  1.914 ms  1.945 ms  1.971 ms
 6  ae0.bbr02.cs01.lax01.networklayer.com (173.192.18.151)  10.292 ms  10.630 ms  10.217 ms
 7  ae7.bbr01.cs01.lax01.networklayer.com (173.192.18.166)  10.367 ms  10.220 ms  10.698 ms
 8  ae19.bbr01.eq01.dal03.networklayer.com (173.192.18.140)  40.263 ms  37.674 ms  40.394 ms
 9  po31.dsr02.dllstx3.networklayer.com (173.192.18.227)  38.005 ms  37.520 ms  40.913 ms
10  po32.dsr02.dllstx2.networklayer.com (70.87.255.70)  41.327 ms  37.968 ms
    po31.dsr01.dllstx2.networklayer.com (70.87.255.66)  40.557 ms
11  po1.car02.dllstx2.networklayer.com (70.87.254.82)  37.646 ms
    po2.car01.dllstx2.networklayer.com (70.87.254.78)  37.714 ms
    po2.car02.dllstx2.networklayer.com (70.87.254.86)  41.112 ms
12  router2-dal.linode.com (67.18.7.94)  37.950 ms  40.729 ms
    router1-dal.linode.com (67.18.7.90)  41.317 ms
13  www.rubyplus.com (198.58.102.13)  41.468 ms  41.386 ms  37.602 ms

Dependency Inversion Principle Example from The RSpec Book

The code example for Codebreaker game from The Rspec Book. The solution in the book that does not apply the DIP

Before

module Codebreaker
  class Game
    def initialize(output)
      @output = output
    end

    def start(secret)
      @secret = secret
      @output.puts 'Welcome to Codebreaker!'
      @output.puts 'Enter guess:'
    end
  end
end

g = Codebreaker::Game.new($stdout)
g.start('sekret')

The solution after applying the DIP.

After

module Codebreaker
  class Game
    def initialize(writer)
      @writer = writer
    end

    def start(secret)
      @secret = secret
      @writer.write 'Welcome to Codebreaker!'
      @writer.write 'Enter guess:'
    end
  end
end

class StandardConsole
  def write(message)
    $stdout.puts(message)
  end 
end

writer = StandardConsole.new
g = Codebreaker::Game.new(writer)
g.start('sekret')

List Untracked Files in Git

git ls-files --others --exclude-standard

You can chain this to xargs:

git ls-files --others --exclude-standard | xargs git rm

to remove those files.

Monday, March 07, 2016

Dependency Inversion Principle

The article

The Three Basic Rules for a Good Design

illustrates the Dependency Inversion Principle in action by using a simple example. It applies three simple rules:

  1. Separate things that change from things that stays the same. Encapsulate what varies behind a well-defined interface.
  2. Program to interfaces, not implementations. This exploits polymorphism.
  3. Depend on abstractions. Do not depend on concrete classes.
to satisfy Dependency Inversion Principle. 

Storage mechanisms such as PersonMemoryStore and PersonFileStore have a well defined interface called records. The mechanisms to send the message such as GreetingConsole and GreetingPony have a well defined interface call send. Classes that implement a specific storage or sending email now conform to a uniform interface. This gives us the ability to switch implementation in different combinations. The classes that implement specific way of doing things depend on stable abstractions, records and send that we came up with in the final design.

Saturday, March 05, 2016

Compress Custom Web Fonts in Rails 4.2.5 Apps

 The easiest way to compress custom web fonts in a Rails 4.2.5 app is to use Amazon Cloudfront. In your Cloudfront configuration, select Yes for Compress Objects Automatically.


Here you can see the result of Web Page Performance Test for RubyPlus after the Custom Web fonts has been compressed. It takes 30 minutes or so for the cloudfront configuration changes to take effect.

Amazon Docs

Friday, March 04, 2016

Caching Database Results in Rails 4.2.5

If you make the same database calls  within any one request, Rails will cache the database result. You don't need to use use ||= to cache the value.
  def show
    Article.find(params[:id])
    Article.find(params[:id])
  end

You can see that the cache is hit in the log file:

Started GET "/articles/1" for ::1 at 2016-03-03 16:42:13 -0800
Processing by ArticlesController#show as */*
  Parameters: {"id"=>"1"}
  Article Load (0.1ms)  SELECT  "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT 1  [["id", 1]]
  CACHE (0.0ms)  SELECT  "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT 1  [["id", "1"]]
  Rendered articles/show.html.erb within layouts/application (0.3ms)
Completed 200 OK in 25ms (Views: 24.0ms | ActiveRecord: 0.1ms)

From  the Caching with Rails guide.

SQL Caching

Query caching is a Rails feature that caches the result set returned by each query so that if Rails encounters the same query again for that request, it will use the cached result set as opposed to running the query against the database again.

Thursday, March 03, 2016

Compress all Assets using GZip

In production.rb:

use Rack::Deflater

https://remino.net/rails-html-css-js-gzip-compression/

Wednesday, March 02, 2016

Compress Html to Improve Rails 4.2.5 App Performance

1. Add htmlcompressor gem to Gemfile.

group :production do
  gem 'htmlcompressor'
end

Run bundle install.

2. In production.rb:

  config.middleware.use HtmlCompressor::Rack

3. Deploy and enjoy the speed.


GTmetrix.com test score for html compression went up. But the performance went down. The page load time went up to 2.1 seconds from 1.7 seconds.

Can't initialize a new Rails application within the directory of another, please change to a non-Rails directory first.

This error happens if any of the directory in which you are running rails new has some rails directory structure. Resolution: Go to a directory that does not have any rails directory structure.

Can the genius Rails committers provide the resolution as part of the error message please?

Tuesday, March 01, 2016

Using Asset Pipeline for Favicons in Rails 4.2.5

1. Copy icon images to app/assets/images folder.

2. Use favicon_link_tag helper. Default image name : favicon.ico.
   
      <%= favicon_link_tag %>
  <%= favicon_link_tag 'apple-touch-icon-57x57.png', rel: 'apple-touch-icon', type: 'image/png', sizes: "57x57" %>
  <%= favicon_link_tag 'apple-touch-icon-60x60.png', rel: 'apple-touch-icon', type: 'image/png', sizes: "60x60" %>
  <%= favicon_link_tag 'apple-touch-icon-72x72.png', rel: 'apple-touch-icon', type: 'image/png', sizes: "72x72" %>
  <%= favicon_link_tag 'apple-touch-icon-76x76.png', rel: 'apple-touch-icon', type: 'image/png', sizes: "76x76" %>
  <%= favicon_link_tag 'apple-touch-icon-114x114.png', rel: 'apple-touch-icon', type: 'image/png', sizes: "114x114" %>    
  <%= favicon_link_tag 'apple-touch-icon-120x120.png', rel: 'apple-touch-icon', type: 'image/png', sizes: "120x120" %>
  <%= favicon_link_tag 'apple-touch-icon-144x144.png', rel: 'apple-touch-icon', type: 'image/png', sizes: "144x144" %>
  <%= favicon_link_tag 'apple-touch-icon-152x152.png', rel: 'apple-touch-icon', type: 'image/png', sizes: "152x152" %>
  <%= favicon_link_tag 'apple-touch-icon-180x180.png', rel: 'apple-touch-icon', type: 'image/png', sizes: "180x180" %>
  <%= favicon_link_tag 'favicon-32x32.png', rel: 'icon', type: 'image/png', sizes: "32x32" %>          
  <%= favicon_link_tag 'android-chrome-192x192.png', rel: 'icon', type: 'image/png', sizes: "192x192" %>          
  <%= favicon_link_tag 'favicon-96x96.png', rel: 'icon', type: 'image/png', sizes: "96x96" %>          
  <%= favicon_link_tag 'favicon-16x16.png', rel: 'icon', type: 'image/png', sizes: "16x16" %>            


3. Verify by viewing the page source.

  <link rel="shortcut icon" type="image/x-icon" href="https://d1b5oz78c0udqh.cloudfront.net/assets/favicon-0784d42434f39fe96f3736f3e47d1e9f.ico" />
  <link rel="apple-touch-icon" type="image/png" href="https://d1b5oz78c0udqh.cloudfront.net/assets/apple-touch-icon-57x57-1f87fa73399b81c63cf77fee620b3f25.png" sizes="57x57" />
  <link rel="apple-touch-icon" type="image/png" href="https://d1b5oz78c0udqh.cloudfront.net/assets/apple-touch-icon-60x60-421e797d9dc30906f3876c0bf72c8e98.png" sizes="60x60" />
  <link rel="apple-touch-icon" type="image/png" href="https://d1b5oz78c0udqh.cloudfront.net/assets/apple-touch-icon-72x72-53f33feccdeb7a9428d3bfd3f9fdcb5c.png" sizes="72x72" />  
  <link rel="apple-touch-icon" type="image/png" href="https://d1b5oz78c0udqh.cloudfront.net/assets/apple-touch-icon-76x76-8d6db4af70c6c952ffbc34e742035187.png" sizes="76x76" />  
  <link rel="apple-touch-icon" type="image/png" href="https://d1b5oz78c0udqh.cloudfront.net/assets/apple-touch-icon-114x114-308d3819dfb621285ab6368f672a72fb.png" sizes="114x114" />      
  <link rel="apple-touch-icon" type="image/png" href="https://d1b5oz78c0udqh.cloudfront.net/assets/apple-touch-icon-120x120-15eedd3461f483a5b27828fa9ed789de.png" sizes="120x120" />  
  <link rel="apple-touch-icon" type="image/png" href="https://d1b5oz78c0udqh.cloudfront.net/assets/apple-touch-icon-144x144-5759a401867e2dfe239149695d7cd081.png" sizes="144x144" />  
  <link rel="apple-touch-icon" type="image/png" href="https://d1b5oz78c0udqh.cloudfront.net/assets/apple-touch-icon-152x152-9f15e1c9218a79ee781a128e8bfba79a.png" sizes="152x152" />  
  <link rel="apple-touch-icon" type="image/png" href="https://d1b5oz78c0udqh.cloudfront.net/assets/apple-touch-icon-180x180-2fc81325eec91ad63efb7d10ae0e1089.png" sizes="180x180" />  
  <link rel="icon" type="image/png" href="https://d1b5oz78c0udqh.cloudfront.net/assets/favicon-32x32-e6eebf5633792e63508f58260cfc98c6.png" sizes="32x32" />            
  <link rel="icon" type="image/png" href="https://d1b5oz78c0udqh.cloudfront.net/assets/android-chrome-192x192-b03a39be430b547b8448857ef3ed1960.png" sizes="192x192" />            
  <link rel="icon" type="image/png" href="https://d1b5oz78c0udqh.cloudfront.net/assets/favicon-96x96-93f5bc8d5e587ff2a07f4f6ea8349b09.png" sizes="96x96" />            
  <link rel="icon" type="image/png" href="https://d1b5oz78c0udqh.cloudfront.net/assets/favicon-16x16-ecb043d6bec4bf88aa1435bfa04000c2.png" sizes="16x16" />              

This should take the CDN for all static assets score from 90/100 to 100/100 on WebPageTest.

Monday, February 29, 2016

Upgrading from Passenger 4.0.60 to 5.0.25

If you are managing your Rails 4.2.5 server using Moonshine, follow these steps.

Step 1

In passenger.rb, within Moonshine::Manifest::Rails::Passenger module, change the passenger version:

```ruby
BLESSED_VERSION = '5.0.25'
```

Step 2

Add the following Capistrano 2 task to deploy.rb:

namespace :deploy do
  task :restart, :roles => :app, :except => { :no_release => true } do
    sudo "passenger-config restart-app --ignore-app-not-running /srv//current"
  end
end

Checkin the code changes to git and deploy the app using Capistrano.

Step 3

On the server, verify the installed version:

```sh
passenger-config --version
```

Page Load Time

In passenger 4.0.60, it took 2.4 s
In passenger 5.0.25, it took 1.7 s


Turn on Keepalive to Speed Up Rails 4.2.5 App

I am using Moonshine to manage Rails 4.2.5 app RubyPlus on Linode. In Moonshine source code, file apache.rb, change the keep_alive to 'on':

 defaults = {
    :keep_alive => 'on',
 
Linode provides 2 GB of RAM for just $20/month. So, there is no reason not to turn on this setting. Especially for low traffic sites. This setting will keep the connection open so that all assets can be downloaded in one connection. This avoids opening multiple connection to the server by the browser to download the assets.

Moonshine Support for Passenger 5

1. Passenger 5 support added in : lib/moonshine/manifest/rails/passenger.rb
2. To restart the app with capistrano 2 add the following to your config/deploy.rb file:

namespace :deploy do
  task :restart, :roles => :app, :except => { :no_release => true } do
    sudo "passenger-config restart-app --ignore-app-not-running /srv//current"
  end
end


https://github.com/railsmachine/moonshine/pull/240

Using Custom Web Fonts in Rails 4.2.5 Apps


I was getting this error after hooking up Amazon Cloudfront CDN for RubyPlus. Here are the steps to make Rails 4.2.5 use custom fonts.

1. In:

config/application.rb 

config.assets.paths << Rails.root.join("app", "assets", "fonts")

2.  In your .scss files, change the src to use font-url not url:

@font-face {
    font-family: 'icofonts';
    src:font-url('fonts/icofonts.ttf') format('truetype');
    font-weight: normal;
    font-style: normal;
}   
3.  In Moonshine source code, file apache.rb, add 'application/x-font-ttf', 'font/ttf' to the end of the gzip_types:

 defaults = {
    :gzip_types => ['text/html', 'text/plain', 'text/xml', 'text/css', 'text/javascript', 'text/json', 'application/x-javascript', 'application/javascript', 'application/json', 'application/x-font-ttf', 'font/ttf' ]


Reference:

Custom Web Fonts and the Rails Asset Pipeline



Thursday, February 25, 2016

retry

attempts = 0
begin
  raise
rescue
  attempts += 1
  puts 'retrying...'
  retry if attempts < 3
end


def work
  with_retry do
    puts 'working...'
    raise
  end
end

def with_retry
  attempts = 0
  begin
    yield
  rescue
    attempts += 1
    puts 'retrying...'
    if attempts < 3
      retry
    else
      puts 'Giving up!'
    end
  end
end

work

Tuesday, February 23, 2016

Performance of a.length > 0 vs a.empty? on

In Ruby 2.3.0

require 'benchmark'

a = []

t1 = Benchmark.realtime do
 a.length > 0
end

t2 = Benchmark.realtime do
  a.empty?
end

p t2 < t1


This prints true.



Tuesday, February 16, 2016

Symbol vs String

Symbol is like country names and string is like city names that are not unique. There is Richmond city in California as well as Virginia. This is an example for strings that have the same content but are in different memory locations. State name is unique, there is only one california in USA.

Filter out sensitive parameters from logging file in Rails 4.2.5

Create filter_parameter_logging.rb in config/initializers folder:

Rails.application.config.filter_parameters += [:password, :password_confirmation]





Tuesday, February 02, 2016

Thoughts on Sandi Metz presentation

Returning nil in the absence of some object means the type changes. Not all of them are ducks. One of them is going to be NilClass. This will not be able to respond to the message sent by the client.

This problem is because the return type from a method is not uniform. If it always returns an object that can respond to a certain message sent by a client, then the program will not crash.

In Java, we can declare interface. Something like this:

interface OperateCar {
  int turn(direction)
}

You can see that the return type of the turn method is integer. The clients can depend on this fact. They need not worry about handing a null for instance. Since the interface is implicit in Ruby, it allows returning different types of objects, this leads to problems. The only way to make the client code simpler is to make the implementation return something that has consistent interface.

What are the components of an interface?
How can we write code to express the interface ?
Seems like the code will be implicit when it has to express the uniformity or the protocol.
What is a protocol?
What is an interface?

Monday, February 01, 2016

Dave Thomas Presentation Notes

Class names are constant. Why?
Classes are objects.
Class name can be assigned to a variable and used to create an instance.

irb
2.2.4 :001 > String.name
 => "String"
2.2.4 :002 > Class.name
 => "Class"
2.2.4 :003 > BasicObject.name
 => "BasicObject"
2.2.4 :004 > self.name
NoMethodError: undefined method `name' for main:Object
    from (irb):4
    from /Users/bparanj/.rvm/rubies/ruby-2.2.4/bin/irb:11:in `
'
2.2.4 :005 > self.to_s
 => "main"

 String.to_s
 => "String"
2.2.4 :007 > Class.to_s
 => "Class"
2.2.4 :008 > BasicObject.to_s
 => "BasicObject"


Instance variables are stored in current instance.


In the middle of the class, the code is running.
Every method call has a receiver.


puts does not have explicit receiver.
Default object, is always the self (the current object)
We did not create any object. We ask main :
What is the class that is used to create an instance of main?


Methods are not objects. It can be converted to an object.
puts can be converted into an object and we can call puts.

What is the current object?

Example.

No compilation phase.
Definitions are active.
There is always a receiver.

Class definitions is executable.
Everything gets executed.


Instead of doing:

Calling an utility method:

Encryptor.encrypt('secret')

vs

'secret'.encrypt

Sending a message

module Some

end

Some.new

vs

Module.new

class Object


  def to_s
    'main'
  end
end


class Person

  puts self
  puts self.class

end

class Person

  def self.talk
  end

end


class Person

  def self.talk
  end

  Person.talk
end



class Person

  def self.talk
  end

  self.talk

end


class Person

  def self.talk
  end

  talk

end


class Person

  def self.talk
  end

end

Person.talk


class Dumbass < Person

  talk

end

Notes from Smalltalk Presentation by Dan

The real power is in the messaging. The message name represents what and the implementation is hidden behind the method.

Break complex problem down into:

As few parts as possible as independent as possible.
Easier to learn because fewer components.
Productive because the components are re-usable.

Simplicity and Generality

Analysis

Small number of independent parts

Synthesis

Easy to learn
Productive
Maintainable (Built with fewer components)

factorial
self <= 1
  ifTrue: []
 
 
self = 0 ifTrue: [^ 1].
self > 0 ifTrue: [^ self * (self - 1) factorial].
self error: 'Not valid for negative integers'


recFact
self < 0
     ifTrue : [^0]
     ifFalse: [
         self = 0
             ifTrue : [^1]
             ifFalse: [^self * (self -1) recFact]
              ]


Instead of :

loop do
 p 'This will print forever'
end

[ code ] repeat

Ruby Equivalent

(Block Object).repeat

Ignore knowledge about objects. Focus on messages.


Smalltalk

Wednesday, January 27, 2016

Installing Scheme 9.2 on Mac OS 10.10.5

1. Download 64-bit installer mit-scheme-9.2-x86-64.dmg
2. Install Scheme.
3. sudo ln -s /Applications/MIT\:GNU\ Scheme.app/Contents/Resources /usr/local/lib/mit-scheme-x86-64
4. sudo ln -s /usr/local/lib/mit-scheme-x86-64/mit-scheme /usr/local/bin/scheme
5. Type scheme on the terminal.

undefined method `want=' for nil:NilClass (NoMethodError)

In Rails 4.2, you can define your own application specific custom variables in development.rb, test.rb and so on. If you define this:

  config.x.whatever.value.want = 42

It throws the error : undefined method `want=' for nil:NilClass (NoMethodError)

It seems to work only for two levels, so, this will work:

  config.x.whatever.value = 42

You can access the value like this:

Rails.configuration.x.whatever.value

You need to define the custom values by using 'config.x'.

Thursday, January 21, 2016

Error in The Well Grounded Rubyist Book

David Black says "The only circumstances under which you can omit the receiver are precisely the circumstance in which it's ok to call a private method."

 This is not true because we can omit the receiver when we call the class method declared in the superclass. ActiveRecord has_many declaration is an example.

Tuesday, January 19, 2016

Looking for Ruby Book Reviewers

I am looking for technical reviewers to review Essential Ruby Kindle book. I will mention your name and give a link to your site or blog  in the book. If you are interested, please contact me at bparanj at gmail dot com or RubyPlus contact form.

Tuesday, January 12, 2016

How to find out if a name is reserved in Rails 4.2.5

One of the articles that gets lot of traffic is : Reserved Words in Rails. If you do not use the generator to generate the code in your Rails project, you could potentially have class collision during runtime of your application. Here are the steps I followed:

1. I browsed the railties gem and searched for 'reserved by Ruby on Rails' to find where in the source code the check is done.
2. It is defined in the class rails/generators/base.rb in class_collisions(*class_names) protected method.
3. I went to the rails console to figure out how to use this method:

> require 'rails/generators/base'
NameError: uninitialized constant Rails::Generators::Actions
from /Users/bparanj/.rvm/gems/railties-4.2.5/lib/rails/generators/base.rb:17:in `'
pry(main)> require 'rails/generators/actions'
=> true
 pry(main)> require 'rails/generators/base'
=> true
 pry(main)> g = Rails::Generators::Base.new
=> # @_initializer=[[], {}, {}],
 @_invocations={},
 @after_bundle_callbacks=[],
 @args=[],
 @behavior=:invoke,
 @destination_stack=["/Volumes/Work/dev/ewok"],
 @in_group=nil,
 @options={},
 @shell=#, @mute=false, @padding=0>>
 pry(main)> g.send(:class_collisions, 'ActiveRecord')
Rails::Generators::Error: The name 'ActiveRecord' is either already used in your application or reserved by Ruby on Rails. Please choose an alternative and run this generator again.
pry(main)> g.send(:class_collisions, 'type')
=> ["type"]
pry(main)> g.send(:class_collisions, 'ActiveRecord', 'ActiveJob')
Rails::Generators::Error: The name 'ActiveRecord' is either already used in your application or reserved by Ruby on Rails. Please choose an alternative and run this generator again.



Methods Live in Class

$ irb
2.2.4 :001 > s = 'hi'
 => "hi"
2.2.4 :002 > s.methods
 => [:<=>, :==, :===, :eql?, :hash, :casecmp, :+, :*, :%, :[], :[]=, :insert, :length, :size, :bytesize, :empty?, :=~, :match, :succ, :succ!, :next, :next!, :upto, :index, :rindex, :replace, :clear, :chr, :getbyte, :setbyte, :byteslice, :scrub, :scrub!, :freeze, :to_i, :to_f, :to_s, :to_str, :inspect, :dump, :upcase, :downcase, :capitalize, :swapcase, :upcase!, :downcase!, :capitalize!, :swapcase!, :hex, :oct, :split, :lines, :bytes, :chars, :codepoints, :reverse, :reverse!, :concat, :<<, :prepend, :crypt, :intern, :to_sym, :ord, :include?, :start_with?, :end_with?, :scan, :ljust, :rjust, :center, :sub, :gsub, :chop, :chomp, :strip, :lstrip, :rstrip, :sub!, :gsub!, :chop!, :chomp!, :strip!, :lstrip!, :rstrip!, :tr, :tr_s, :delete, :squeeze, :count, :tr!, :tr_s!, :delete!, :squeeze!, :each_line, :each_byte, :each_char, :each_codepoint, :sum, :slice, :slice!, :partition, :rpartition, :encoding, :force_encoding, :b, :valid_encoding?, :ascii_only?, :unpack, :encode, :encode!, :to_r, :to_c, :unicode_normalize, :unicode_normalize!, :unicode_normalized?, :>, :>=, :<, :<=, :between?, :nil?, :!~, :class, :singleton_class, :clone, :dup, :itself, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :extend, :display, :method, :public_method, :singleton_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]
2.2.4 :003 > s.instance_methods
NoMethodError: undefined method `instance_methods' for "hi":String
    from (irb):3
    from /Users/bparanj/.rvm/rubies/ruby-2.2.4/bin/irb:11:in `
'
2.2.4 :004 > String.instance_methods
 => [:<=>, :==, :===, :eql?, :hash, :casecmp, :+, :*, :%, :[], :[]=, :insert, :length, :size, :bytesize, :empty?, :=~, :match, :succ, :succ!, :next, :next!, :upto, :index, :rindex, :replace, :clear, :chr, :getbyte, :setbyte, :byteslice, :scrub, :scrub!, :freeze, :to_i, :to_f, :to_s, :to_str, :inspect, :dump, :upcase, :downcase, :capitalize, :swapcase, :upcase!, :downcase!, :capitalize!, :swapcase!, :hex, :oct, :split, :lines, :bytes, :chars, :codepoints, :reverse, :reverse!, :concat, :<<, :prepend, :crypt, :intern, :to_sym, :ord, :include?, :start_with?, :end_with?, :scan, :ljust, :rjust, :center, :sub, :gsub, :chop, :chomp, :strip, :lstrip, :rstrip, :sub!, :gsub!, :chop!, :chomp!, :strip!, :lstrip!, :rstrip!, :tr, :tr_s, :delete, :squeeze, :count, :tr!, :tr_s!, :delete!, :squeeze!, :each_line, :each_byte, :each_char, :each_codepoint, :sum, :slice, :slice!, :partition, :rpartition, :encoding, :force_encoding, :b, :valid_encoding?, :ascii_only?, :unpack, :encode, :encode!, :to_r, :to_c, :unicode_normalize, :unicode_normalize!, :unicode_normalized?, :>, :>=, :<, :<=, :between?, :nil?, :!~, :class, :singleton_class, :clone, :dup, :itself, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :extend, :display, :method, :public_method, :singleton_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]

Monday, January 11, 2016

Changing Self inside the Block

(1..10).tap {|x| puts "original: #{x.inspect}"}.tap {|x| puts "Original class: #{x.class}"}.to_a.tap {|x| puts "array: #{x.inspect}"}.tap {|x| puts "After class: #{x.class}"}