Sending TCP keepalives in Ruby
When you make a simple TCP connection to a remote server (like telnet), your client won't normally notice when the connection is unexpectly severed on the remote side. E.g. if someone would disconnect a network cable from the server you're connected to, no client would notice. It would simply look like nothing is being sent.
You can detect remote connection loss by configuring your client socket to send TCP keepalive signals after some period of inactivity. If those signals are not acknowledged by the other side, your client will terminat...
Test downstream bandwidth of Internet connection
You want to test your 1GE or 10GE internet uplink? We needed to ensure we have full 10GE to the backbone for a customer project.
Using netcat
To test whether we can achieve the bandwidth internally, you can use netcat and dd like this:
On your first server: nc -v -l 55333 > /dev/null
On your second server: dd if=/dev/zero bs=1024K count=5000 | nc -v $remote_ip 55333
You should see some output like this:
user@xxx:~ % dd if=/dev/zero bs=1024K count=5000 | nc -v removed 55333
Connection to 91.250.95.249 55333 port [...
Ruby: How to make an object that works with multiple assignment
Ruby allows multiple assignment:
a, b, c = o
In order to prove multiple values from a single object, Ruby calls #to_a on the object:
o = String.new('O')
def o.to_a
[1,2,3]
end
a, b, c = o # Implicit call to #to_a here
a # => 1
b # => 2
c # => 3
Hence, if you want your class to support multiple assignment, make sure to define a #to_a method.
Heads up: Ruby implicitly converts a hash to keyword arguments
When a method has keyword arguments, Ruby offers implicit conversion of a Hash argument into keyword arguments. This conversion is performed by calling to_hash on the last argument to that method, before assigning optional arguments. If to_hash returns an instance of Hash, the hash is taken as keyword arguments to that method.
Iss...
Ruby: Do not mix optional and keyword arguments
Writing ruby methods that accept both optional and keyword arguments is dangerous and should be avoided. This confusing behavior will be deprecated in Ruby 2.7 and removed in Ruby 3, but right now you need to know about the following caveats.
Consider the following method
# DO NOT DO THIS
def colored_p(object = nil, color: 'red')
switch_color_to(color)
puts object.inspect
end
colored_p(['an array']) # ['an array'] (in red)
colored_p({ a: 'hash' }, color: 'blue') # {:a=>'hash'} (in blue)
colored_p({ a: 'ha...
ExceptionNotification gem will only show application backtrace starting on Rails 4
Starting with Rails 4.0, when you get an exception reported via the ExceptionNotification gem, you will only see a very short backtrace with all backtrace lines from gems or ruby libraries missing.
This happens, because the ExceptionNotification gem uses Rails' default backtrace cleaner. To get a full backtrace in exception emails, you can remove the comment from this line in config/initializers/backtrace_silencers.rb:
Rails.backtrace_cleaner.remove_silencers!
Note that this will break the "Application Trace" functionality o...
Enumerators in Ruby
Starting with Ruby 1.9, most #each methods can be called without a block, and will return an enumerator. This is what allows you to do things like
['foo', 'bar', 'baz'].each.with_index.collect { |name, index| name * index }
# -> ["", "bar", "bazbaz"]
If you write your own each method, it is useful to follow the same practice, i.e. write a method that
- calls a given block for all entries
- returns an enumerator, if no block is given
How to write a canonical each method
To write a m...
OR-ing query conditions on Rails 4 and 3.2
Rails 5 will introduce ActiveRecord::Relation#or. On Rails 4 and 3.2 you can use the activerecord_any_of gem which seems to be free of ugly hacks and nicely does what you need.
Use it like this:
User.where.any_of(name: 'Alice', gender: 'female')
^
SELECT "users".* FROM "users" WHERE (("users"."name" = 'Alice' OR "users"."gender" = 'female'))
To group conditions, wrap them in hashes:
User.where.any_of({ name: 'Alice', gender: 'female' }, { name: 'Bob' }, { name: 'Charl...
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...
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
HTTPClientinstance 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...
Error installing gem with native extension (collect2: error: ld returned 1 exit status)
If you have problems installing a gem and get a error collect2: error: ld returned 1 exit status it's due to missing development headers of a library (ld is the linker).
For example, with this output:
$ gem install json
Building native extensions. This could take a while...
ERROR: Error installing json:
ERROR: Failed to build gem native extension.
/home/foobar/.rvm/rubies/ruby-2.2.3/bin/ruby -r ./siteconf20150915-3539-1i9layj.rb extconf.rb
creating Makefile
make "DESTDIR=" clean
make "DESTDIR="
compiling generator.c...
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...
How to update RubyGems binary for all installed rubies
To update your Rubygems to the latest available version, type the following:
gem update --system
Note that you have a separate Rubygems installation for each Ruby version in your RVM or rbenv setup. Updating one does not update the others.
Ruby 1.8.7
If you are using Ruby 1.8.7 you cannot use the latest version of Rubygems. Type the following to get the latest version that is compatible with 1.8.7:
gem updat...
Matching Unicode characters in a Ruby regexp
On Ruby 1.9+, standard ruby character classes like \w, \d will only match 7-Bit ASCII characters:
"foo" =~ /\w+/ # matches "foo"
"füü" =~ /\w+/ # matches "f", ü is not 7-Bit ASCII
There is a collection of character classes that will match unicode characters. From the documentation:
-
/[[:alnum:]]/Alphabetic and numeric character -
/[[:alpha:]]/Alphabetic character -
/[[:blank:]]/Space or tab -
/[[:cntrl:]]/Control character -
/[[:digit:]]/Digit -
/[[:graph:]]/Non-blank character (excludes spaces...
List RubyGems binary version for all installed Ruby versions
rbenv
To check which rubygems versions your different rbenv rubys are using, you can use this small bash script:
for i in $(rbenv versions --bare); do rbenv shell "${i}"; echo -n "ruby ${i} has gem version: "; gem -v; done
RVM
rvm all do gem -v
marco-polo improves your Rails console prompt
MarcoPolo shows your app name and environment in your console prompt so you don't accidentally break production
Officially supporting IRB (standard rails console) and pry (via pry-rails gem).
Example:
$ rails console
Loading development environment (Rails 4.2.1)
agencyapp(dev)>
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
:...
Detecting N+1 queries with Bullet
The Bullet gem is designed to help you increase your application's
performance by reducing the number of queries it makes. It will watch
your queries while you develop your application and notify you when
you should add eager loading (N+1 queries), when you're using eager
loading that isn't necessary and when you should use counter cache.
The Complete Guide to Rails Caching
Very detailed guide to caching Ruby on Rails.
Goes well with the official Rails guide on caching.
emcien/iso_latte
Sometimes you need to run background jobs that you can't make important guarantees about - they may run out of memory and get killed, or produce segmentation faults, or exit! directly - and you need to be able to clean up after such problems.
IsoLatte is a gem that allows a block of code to be executed in a subprocess. Exceptions get passed back to the parent process through a pipe, and various exit conditions are handled via configurable callbacks.
Savon: Use complex SOAP types as arguments
If a SOAP API expects you to call a remote method with arguments of complex types, Savon lets you manually set the xsi:type attribute like this:
client.call(:rpc_method,
message: {
:some_object => {
:name => 'foo',
:other => 'bar',
'@xsi:type' => 'somenamespace:SomeObject'
}
}
)
This is roughly equivalent to this in Javaland, where you have magic generated stub code:
SomeObject so = new SomeObject();
so.setName('foo');
so.setOther('bar');
client.rpcMethod(so);
ZenTest "invalid gemspec" / "Illformed requirement"
Today I ran into this:
Invalid gemspec in [/usr/local/rvm/gems/ruby-1.9.3-p194/specifications/ZenTest-4.9.3.gemspec]: Illformed requirement ["< 2.1, >= 1.8"].
You need a newer Rubygems version. Try this: gem update --system 1.8.29