View
Linked contentRepeats

count vs. size on ActiveRecord associations

TLDR

  • When counting records in an association, you should use #size in most cases.
  • It will not work if the parent record has never been saved. Also there are finer distinctions between #size and #count. See below.

count

  • Always makes a COUNT(*) query if a counter cache is not set up.
  • If a counter cache is set up on the association, #count will return that cached value instead of executing a new query.

size, if the association has already been loaded

  • Counts elements in the already loaded array.
  • Does not ...
Repeats

How Ruby method lookup works

When you call a method on an object, Ruby looks for the implementation of that method. It looks in the following places and uses the first implementation it finds:

  1. Methods from the object's singleton class (an unnamed class that only exists for that object)
  2. Methods from prepended modules (Ruby 2.0+ feature)
  3. Methods from the object's class
  4. Methods from included modules
  5. Methods from the class hierarchy (superclass and its ancestors)

Example

Let's say we h...

Rspec: Expecting a Rake task to be called

This seems to be obvious, but you can expect Rake tasks to be called in RSpec.

it 'deletes all Users' do
   FactroyBot.create(:user)
   expect(Rake::Task['notify:critical_operation']).to receive(:invoke)
   
   expect { described_class.clean }.to change(User, :count).from(1).to(0) 
end

Note: Try to avoid logic in rake tasks and prefer to just call classes in them.

Example:

desc 'Some task'
task :some_task do
  SomeClass.new.run
end
Repeats

BigDecimal arithmetic in Ruby

Ruby comes with a class BigDecimal which you can use for arbitrary precision arithmetic. You should use BigDecimal instead of Float whenever you care about rounding errors, e.g. whenever you are dealing with money.

You should remember these two rules when working with BigDecimal values:

  • When you add or multiply a BigDecimal with another BigDecimal, the ...

Rails: When defining scopes with class methods, don't use `self`

Sometimes it is useful to define a named scope by implementing a static method with the scope's name on the scoped class. For instance, when a method should decide which existing scope should be the next link in the scope chain. Take this class for example:

class Meal < ActiveRecord::Base

  named_scope :for_date, lambda { |date| :conditions => { :date => date }}
  named_scope :with_meat, :conditions => { :meat => true }
  named_scope :without_meat, :conditions => { :meat => false }

  def self.suitable_for(user)
   ...
Repeats

How to grep through the DOM using the Capybara API

When your Cucumber feature needs to browse the page HTML, and you are not sure how to express your query as a clever CSS or XPath expression, there is another way: You can use all and find to grep through the DOM and then perform your search in plain Ruby.

Here is an example for this technique:

Then /^I should see an image with the filename...
Repeats

Deterministic ordering of records by created_at timestamp

Creating records in specs can be so fast that two records created instantly after one another might have the same created_at timestamp (especially since those timestamps don't have an indefinitely high resolution). When ordering lists by timestamps, you should therefore always include a final order condition using the primary key of the table.

class Photo < ActiveRecord::Base
  scope :by_date, -> { order('created_at DESC, id DESC') }
end

Photo.by_date

Remember to include the id field in the database index.

Repeats

Ruby / Rails: clone vs. dup vs. deep_dup

Ruby and Rails have several methods for creating a new object that looks like another: clone, dup, deep_dup. When using them you should be aware of their differences so that you can select the method you really need.

clone

  • Shallow copy: references to other objects/values are copied (instead of cloning those objects/values)
  • Clones the object and all its "special object attributes" like frozen, tainted and modules that the object has been extended with
  • [Ruby 2.6 documentation for clone](https://devdocs.io/ruby~2.6/obj...

Git: How to add changes matching a regular expression

When you have many changes, and you want to spread them across different commits, here is a way to stage all changes matching a given regular expression for a single commit.

Example

Consider the following git diff output.

diff --git a/file1.rb b/file1.rb
index 806ca88..36d536b 100644
--- a/file1.rb
+++ b/file1.rb
@@ -1,7 +1,5 @@
-# Here is a useless comment.
-# It will be removed.
 class File1
-  def foo
+  def bar
     # ...
   end
 end
diff --git a/file2.rb b/file2.rb
index 550e1c6..600f4e3 100644
--- a/file2.rb
+++ b/file2...
Repeats

PSA: "index: true" in Rails migrations does not work as you'd expect

Several Rails migration methods accept index: true as an option to create an index. In some cases (like #add_column), this option is silently discarded. Know what you are doing, or use #add_index instead.

Example

Consider the following migration.

class CreateExamples < ActiveRecord::Migration
  def change
    create_table :examples do |t|
      t.references :category, index: true
      t.boolean :positive, index: true
      t.integer :number_of_participants, index: true
    end

    add_referen...
Linked contentRepeats

Ruby: A small summary of what return, break and next means for blocks

Summary

  • Use return to return from a method. return accepts a value that will be the return value of the method call.
  • Use break to quit from a block and from the method that yielded to the block. break accepts a value that supplies the result of the expression it is “breaking” out of.
  • Use next to skip the rest of the current iteration. next accepts an argument that will be the result of that block iteration.

The following method will serve as an example in the details below:

def example
  puts yield
  puts 'don...
Linked content

Five years of "Today I Learned" from Josh Branchaud

The linked GitHub repository is a bit like our "dev" cards deck, but groomed from a single person (Josh Branchaud). It includes an extensive list of over 900 TILs on many topics that might be interesting for most of us. (e.g. Ruby, Rails, Git, Unix..)

Ruby

Here is an excerpt of all the Ruby TILs that were new to me. I encourage you to take your time to skim over the original list as well!

How to use Simplecov to find untested code in a Rails project with RSpec and Cucumber

Simplecov is a code coverage tool. This helps you to find out which parts of your application are not tested.

Integrating this in a rails project with rspec, cucumber and parallel_tests is easy.

  1. Add it to your Gemfile and bundle

    group :test do
      gem 'simplecov', require: false
    end
    
  2. Add a .simplecov file in your project root:

    SimpleCov.start 'rails' do
      # any custom configs like groups and filters can be here at a central place
      enable_cov...
    

Using #deep_dup for copying whole hashes and array

"Everything in Ruby is an object". This is also true for nested hashes and arrays. If you copy a hash with #clone or #dup and you modify the copy, you will run into the following behavior:

original_hash = { foo: { bar: 'original value' } }
copied_hash = original_hash.dup
copied_hash[:foo][:bar] = 'changed value'

original_hash # => { foo: { bar: "changed value" }

This is, because { bar: 'baz' } is an object, which is referenced in :foo. The copy of original_hash still holds the reference to the same object, so alterin...

Repeats

Async control flow in JavaScript: Promises, Microtasks, async/await

Slides for Henning's talk on Sep 21st 2017.


Understanding sync vs. async control flow

Talking to synchronous (or "blocking") API

print('script start')
html = get('/foo')
print(html)
print('script end')

Script outputs 'script start', (long delay), '<html>...</html>', 'script end'.

Talking to asynchronous (or "evented") API

print('script start')
get('foo', done: function(html) {
  print(html)
})
print('script end')

Script outputs 'script start', `'...

Linked contentRepeats

How to use Parallel to speed up building the same html partial multiple times (for different data)

The parallel-gem is quite easy to use and can speed up rendering time if you want to render the same partial multiple times (e.g. for rendering long lists of things).
If your parallelized code talks to the database, you should ensure not to leak database connections.

Consider you want to render a list of groups with their members as json. You can use a partial for the rendering of group members, b...

Repeats

Bundler in deploy mode shares gems between patch-level Ruby versions

A recent patch level Ruby update caused troubles to some of us as applications started to complain about incompatible gem versions. I'll try to explain how the faulty state most likely is achieved and how to fix it.

Theory

When you deploy a new Ruby version with capistrano-opscomplete, it will take care of a few things:

  • The new Ruby version is installed
  • The Bundler version stated in the Gemfil...
Repeats

How to use a local gem in your Gemfile

You can use local copies of gems in your Gemfile like this:

gem 'spreewald', :path => '~/gems/spreewald'

As soon as you have bundled your project with the local copy of the gem, all code changes in the copy will be available on your project. So you can for example set a debugger or add console output in the gem and use it from your project.
If you checked out the gem with your versioning tool, you can easily reset your changes afterwards or make a pull request for the gem if you improved it.

Don't commit a Gemfile with local pat...

This website uses short-lived cookies to improve usability.
Accept or learn more