Escape a string for transportation in a URL
To safely transport an arbitrary string within a URL, you need to percent-encode characters that have a particular meaning in URLs, like &
or =
.
If you are using Rails URL helpers like movies_path(:query => ARBITRARY_STRING_HERE)
, Rails will take care of the encoding for you. If you are building URLs manually, you need to follow this guide.
Ruby
In Ruby, use CGI.escape
:
# ✅ good
CGI.escape('foo=foo&bar=bar')
=> "foo%3Dfoo%26bar%3Dbar"
Do not ever use `URI.en...
Improving browser rendering performance
As the web is being used for more and more tasks, expectations rise. Not only should web pages offer rich interaction, they must be responsive in both size and interaction.
This imposes a paradoxon that needs to be solved by building performing applications. It's not enough any more to have your web site do crazy stuff, it is also required to do it crazy fast. This card is intended to give you an introduction to this emerging aspect of web development.
Read this introductory [performance study on Pinterest](http://www.smashingmagazine.com/...
httpclient: A Ruby HTTP client for serious business
While debugging an intricate issue with failed HTTP requests I have come to appreciate the more advanced features of the httpclient Rubygem.
The gem is much more than a lightweight wrapper around Ruby's net/http
. In particular:
- A single
HTTPClient
instance can re-use persistent connections across threads in a thread-safe way. - Has a custom and configurable SSL certificate store (which you probably want to disable by default...
Installing Node.js / npm under Ubuntu with nvm (with yarn)
I recommend install Node.js using nvm. This way you can have multiple Node versions in your ~/.nvm
. You also won't need to install global packages with sudo
anymore.
Node via nvm will automatically bring npm. yarn will automatically be available if corepack is enabled for node.
Installing nvm
DigitalOcean has a HOWTO for installing nvm on Ubuntu (16.04, [18.04](https://www.digitalocean.com/community/tutorials/how-to-...
How to iterate over an Enumerable, returning the first truthy result of a block ("map-find")
Ruby has Enumerable.find(&block)
, which returns the first item in the collection for which the block evaluates to true
.
first_post_with_image = posts.find do |post|
post.image
end
However, sometimes it's not the item you're interested in, but some value depening on it – e.g. the value the block evaluated to. You could first map the collection and then take the first truthy value, but this way you need to process the whole collection twice:
first_image_url = posts.map(&:image).find(&:present?).url
If the mapp...
include_tags with the asset pipeline
You can include files from app/assets
or from the public
folder with javascript_include_tag
. The subtle difference that tells rails how to build the path correctly is a single slash at the beginning of the path:
<%= javascript_include_tag('ckeditor/config') %> # for assets/ckeditor/config.js
<%= javascript_include_tag('/ckeditor/ckeditor') %> # for public/ckeditor/ckeditor.js
This also applies to stylesheet_link_tag
.
Note that when you refer to a Javascript or stylesheet in /assets
you need to add it to [the list of asse...
How to split config/routes.rb in Rails 4
A word of caution
There should rarely be a reason for you to split up config/routes.rb
. If you need to, probably your whole application should be split up.
Split it anyway
Rails::Engine
looks at config.paths['config/routes.rb']
and registers its value with app.routes_reloader
. This means you could put routing files anywhere and then require them. However, I recommend to put any routing files into config/routes/
:
# config/routes/example.rb
Rails.application.routes.draw do
resources :example
end
After creating y...
Using tig
tig
is a command line explorer for Git that is just awesome. Install via apt-get
or brew
.
Handy commands
-
t
("tree"): Directory-structure based access. You'll see the current directory annotated with the latest change date and its author. Navigate with arrow keys or vim. -
b
("blame"): Opens the file under the cursor and annotates each line with change date and author. -
d
("diff"): LikeENTER
on a commit, but arrow keys will scroll the diff! -
/
: Search current view (e.g. commit list, diff). Jump to next hit withn
....
How to enable SSL in development with Passenger standalone
Here is how to start your Rails application to accept both HTTP and HTTPS in development.
-
gem install passenger
-
Create a self-signed SSL certificate. Store the generated files in config/passenger-standalone-ssl.
-
Create a Passengerfile.json at the project root with this content (or save the attached file):
{ "ssl": true, "ssl_port": 3001, "ssl_certificate": "config/passenger-standalone-ssl/server.crt",
...
List of Helpful RubyMine Shortcuts
Navigation
CTRL + SHIFT + ALT + N
-
Search for any symbol in your application, like CSS classes, Ruby classes, methods, helpers etc.
CTRL + SHIFT + N
-
Search for filename in your application (also dependencies)
CTRL + E
-
Open a list of recently opened files
ALT + POS1
-
Open a the navigation bar as a context menu. Allows you to quickly navigate between files.
CTRL + G
-
Go to line
Actions
:...
Capistrano 3 has slightly changed its symlink implementation
In Capistrano 2, directories in shared_children
used to be symlinked to the shared
directory during the finalize_update
task.
# <capistrano>/lib/capistrano/recipes/deploy.rb
_cset :shared_children, %w(public/system log tmp/pids)
# ...
task :finalize_update, :except => { :no_release => true } do
# ...
shared_children.map do |d|
run "ln -s #{shared_path}/#{d.split('/').last} #{latest_release}/#{d}" # <-- symlinks only the last s...
Faster debugging with RubyMine macros
In my RubyMine I have recorded two macros for debugging and linked them to some keyboard shortcuts. Since I believe everyone could benefit from having those I wanted to share this.
The first one simply inserts
binding.pry
and the second one
.tap { |object| binding.pry }
for when you do not have a reference to the object you want to inspect.
In order to record a macro you simply follow the path Edit > Macros > Start Macro Recording
.
Then you simply type binding.pry
or whatever you want to record and stop recor...
Rails 4.1+ automatically detects the :inverse_of an association
Starting from 4.1, Rails automatically detects the inverse of an association, based on heuristics. Unfortunately, it does not seem to notify you when it fails to infer the :inverse_of
, so you are better off to always manually set :inverse_of anyway.
Note that automatic inverse detection only works on
has_many
,has_one
,belongs_to
associations. Extra options on the associations will prevent the association's...
Databases don't order rows unless you tell them so
There is no such thing as a "default order" of rows in database tables.
For instance, when you paginate a result set: When using LIMIT
, it is important to use an ORDER BY
clause that constrains the result rows into a unique order. Otherwise you will get an unpredictable subset of the query's rows. You might be asking for the tenth through twentieth rows, but tenth through twentieth in what ordering? The ordering is unknown, unless you specified ORDER BY
.
In Rails, if you use Record.first
or Record.last
, it will default to orderin...
Exception Notifier: Foreground vs. background sections
Since version 2.6 exception notifier distinguishes between foreground and background sections. The reason is that with background jobs (e.g. methods that are called by a cron job) some variables are not available for exception notifier, e.g. @request
and @kontroller
.
Therefore you can configure foreground and background sections individually. Our default settings are documented in Get notified when your application raises an error.
**W...
Reverse-proxying web applications with Apache 2.4+
Note: Making a reverse proxy with nginx is much more straightforward.
A reverse proxy is a "man in the middle" server that tunnels requests to another server. You can use for things like:
- Expose a local service that you cannot directly reach over the internet
- "Change" the domain or path of a web application by rewriting them on the fly
- Instantly change servers that respond to a name or ...
Upgrading from Capistrano 2 to 3
Capistrano 3 is a major rework of the framework and requires several adjustments to your deploy configuration files. The biggest change is that they moved away from their custom DSL and use Rake
instead. For connecting with and operating on the servers, they bring a new gem SSHKit
which does the heavy lifting. It's SSHKit's DSL that is used anywhere inside the Rake tasks. See #Resources at the bottom for examples.
Step 1: Upgrade guide
For migration from 2 to 3, follow this tutorial: [Capistrano 3 Upgrade Guide](https://semaphorec...
Savon testing: How to expect any message
When using Savon to connect a SOAP API, you may want to use Savon::SpecHelper
to mock requests in your tests as described in their documentation.
When sending a message body, the savon
mock object requires a message to be set, like this:
savon.expects(:action_name).with(message: { user_id: 123 }).returns('<some xml>')
If you want to stub only the returned XML and do not care about request arguments, you can not omit with
as Savon's helper will complain:
savo...
Why you see a GET "/__identify__" request in Capybara tests
You might wonder about this request in your test.log
:
Started GET "/__identify__" for 127.0.0.1 at 2015-04-29 18:00:02 +0100
This is what happens: For drivers like Selenium, Capybara will boot up a Thin or Webrick server in a separate thread. It then makes a GET request to /__identify__
to see if the server is ready to accept requests.
Since you don't have a route that responds to /__identify
, Capybara will wrap your Rails app in...
Using mime types with send_file
When using send_file
(for example for attachments of any kind), make sure your application knows the correct mime types so that all browsers can handle the files. It is much more convenient for users if they can decide to open a file directly instead of having to save it first.
For Rails >= 3.2
Simply put your mime types in config/initializers/mime_types.rb
. send_file
will take care of everything else.
For Rails < 3.2
Put your mime types in config/initializers/mime_types.rb
. Additionally, tell send_file
to use them (for ex...
Capybara: Waiting for pending AJAX requests after a test
When ending a Selenium test Capybara resets the browser state by closing the tab, clearing cookies, localStorage
, etc.
It may be a good idea to wait for all in-flight AJAX requests to finish before ending a scenario:
- You may have client-side JavaScript that freaks out when the tab closure kills their pending requests. If that JavaScript opens an error alert or spams errors to the console, your test may fail after the last step.
- With unlucky timing the server may receive an AJAX request as the browser tab closes, causing a connection ...
Browse Amazon S3 buckets with Ubuntu Linux
There are some frontends available, but they all suck, are no longer maintained or are hard to install.
As a surprisingly comfortable alternative I have found a command line tool s3cmd
:
sudo apt-get install s3cmd
When you run s3cmd
the first time it will ask you for your access key ID and secret access key. This information is cached somewhere so you only need to write them once. To reconfigure later, call s3cmd --configure
.
Once you're done setting up, s3cmd
gives you shell-like commands like s3cmd ls
or `s3cmd del som...
Differences between transactions and locking
Web applications can be used by multiple users at the same time. A typical application server like Passenger has multiple worker processes for a single app. In a distributed deployment setup like we use at makandra you will even have multiple application servers, each with their own worker pool.
This means that your code needs to deal with concurrent data access. The two main tools we use to cope with concurrency are database transactions and distributed locks. These two are not interchangeable. You ca...
Slack integration for deployments via Capistrano
You can hook into Slack when using Capistrano for deployment. The slackistrano gem does most of the heavy lifting for you. Its default messages are unobtrusive and can be adjusted easily.
When deploying, it posts to a Slack channel like this:
How to integrate
Integrating Slackistrano with Capistrano 3 is fairly simple.
- In your Slack, open menu → A...