3609 cards
View
Linked contentRepeats

Debugging AJAX requests with better_errors

better_errors is an awesome gem for enhanced error pages in development, featuring a live-REPL for some light debugging.

To debug the exception you got on an AJAX-Request, visit /__better_errors on your app's root path (e.g. http://localhost:3000/__better_errors). It shows the error page for the last exception that occurred, even when it has been triggered by an AJAX request.

Upgrade guide for moving a Rails app from Webpack 3 to Webpack 4

Webpacker is Rails' way of integrating Webpack, and version 4 has been released just a few days ago, allowing us to use Webpack 4.

I successfully upgraded an existing real-world Webpack 3 application. Below are notes on everything that I encountered.
Note that we prefer not using the Rails asset pipeline at all and serving all assets through Webpack for the sake of consistency.

Preparations

  • Remove version locks in Gemfile for webpacker
  • Remove version locks in package.json for webpack and webpack-dev-server
  • Install by ca…
Repeats

Running external commands with Open3

There are various ways to run external commands from within Ruby, but the most powerful ones are Open3.capture3 and Open3.popen3. Since those can do almost everything you would possibly need in a clean way, I prefer to simply always use them.

Behind the scenes, Open3 actually just uses Ruby's spawn command, but gives you a much better API.

Open3.capture3

Basic usage is

```ruby
require 'open3'

stdout_str, error_str, status = Open3.capture3('/some/binary', 'with', 'some', 'args')
if status.success?…

Repeats

Guide to localizing a Rails application

Localizing a non-trivial application can be a huge undertaking. This card will give you an overview over the many components that are affected.

When you are asked to give an estimate for the effort involved, go through the list below and check which points are covered by your requirements. Work with a developer who has done a full-app localization before and assign an hour estimate to each of these points.

Static text

  • Static strings and template text in app must be translated: Screens, mailer templates, PDF templates, helpe…
Repeats

RSpec: How to aggregate failures

RSpec >= 3.3 added aggregate_failures, which allows multiple failures in an example and list them all, rather than aborting on the first failure.

This can be used:

  • In the global configuration
  • With the tag :aggregate_failures (our preferred option in case every expectations should be aggregated)
  • With the method aggregate_failures

Below is an example, which shows why aggregating failures are useful.

Example

```RUBY
aggregate_failures do
firs…

Rails: How to get URL params without routing parameters (or vice versa)

Rails' params hash contains any request parameters (URL parameters or request payload) as well as routing parameters like :controller, :action, or :id.

To access only URL parameters, use request.query_parameters. Routing params are available through request.path_parameters.

```ruby
# On /users?query=Bob&page=2

request.params
=> {"page"=>"2", "query"=>"Bob", "controller"=>"users", "action"=>"index"}

request.query_parameters
=> {"page"=>"2", "query"=>"Bob"}

request.path_parameters
=> {:controller=>"users", :action=>"i…

Repeats

We now have our own memoization gem "Memoized"

We forked trusty memoizer to make two changes:

  1. Memoized methods now preserve their arity. Previously all memoized methods had an arity of -1.
  2. Memoized methods are now faster at runtime. This will only be noticable if you call a memoized methods many times in the same request.

We published our fork as a new gem named memoized.

memoized is API-compatible to memoizer, you just need to include Memoized instead of `M…

Repeats

Getter and setter functions for Javascript properties

Javascript objects can have getter and setter functions that are called when a property is read from or written to.

For example, if you'd like an object that has a virtual person.fullName attribute that dynamically composes person.firstName and person.lastName:

```
var person = {

firstName: 'Guybrush',

lastName: 'Threepwood',

get fullName() {
return this.firstName + " " + this.lastName;
},

set fullName(name) {
var parts = name.split(" ");
this.firstName = parts[0];
this.lastName = parts[1];
}

};
```…

Micro clearfix mixin for Sass

Clearfix is a hack to clear floating elements without additional HTML markup.

If you only need to support IE8 and above, a great clearfix with few side effects is:

=clearfix
  &:after
    content: ""
    display: block
    clear: both

This is a Sass mixin.

Issues clearing with display: table

You will find many clearfix solutions that clear with display: table instead:

=clearfix
  &:after
    content: ""
    display: table
    clear: both

The problem with th…

Repeats

Carrierwave: always limit images to a reasonable size

Today's cameras create huge images, some beyond 50MB. Unless you need to offer this large files, you should always shrink uploaded files to a reasonable resolution.

class ImageUploader < CarrierWave::Uploader::Base
  
  process resize_to_limit: [3000, 3000]
  
  # ...

end
Repeats

Carrierwave processing facts

  1. Class-level process definitions are only applied to the original file
  2. Versions are generated based on the processed original file
  3. Callbacks (before/after) are applied to original file and each version by itself
  4. Under the hood, a version is an instance of the uploader class that has no versions
  5. Version uploader and original uploader can be distinguished by checking #version_name: version uploaders return the version name, whereas the original uploader instance returns nil
  6. Version instances do not have a re…
Repeats

Carrierwave reminder: always call model.save! after uploader.recreate_versions!

If your Carrierwave uploader dynamically generates the filename (e.g. by incorporating a user's name), you must call model.save! after recreating versions, because uploader.recreate_versions! does not update the model with the stored filename.

Repeats

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:

```text
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/

Linked contentRepeats

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 |
+—-+—–…

Repeats

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 mapping …

Repeats

Simple database lock for MySQL

Note: For PostgreSQL you should use an alternative that doesn't require a database table. For MySQL we still recommend the solution in this card.


If you need to synchronize multiple rails processes, you need some shared resource that can be used as a mutex. One option is to simply use your existing (MySQL) database.

The attached code provides a database-based mutex for MySQL. You use it by simply calling

Lock....
Linked content

Copy to clipboard without flash (clipboard.js)

We used zeroclipboard.js in some of our projects but now we switched to clipboard.js because it does not rely on flash. Flash support of the major browsers has ended.

Some more advantages of clipboard.js:

  • it consists only of a single javascript file, so it does not trigger additional requests with rails
  • it automagically provides user feedback by selecting the text it has copied
  • it provides callbacks for success and error which make it easier to add custom behaviour after copying to the clipboar…
This website uses cookies to improve usability and analyze traffic.
Accept or learn more