Querying model errors in Rails 4
ActiveModel
supplies an errors object that behaves similar to a Hash. It can be used to add errors to a record, as well as to query the record for registered errors. This object is returned when calling <object>.errors
:
errors = @user.errors # => #<ActiveModel::Errors ...>
Here are some helpful messages of its API:
[<attribute name>]
: Returns an array of error messages on that attribute. Example: errors[:name] => ['is missing']
add_on_blank(<attribute list>)
(similarly add_on_empty
)
: Registers an error fo...
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 ...
Gatekeeping: Guide for gatekeeper
If you're responsible for gatekeeping in a projects, here is a guide, what to do.
In order to reduce the number of rejects we get from clients, we want to review all code written before it goes to the staging server.
Note: This process is tailored to our specific needs and tools at makandra. While it will certainly not apply to all (especially larger teams), we think it is a helpful starting point.
First, read the [Gatekeeping for developers](https://makandracards.com/makandra/6579-gatekeeping-guide-for...
Manually trigger a delegated DOM event
When you register a delegated event using on
(or the deprecated delegate
/ live
), it is somewhat hard to manually trigger these events manually, e.g. for testing.
After trying jQuery's trigger
to no avail, I had success by using native Javascript methods to create and dispatch an event. For instance, to trigger a mousedown
event:
element = $('...').get(0);
event = new MouseEvent('mousedown', { view: window, cancelable: true, bubbles: true }...
Show details of TLS/SSL connections of remote hosts
sslscan
is a nice tool to show details about TLS/SSL connections:
~> sslscan some-host-at.makandra.de
Testing SSL server some-host-at.makandra.de on port 443
Supported Server Cipher(s):
Failed SSLv3 256 bits ECDHE-RSA-AES256-GCM-SHA384
Failed SSLv3 256 bits ECDHE-ECDSA-AES256-GCM-SHA384
Failed SSLv3 256 bits ECDHE-RSA-AES256-SHA384
Failed SSLv3 256 bits ECDHE-ECDSA-AES256-SHA384
Rejected SSLv3 256 bits ECDHE-RSA-AES256-SHA
...
Prefered Server Cipher(s):
TLSv1 128 bits ECDHE-RSA-A...
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...
CucumberFactory 1.11 lets you use FactoryGirl traits
If you have FactoryGirl traits like this:
factory :movie do
title 'Sunshine'
year 2007
trait :vintage do
year 1951
end
trait :moody do
title 'Interstellar'
end
end
You can now call them from Cucumber Factory like this:
Given there is a movie (vintage, moody)
Cucumber step to pick a datetime in Rails' horrible datetime_select
Please don't use the horrible datetime_select
helper. It has a terrible UI. Always prefer to use a visual time picker like Rome instead.
In case everything has failed and you do need a Cucumber step to pick a datetime datetime_select
, here it is:
When(/^I select the time (\d+)\-(\d+)\-(\d+) (\d+):(\d+) from "(.*?)"$/) do |year, month, day, hour, minute, label_text|
label = page.find('label', text: label_text)
id = label[...
has_defaults 0.4.2 lets you use dagger lambdas
Starting with has_defaults
0.4.2, default values that are lambdas are no longer called with the current object as argument, but instance_exec
'd instead.
This means you can now use dagger lambdas like this:
has_defaults :full_name => -> { "#{first_name} #{last_name}" }
You can also use lambda
and proc
as long as you don't take parameters:
has_defaults :full_name => lambda { "#{first_name} #{last_name}" }
has_defaults :full_name => proc { "#{first_name} #{last_name}" }
You can no longer write this:
has...
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...
Ubuntu: Make Ctrl-Space work in RubyMine, Emacs, or other tools
I was annoyed that RubyMine's autocompletion did not work via Ctrl+Space for me. In fact, it did not work in any application.
Turns out that keyboard combination was hijacked by Ubuntu as it's the default for switching input languages (i.e. keyboard layouts). If you use only 1 language/layout, you will not notice except for the key not working.
To fix it, do the following:
- Run
ibus-setup
(e.g. from a terminal). This will open a GUI dialog. - In the 1st tab you should see "Next Input Method" followed by "
<Control>space
". - Click t...
Detect recently added vdisks in a VMware ESXi linux guest
After adding a vdisk to an ESXi linux guest you will assert that you can't find a new device in the running VM. You have to force a SCSI rescan.
- find your host bus number with:
grep mtpspi /sys/class/scsi_host/host?/proc_name
- output should look like this: /sys/class/scsi_host/host2/proc_name:mptspi where the bold part is what you're searching for
- force an SCSI rescan with
echo "- - -" > /sys/class/scsi_host/<host>/scan
and insert the host found in point two for<host>
-
cat /proc/scsi/scsi
should now show the new ad...
Customizable date (and time) picker: Rome
Datetime picker that offers:
- simple UI without a specific framework
- several of customization options
- allows custom date/time validations
Localization happens via moment.js (which is a Dependency anyway).
However, you won't be happy trying to customize it too much:
- It does not support full custom templates, you can only set classes of its elements. If you require extra containers, you are out of luck.
- It offers only a few events, and you can not distinguish if users pick a date, switch to another month, or click outside of the p...
LibreOffice / Excel: Use tables like a hash map in formulas with VLOOKUP
If you're a frequent user of LibreOffice, I strongly recommend to checkout out the VLOOKUP
function (SVERWEIS
in German). It allows you to treat a column pair as a hash map, where you lookup keys in the first column and return values from the second.
Clusterize.js
Small (1.5 KB) Javascript library that lets you render tables, lists, etc. with hundreds of thousands of items.
How it works is that you move your data set from the DOM into JS. Clusterize than makes sure only the rows in the viewport (and adjacent batches) are rendered.
I believe that AngularUI's data grid component uses a similar technique to reduce the number of bindings in large tables, but I can't seem to find documentation on that.
Testing setTimeout and setInterval with Jasmine
Jasmine has a jasmine.clock()
helper that you can use to travel through time and trigger setTimeout
and setInterval
callbacks:
beforeEach(function() {
timerCallback = jasmine.createSpy("timerCallback");
jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
});
it("causes a timeout to be called", function() {
setTimeout(function() {
timerCallback();
}, 100);
expect(timerCallba...
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...
The Ruby Toolbox – a collection of good gems
If you need a gem for a certain purpose, be sure to check this site.
The rankings are determined by counting up the number of forks and watchers of various github projects, so I'd view it less as "this is what I should be using," and more as "these are some things I should check out." At the very least, they're all likely to be under active development and fairly up to date, and it's very useful to see groups of gems broken down by category.
TrackDuck: Visual feedback for web design and development
Service that you can integrate for user feedback.
Super-simple integration: Add a <script>
tag to your layout, done.
It will then add a button to the bottom right of your application. When a user clicks it, they can take a screenshot and leave a message. The screenshot then appears in TrackDuck's interface for you to work off.
Current pricing is 9 USD per month for the smallest tier (1 project).
A solid and unobtrusive plugin for form field placeholders
jquery-placeholder
is a simple jQuery plugin that enables form placeholders in browsers that do not support them natively, i.e. IE < 10.
Properties
- Works in IE6.
- Automatically checks whether the browser natively supports the HTML5 placeholder attribute for input and textarea elements. If this is the case, the plugin won’t do anything. If @placeholder is only supported for input elements, the plugin will leave those alone and apply to textareas exclusively. (This is the case for Safari 4, Opera 11.00, and possibly other browsers.)
...
Ruby bug: Symbolized Strings Break Keyword Arguments in Ruby 2.2
TL;DR Under certain circumstances, dynamically defined symbols may break keyword arguments in Ruby 2.2. This was fixed in Ruby 2.2.3 and 2.3.
Specifically, when …
- there is a method with several keyword arguments and a double-splat argument (e.g.
def m(foo: 'bar, option: 'will be lost', **further_options)
) - there is a dynamically created
Symbol
(e.g.'culprit'.to_sym
) that is created before the method is parsed - the method gets called with both the
option
and aculprit
keyword argument
… then the `optio...
Make timestamp of dmesg in Ubuntu human readable
dmesg
shows the kernel ring buffer containing low-level system messages.
Per default, dmesg
shows a timestamp:
12:59:26 fnordomator ~ > dmesg | tail
[101925.211846] usb 2-1.1: USB disconnect, device number 16
[110486.855788] usb 2-1.1: new high-speed USB device number 17 using ehci_hcd
If you're a human, use dmesg -T
to print the timestamp human readable:
12:59:31 fnordomator ~ > dmesg -T | tail
[Di Apr 21 12:43:16 2015] usb 2-1.1: USB disconnect, device number 16
[Di Apr 21 15:05:57 2015] usb 2-1.1: new hig...
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...