Tasks, microtasks, queues and schedules - JakeArchibald.com
The way that Javascript schedules timeouts and promise callbacks is more complicated than you think. This can be the reason why callbacks are not executed in the order that they are queued.
Please read this article!
This is an extract of the example in the article which demonstrates the execution order of tasks and microtasks.
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
})...
How to organize monkey patches in Ruby on Rails projects
As your Rails project grows, you will accumulate a number of small patches. These will usually fix a bug in a gem, or add a method to core classes.
Instead of putting many files into config/initializers
, I recommend to group them by gem in lib/ext
:
lib/
ext/
factory_girl/
mixin.rb
carrierwave/
change_storage.rb
fix_cache_ids.rb
sanitize_filename_characters.rb
ruby/
range/
covers_range.rb
array/
dump_to_excel.rb
xss_aware_join.rb
enumerable/
...
Dynamically uploading files to Rails with jQuery File Upload
Say we want …
- to create a
Gallery
that has a name andhas_many :images
, which in turn have a caption - to offer the user a single form to create a gallery with any number of images
- immediate uploads with a progress bar per image
- a snappy UI
Enter jQuery File Upload. It's a mature library that can do the job frontend-wise. On the server, we'll use Carrierwave, because it's capable of caching images.
(FYI, [here's how to do the u...
UI Sortable on table rows with dynamic height
UI sortable helps reordering items with drag 'n drop. It works quite fine.
Proven configuration for sorting table rows
When invoking the plugin, you may pass several options. This set is working fine with table rows:
$tbody.sortable # Invoke on TBODY when ordering tables
axis: 'y' # Restrict drag direction to "vertically"
cancel: 'tr:first-child:last-child, input' # Disable sorting a single tr to prevent jumpy table headers
containment: 'parent' # Only drag within this container
placehol...
Testing Cookie Limits
TL;DR If you want to support most browsers, then don't exceed 50 cookies per domain, and don't exceed 4093 bytes per domain (i.e. total size of all cookies <= 4093 bytes)
Behind the link, you'll find a simple HTML page that offers some cookie tests (how large, how many etc) and an overview of this data for various browsers.
Fun fact: You cannot delete cookies with a key that hits the size limit and has a small value.
How to inspect RSS feeds with Spreewald, XPath, and Selenium
Spreewald gives you the <step> within <selector>
meta step that will constrain page inspection to a given scope.
Unfortunately, this does not work with RSS feeds, as they're XML documents and not valid when viewed from Capybara's internal browser (e.g. a <link>
tag cannot have content in HTML).
Inspecting XML
If you're inspecting XML that is invalid in HTML, you need to inspect the page source instead of the DOM. You may use Spreewald's "... in the HTML" meta step, or add this proxy step fo...
RSpec: Scoping custom matchers to example groups
When you find yourself in the situation that you would like to define a custom matcher in your specs, but you do not want to define a global matcher since you need it only for your specific test, there are two ways to do it:
Custom matcher for a single group
If you're only going to include
a matcher once, you can also use the matcher
macro within an example group:
describe "group" do
matcher :be_just_like do |expected|
match {|ac...
Delay your Jasmine tests until the document is ready
To delay your entire Jasmine test suite until the DOM is ready, add the following:
beforeAll(function(done) {
$(done);
});
thoughtbot/fake_stripe: A Stripe fake so that you can avoid hitting Stripe servers in tests.
fake_stripe spins up a local server that acts like Stripe’s and also serves a fake version of Stripe.js, Stripe’s JavaScript library that allows you to collect your customers’ payment information without ever having it touch your servers. It spins up when you run your feature specs, so that you can test your purchase flow without hitting Stripe’s servers or making any external HTTP requests.
We've also had tests actually hitting the testing sandbox of Stripe, which worked OK most of the time (can be flakey).
How to fix: "rake db:rollback" does not work
When you run rake db:rollback
and nothing happens, you are probably missing the latest migration file (or have not migrated yet).
$ rake db:rollback
$
If that happens to you, check your migration status.
$ rake db:migrate:status
up 20160503143434 Create users
up 20160506134137 Create pages
up 20160517112656 Migrate pages to page versions
up 20160518112023 ********** NO FILE **********
When you tell Rails to roll back, it tries to roll back the latest change that was mi...
How to explain SQL statements via ActiveRecord
ActiveRecord offers an explain
method similar to using EXPLAIN
SQL statements on the database.
However, this approach will explain all queries for the given scope which may include joins
or includes
.
Output will resemble your database's EXPLAIN style. For example, it looks like this on MySQL:
User.where(id: 1).includes(:articles).explain
EXPLAIN for: SELECT `users`.* FROM `users` WHERE `users`.`id` = 1
+----+-------------+-------+-------+---------------+
| id | select_type | table | type | possible_keys |
+----+-----...
How to Work With Time Zones in Rails
When dealing with time zones in Rails, there is one key fact to keep in mind:
Rails has configurable time zones, while
Ruby is always in the server's time zone
Thus, using Ruby's time API will give you wrong results for different time zones.
"Without" time zones
You can not actually disable time zones, because their existence is a fact. You can, however, tell Rails the only single time zone you'll need is the server's.
config.time_zone = "Berlin" # Local time zone
config.active_record.default_timezone = :loca...
RSpec Argument Matchers: Expecting non-primitive objects as method invocation arguments
Expecting a primitive value as an argument to a method invocation is easy:
expect(object).to receive(:foo).with('arg1', 'arg2')
This expectation would be met with this call:
object.foo('arg1', 'arg2')
But what if the argument is expected to be an object with a given set of methods? E.g. this class with #first_name
and #last_name
methods:
class Person
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
attr_reader :first_name, :last_name
end
``...
How to use triple quotes inside a Cucumber docstring
Cucumber's docstrings let you add long strings to a step like this:
# foo.feature
Given this text:
"""
First line
Second line
Second Paragraph
"""
# foo_steps.rb
Given /^this text:$/ |docstring|
puts docstring.split
end
You see these neat triple double quotes ("""
). Now what to do when you need your docstring to contain triple double quotes, too?
# Does not work:
Given this text:
"""
Docstrings work like this:
"""
Docstring example
"""
You see?
"""
Update: Official solution
You can escape the inner quotes ...
VCR: An OAuth-compatible request matcher
OAuth requires a set of params to be carried along requests, among which a nonce. Some libraries pass these along as headers, some as query parameters. All fine.
When you're using VCR, the latter case is an issue. By default, requests are matched on method and URI. However, no request URI will equal another when they include a nonce. You won't be able to match these requests with VCR.
Solution
Obviously you need to...
Reading and writing cookies in JavaScript
You can use JavaScript to get or set cookie values on the client.
Using the vanilla JavaScript API
In JavaScript, document.cookie
is an accessor to all cookies on the current site. It looks like a String, but its setter is actually more powerful.
When setting cookies this way, remember to set the path=/
option.
Reading cookies
A result may look like this:
hello=universe; foo=bar
This means that there are 2 cookies: "hello" with value "universe", and "foo" with value "bar...
jQuery promises: done() and then() are not the same
jQuery's deferred objects behave somewhat like standard promises, but not really.
One of many subtle differences is that there are two ways to chain callbacks to an async functions.
The first one is done
, which only exists in jQuery:
$.ajax('/foo').done(function(html) {
console.debug("The server responded with %s", html);
});
There is also then
, which all promise libraries have:
$.ajax('/foo').then(function(html) {
console.debug("The server resp...
Infinitely nested hashes in Javascript (Coffeescript)
The NestedHash
class allows you to read and write hashes of any depth. Examples:
hash = {}
NestedHash.write hash, 'a', 'b', 'c', 'value' # => { a: { b: { c: 'value' } } }
NestedHash.read hash, 'a', 'b', 'c' # => 'value'
NestedHash.read hash, 'a' # => { b: { c: 'value' } }
NestedHash.read hash, 'foo', 'bar' # => undefined
Inspired by victusfate.
Code
class @NestedHash
@read: (objekt, keys...) ->
if objekt and keys.length
@read objekt[keys[0]], keys[1...]...
...
Heads up: RSpec's diffs may not tell the truth
RSpec provides a nice diff when certain matchers fail.
Here is an example where this diff is helpful while comparing two hashes:
{a:1}.should match(a:1, b:2)
Failure/Error: {a:1}.should match(a:1, b:2)
expected {:a=>1} to match {:a=>1, :b=>2}
Diff:
@@ -1,3 +1,2 @@
:a => 1,
-:b => 2,
Unfortunately, this diff is not as clever as it would need to. RSpec's instance_of
matchers will look like errors in the diff (even if they are not), and time objects that differ only in milliseconds won't appear in the ...
Don't open user-supplied links with target="_blank"
This will give the target site full access to your Javascript environment through window.opener
, if the target is on the same domain.
Even if the target site is on another domain, it still has some access and can for example manipulate window.location
to perform a phishing attack.
You may use a rel="noopener"
attribute to avoid this in modern browsers, except IE or Edge.
How to fix routing error when using concerns in Rails up to 3.2.22.1
tl;dr
-
Don't write
resources :people, :concerns => :trashable
-
Write
resources :people do concerns :trashable end
Why
Writing a controller spec I encountered this error:
Failure/Error: get :index
ActionController::RoutingError:
No route matches {:controller=>"people"}
caused by this route definition
resources :people, :concerns => :trashable
which renders strange routes:
trash_person PUT /people/:id/trash(.:format) people#check {:concerns=>:trashable}
...
nginx: How to drop connections for a location
If you want to configure your nginx to drop connections to a specific location
, you can do so by responding with HTTP response code 444.
Status 444 is a non-standard response code that nginx will interpret as "drop connection".
Example:
server {
listen 127.0.0.1;
location /api/ {
return 444;
}
}
An example use case is reverse-proxying with nginx and simulating a route that drops connections.
Rails route namespacing (in different flavors)
TL;DR There are three dimensions you can control when scoping routes: path helpers, URL segments, and controller/view module.
scope module: 'module', path: 'url_prefix', as: 'path_helper_name' do
resources :examples, only: :index
end
as
→ prefixes path helpers: path_helper_name_examples_path
and path_helper_name_examples_url
path
→ prefixes URL segments: /url_prefix/examples
module
→ nests the controller: controller Module::ExamplesController
, found at app/controllers/module/examples_controller.rb with views ...
Testing ActiveRecord callbacks with RSpec
Our preferred way of testing ActiveRecord is to simply create/update/destroy the record and then check if the expected behavior has happened.
We used to bend over backwards to avoid touching the database for this. For this we used a lot of stubbing and tricks like it_should_run_callbacks
.
Today we would rather make a few database queries than have a fragile test full of stubs.
Example
Let's say your User
model creates a first Project
on cr...