In old versions of Rails, you were able to override the ActiveJob queue in a test like this:

describe MyJob do
it 'works' do
ActiveJob::Base.queue_adapter = :delayed_job
expect {
MyJob.perform_later(some_params)
}.to change(Delayed::Job.count).by(1)
end
end

With Rails 5.1, we have the ActiveJob::TestHelper class which you will need to employ in your tests. In order to override the queue a different strategy is needed.

describe MyJob do
def queue_adapter_for_test
ActiveJob::QueueAdapters::DelayedJobAdapter.new
end
it 'works' do
expect {
MyJob.perform_later(some_params)
}.to change(Delayed::Job.count).by(1)
end
end

You will need to add the following to your rspec config or a support file:

RSpec.configure do |config|
config.include(ActiveJob::TestHelper)
end
# you will also need the code below for the test
# to clear out the jobs between test runs
class ActiveJob::QueueAdapters::DelayedJobAdapter
class EnqueuedJobs
def clear
Delayed::Job.where(failed_at:nil).map &:destroy
end
end
class PerformedJobs
def clear
Delayed::Job.where.not(failed_at:nil).map &:destroy
end
end
def enqueued_jobs
EnqueuedJobs.new
end
def performed_jobs
PerformedJobs.new
end
end

If a link or button initiates a request that takes a long time to respond then
the user (being a user) might click the link or button again. Depending on the
code implemented on the server this could put the application into a bad state.

Rails has a handy feature that will disable a link or button after the user has clicked it, disable_with:

When you set values into the ActiveRecord object the previous values are still available with changes, but when you save, however you save, those changes are wiped out. You can access what those values were before saving with previous_changes.

You can pass an array of hashes to Thing.create! in ActiveRecord. If one of those records is invalid, then an ActiveRecord::RecordInvalid error is thrown. You might need to know which record threw the error, in which case you can get the record from the error with record_invalid_error.record

By default, the BetterErrors gem only works for localhost. If you’re using ngrok to access your rails server and you want to have access to BetterErrors, you’ll need to whitelist the IP of the machine that ngrok is running on.

Add the following to development.rb:

BetterErrors::Middleware.allow_ip!(NGROK_MACHINE_PUBLIC_IP)
# - or -
# Use an IP finding service to grab your public IP each time you start the server:
# (ipecho.net, api.ipify.org, etc.)
BetterErrors::Middleware.allow_ip!(open('http://api.ipify.org').read)

Ruby on Rails gives us a nice warning in development when we haven’t run a pending database migration. But what if we’re iterating on a migration, and the results can best be viewed in the browser? We might want to temporarily disable this warning.

If the migration fails, we’ll get an error pointing to the specific problematic HEREDOC, instead of essentially ‘the entire statement is invalid’. You then put a debugger between any HEREDOC to iterate on the issue.

I’ve recently run into a situation where I needed to apply a group statement to an ActiveRecord scope if a group statement had already been applied. In this case we need to examine the current scope to see if in fact a group statement has already been applied. ActiveRecord::Relation fortunately has a group_values method that returns an array of all the columns that the query has been grouped by as symbols.

When running tests via RSpec in Rails 5.1 with Webpack support (via the built-in webpacker gem) you need to have Webpack compile your front-end assets before running your tests. To achieve that in RSpec add the following to your rails_helper.rb:

Rails’ ActiveRecord can easily support 90% of the querying we do against the
tables in our database. However, there is the occasional exceptional query
that is more easily written in SQL — perhaps that query cannot even be
written with the ActiveRecord DSL. For these instances, we need a way to
generate and execute SQL safely. The
sanitize_sql_array
method is invaluable for this.

First, let’s get a connection and some variables that we can use downstream
in our query.

Now, we are ready to safely generate our SQL query as a string. We have to
use send because it is not publicly available. Generally, this is frowned
upon, but in my opinion it is worth breaking the private interface to ensure
our SQL is sanitized.

When basing logic on the current time its helpful for testing to have a stable
time. A time that does not change. Rails has a module ActiveSupport::Testing::TimeHelpers that was added in Rails 4.2 to provide methods that manipulate the time during testing.

Generally, we think about expectations in RSpec one at a time. If the first expectation fails, then don’t go any further. Expectations in RSpec however are chainable, meaning, I can attach one expectation to another for the same subject and then know about the failures or successes for both expections, that looks like this.

You have a column on one of your database tables with a default value. You’d
like to remove the default value. Removing the default is the same as
setting it to nil. You can do this with the ActiveRecord DSL using the
change_column_default method.

I’ve been working on some Rails code that brings in ActiveRecord models from multiple gems. Often these models have default scopes, that bane of a legacy Rails codebase, and figuring that out requires source diving one or more gems. Today I hacked my way to a faster solution: just read the SQL Rails generates.

Here’s a post without a default scope, and then one with a default scope:

The webserver for my current project is puma, which is a multi-threaded ruby server. This multithreaded nature makes it hard to but a pry statement in and break in specific places. There are multiple threads that will listen to the input the user provides at the REPL.

Using webrick would allow us to debug and step through our code but changing the applications configuration in order to enable that seems unreasonable.

Fortunately, rails provides an easy way to change servers at the command line.

> rails server webrick

Just pass the name of the server you would rather use as a command line argument.

When typing rails server --help you’ll see this option available on the first line:

If you have a symbol and need to convert it to a constant, perhaps because
of some metaprogramming induced by a polymorphic solution, then you may
start off on an approach like the following. In fact, I’ve seen a number of
StackOverflow solutions like this.

:module.to_s.capitalize.constantize
#=> Module

That is great for one-word constant names, but what about multi-word
constants like OpenStruct. This approach will not work for the symbol
:open_struct. We need a more general solution.

The key is to ditch #capitalize and instead use another ActiveSupport
method,#classify`.
ruby
:open_struct.to_s.classify.constantize
#=> OpenStruct

Many Rails apps need to delegate work to jobs that can be performed at a
later time. Both unit and integration testing can benefit from asserting
about the jobs that get enqueued as part of certain methods and workflows.
Rails provides a handy helper method for checking out the set of enqueued
jobs at any given time.

The
enqueued_jobs
method will provide a store of all the currently enqueued jobs.

It provides a number of pieces of information about each job. One way to
use the information is like so:

describe '#do_thing' do
it 'enqueues a job to do a thing later' do
Processor.do_thing(arg1, arg2)
expect(enqueued_jobs.map { |job| job[:job] }).to match_array([
LongProcessJob,
SendEmailsJob
])
end
end

To use this in your Rails project, just enable the adapter in your test
configuration file:

I’ve known about the Rails Runner command for a long time - all it does is execute some Ruby in the context of your app. I’ve rarely used it, but had a situation today where I wanted to. I couldn’t quite remember how it worked, so I ran it without any arguments and discovered something new (to me, anyway):

When using the host: configuration option in the database.yml set to localhost or 127.0.0.1, I would need to add an entry to PostgreSQL’s pg_hba.conf file to allow my ip address access. But, if you give the host: option the directory of your PostgreSQL sockets, rails will be able to use the socket, without needing to add an entry to the PostgreSQL configuration file.

Enum in PostgreSQL work as a new type with restricted values and if you need to guarantee data integrity there’s no best way to do that than in your database. Here is how we create a new enum in PostgreSQL and use in a new column:

Today I Learned is an open-source project by
Hashrocket
that exists to catalogue the sharing & accumulation of knowledge
as it happens day-to-day. Posts have a 200-word limit, and
posting is open to any Rocketeer as well as selected friends of
Hashrocket. We hope you enjoy learning along with us.