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
How to use git fixup
Using git fixup helps you to speed up appending changes further back in the git history of your feature branch.
Example:
git commit --fixup aabbcc # Create a commit with the message "fixup! Commit message of aabbcc"
git rebase -i --autosquash master
It would be nice if you could use this feature without the -i
flag, but until now it seems not to be possible. Read more about our recommended git workflow for feature branches.
Also have a look at [git shortcut to use git fixup](https://makandracards.com/makand...
How to evaluate CSS media queries in JavaScript
To make CSS rules dependent on the screen size, we use media queries:
@media (max-width: 500px) {
// rules for screen widths of 500px or smaller
}
Browsers will automatically enable and disable the conditional rules as the screen width changes.
To detect responsive breakpoints from JavaScript, you may use the global matchMedia()
function. It is supported in all brow...
Rubygems: Installing the last version of rubygems that has no rubyforge_project deprecation warning
You can install rubygems 3.0.8
(released on February 18, 2020) to keep all the Gem::Specification#rubyforge_project
deprecation warnings away from your development log. With Rubygems >= 3.1
this deprecation warning was introduced. While maintaining older projects this could get quite annoying and the fix below might okey, for newer projects the right ways is to upgrade the gems.
gem update --system 3.0.8
Example message:
NOTE: Gem::Specification#rubyforge_project= is deprecated with no replacement. It will be removed o...
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...
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!
-
Assoc For Hashes
- `Hash#ass...
ActiveRecord: Named bindings in conditions
In Active Record you can use named bindings in where
-conditions. This helps you to make your code more readable and reduces repetitions in the binding list.
Example without named bindings
User.where(
'name = ? OR email = ?',
params[:query],
params[:query]
)
Example with named bindings
User.where(
'name = :query OR email = :query',
query: params[:query]
)
Rails: Concurrent requests in development and tests
With puma
you can have concurrent requests. There are two concepts on how Puma can handle two incoming requests: Workers and Threads.
Workers
Puma can have multiple workers. Each worker is a process fork from puma and therefore a very heavy instance and can have multiple threads, that handle the incoming requests.
Example: A Puma server with 2 workers
and 1 thread
each can handle 2 request in parallel
. A third request has to wait until the thread of one of the workers is free.
Threads
Rails is thread-safe since version 4 (n...
Test-Driven Development with integration and unit tests: a pragmatic approach
Test-Driven Development (TDD) in its most dogmatic form (red-green-refactor in micro-iterations) can be tedious. It does not have to be this way! This guide shows a pragmatic approach with integration and unit tests, that works in practice and improves on productivity.
Advantages
- No added effort: tests need to be written anyway.
- Test heads serve as todo lists. You'll always know what is finished and what is left to do.
- Big tasks are broken down into smaller tasks that can be processed one by one.
- You will not forget a test.
- You...
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.
-
Add it to your Gemfile and bundle
group :test do gem 'simplecov', require: false end
-
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...
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...
How to: Throttle CPU in Google Chrome
Chrome allows you to throttle the Network and the CPU. Both settings are useful to measure the performance of you application and reproduce performance issues (Example Debugging frontend performance issues with Chrome DevTools).
You find the settings in: DevTools
> Performance
> Capture Settings (Gear icon in the right corner)
> `CPU: No...
Video transcoding: Web and native playback overview (April 2020)
Intro
Embedding videos on a website is very easy, add a <video>
tag to your source code and it just works. Most of the time.
The thing is: Both the operating system and Browser of your client must support the container and codecs of your video. To ensure playback on every device, you have to transcode your videos to one or more versions of which they are supported by every device out there.
In this card, I'll explore the available audio and video standards we have right now. The goal is to built a pipeline that...
How to write good code comments
Code comments allow for adding human readable text right next to the code: notes for other developers, and for your future self. You can imagine comments as post-its (or sometimes multi-sheet letters ...) on real-world objects like cupboards, light switches etc.
As always, with power comes responsibility. Code comments can go wrong in many ways: they may become outdated, silently move away from the code they're referring to, restate the obvious, or just clutter files.
Good Comments
Here are some simple rules to keep your comments help...
Capybara: How to find a hidden field by its label
To find an input with the type hidden, you need to specify the type hidden
:
find_field('Some label', type: :hidden)
Otherwise you will see an exception :
find_field('Some label')
# => Capybara::ElementNotFound: Unable to find field "Some label" that is not disabled`.
Note: Usually you don't need to check the input of hidden fields in an integration test. But e.g. waiting for a datepicker library to write the expected value to this field before continuing the test, which prevents flaky tests, is a valid use case.
Quick HTML testing with RubyMine
If you need to test some HTML, e.g. an embed code, you can use RubyMine's "scratch files":
- File > New Scratch File (or
Ctrl + Shift + Alt + Ins
) - Select "HTML" as file type
- Write or paste the HTML
- Move your mouse to the upper right corner of the scratch file editor. Pick a browser to instantly open your file.
ActiveRecord: Specifying conditions on an associated table
We can use ActiveRecord's where
to add conditions to a relation. But sometimes our condition is not on the model itself, but on an associated model. This card explains multiple ways to express this condition using ActiveRecord's query interface (without writing SQL).
As an example we will use a User
that has many Post
s:
class User < ApplicationRecord
has_many :posts
scope :active, -> { tra...
Letting a DOM element fade into transparency
You can use the CSS property mask-image
to define an "alpha channel" for an element.
E.g. to let an element start at full opacity at the top and gradually fade into transparency at the bottom:
.box {
-webkit-mask-image: linear-gradient(to bottom, black 0%, transparent 100%);
mask-image: linear-gradient(to bottom, black 0%, transparent 100%);
}
- A fully opaque black pixel will render the masked pixel fully opaque
- A fully transparent black pixel will render the ...
Ruby: How to fetch a remote host's TLS certificate
TLS/SSL certificates are often used for HTTPS traffic. Occasionally a service may also use their TLS certificate to support public-key encrypting data (e.g. when it is part of the URI and visible to the user, but contains sensitive information).
Here is how to easily fetch such certificate data.
certificate = Net::HTTP.start('example.com', 443, use_ssl: true) { |http| http.peer_cert }
# => #<OpenSSL::X509::Certificate: subject=#<OpenSSL::X509::Name CN=www.example.org,...>
certificate.public_key
# => #<OpenSSL::PKey::RSA:0x...
How to write modular code
Or: How to avoid and refactor spaghetti code
Please note that I tried to keep the examples small. The effects of the methods in this card are of course much more significant with real / more complex code.
What are the benefits of more modular code?
Code is written once but read often (by your future self and other developers who have to understand it in order to make changes for example). With more modular code you reduce the scope of what has to be understood in order to change something. Also, naming things gives you the opportunity t...
How to make a cucumber test work with multiple browser sessions
Imagine you want to write a cucumber test for a user-to-user chat. To do this, you need the test to work with several browser sessions, logged in as separate users, at the same time.
Luckily, Capybara makes this relatively easy:
Scenario:
Scenario: Alice and Bob can chat
Given Alice, Bob, and a chat session
When I am signed in as "Alice"
And I go to the chat
And I am signed in as "Bob" [session: bob]
And I go to the chat [session: bob]
And I send the message "Hello, this is Alice!"
Then I should see "Hello, this ...
Rails: Rest API post-mortem analysis
This is a personal post-mortem analysis of a project that was mainly build to provide a REST API to mobile clients.
For the API backend we used the following components:
- Active Model Serializer (AMS) to serializer our Active Record models to JSON.
- JSON Schema to test the responses of our server.
- SwaggerUI to document the API.
It worked
The concept worked really good. Here are two points that were extraordinary compared to normal Rails project with many UI components:
- Having a Rails application, that has no UI components (only...
How to: Validate dynamic attributes / JSON in ActiveRecord
PostgreSQL and ActiveRecord have a good support for storing dynamic attributes (hashes) in columns of type JSONB
. But sometimes you are missing some kind of validation or lookup possibility (with plain attributes you can use Active Record's built-in validations and have your schema.rb
).
One approach about being more strict with dynamic attributes is to use JSON Schema validations. Here is an example, where a project has the dynamic attributes analytic_stats
, that we can use to store analytics from an external measurement tool.
- A g...
Structuring Rails applications: the Modular Monorepo Monolith
Root Insurance runs their application as a monolithic Rails application – but they've modularized it inside its repository. Here is their approach in summary:
Strategy
- Keep all code in a single repository (monorepo)
- Have a Rails Engine for each logical component instead of writing a single big Rails Application
- Build database-independent components as gems
- Thus: gems/ and engines/ directories instead of app/
- Define a dependency graph of components. It should have few edges.
- Gems and Engines can be extracted easier once nece...