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.
Sunday, April 10, 2016
Saturday, April 09, 2016
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/
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/
Tuesday, April 05, 2016
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.
<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.
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
xcode-select: Error: No Xcode folder is set. Run xcode-select -switch
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
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
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.
Sunday, March 27, 2016
Saturday, March 26, 2016
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? %>
<% 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 %>
<%= 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:
- <%= message %>
<% project.errors.full_messages.each do |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
.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 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
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'
to exclude certain things, pipe to grep -v 'string to exclude'
Saturday, March 19, 2016
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.
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
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.
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.
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
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')
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.
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:
- Separate things that change from things that stays the same. Encapsulate what varies behind a well-defined interface.
- Program to interfaces, not implementations. This exploits polymorphism.
- 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.
Amazon Docs
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.
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/
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
2. In production.rb:
config.middleware.use HtmlCompressor::Rack
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.
group :production do
gem 'htmlcompressor'
end
Run bundle install.
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?
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.
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
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/
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.
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
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/
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
Sunday, February 28, 2016
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
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.
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]
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?
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
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
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)
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.
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'.
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.
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.
Sunday, January 17, 2016
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.
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
=> #
@_invocations={},
@after_bundle_callbacks=[],
@args=[],
@behavior=:invoke,
@destination_stack=["/Volumes/Work/dev/ewok"],
@in_group=nil,
@options={},
@shell=#
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__]
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}"}
Tuesday, January 05, 2016
Friday, January 01, 2016
Subscribe to:
Posts (Atom)




























