Stay safe while using html_safe in Rails

Whether you’re a junior dev, product designer or senior level software engineer, it’s easy to fall on your face when using `html_safe` in Rails.

The thing about this method is: it’s terribly named. I mean really, it’s a horrible name. When you call a method on an object which transforms the original object, the method name should describe the transformation which is about to happen.

The html_safe method makes you think that the transformation you’re doing to the string is actually going to be safe. It can be safe. It can be very unsafe, too.

I’m going to go on record stating that we should call this method something more sane, like: html_beware. Why beware? Because as a code committer, you should be very aware of the string that you’re calling this method on. If the string has input that is user controlled of any kind, you should certainly not call “html_safe” on it. This method should make you think twice about what you’re doing, and by calling it safe, it certainly doesn’t make you think at all.

Let’s go over some code examples and explain exactly how html_safe works, and why it’s unsafe in certain contexts.

Now that we’ve looked at how to use html_safe properly, let’s look an example of how we at Reverb fell on our face. Not too long ago we shipped some code which allowed user-controlled input to be inserted into the DOM. This resulted in a stored XSS attack, which you can see here:


Here’s the bad code:

And here’s how we fixed it:

While there’s nothing inherently harmful about a javascript alert besides a minor annoyance, this attack vector illustrates that a user can inject any type of html tags into the DOM, including script tags. This could be especially disastrous if this vector was used to steal session cookies or login information. Thankfully we caught this error ourselves and it was not exploited.

Keep this in mind while you’re building your next awesome project and know exactly where the string comes from that you’re adding html_safe to. And even if you’re not building something new and have inherited an older codebase, consider grep’ing your codebase looking for string interpolations combined with html_safe:


So while nothing is perfect, including this method name, in conclusion we have learned that it pays to be careful about what type of user data you’re working with. Here at Reverb, we believe in owning mistakes and fully understanding why they happened.

That being said, we also believe that nothing is perfect and mistakes will happen. If you believe you’ve found a bug on our platform, please securely and responsibly disclose it to us at We will work with you to confirm, close and patch the hole. We do offer bounty for critical bugs and swag for bugs with a lower risk profile.

Until next time, stay html_safe!



Rails and Ember Side by Side

This is not a blog post about embedding Ember CLI in your Rails app. Instead, it’s a post about how to get the two to live in harmony next to each other by separately deploying Rails and Ember, but making them feel like one app.

Our first attempt

Last week we launched our first foray into Ember – an admin facing utility that helps us organize, curate, and police content on our site. Our admin capability is developed primarily in Rails, but we wanted one page to be the Ember app.

Our first instinct was to look at ways to integrate our ember app directly into the Rails admin so it can live “inside” the page. We tried ember-cli-rails, a project that promised a lot of magic.

With a few lines of configuration, we could get Rails to compile our ember app and ship it along with our asset pipeline. Great! Ship it! But…disaster struck.

Problems with ember-cli-rails

1. It forces an ember dependency on all our Rails developers. They now need to know about npm, bower, and more in order to get their Rails app to even boot. This is sadness.

2. It bloats our Rails codebase by introducing another big hunk of code into it (an entire ember app).

3. The worst part: it turned our relatively snappy 2 minute Jenkins deploy into an 8 minute deploy (!). The issue appeared to be in the asset pipeline. Something was causing a drastic slowdown in compilation, right around the time of dealing with ember’s vendor assets (things like ember-data). Whether this is a bug in ember-cli-rails or simply the asset pipeline being the slow beast that it is, still remains to be seen.

We could probably get over #1 and #2 after some initial pain, but a 4 fold increase in deploy times was an unacceptable tradeoff for having Ember part of our Rails app.


When we ran ember-cli’s preferred compilation method (ember build), the build time was just fine. In fact on the same Jenkins box that took 4 minutes to concatenate assets in the Rails asset pipeline, the ember build took less than 20 seconds!

So we decided we were going to separate the two apps. But we still wanted it to feel like one app. Let’s get to work.

1. The Ember app should share a session with the Rails app

Because we didn’t want to have to deal with fancy things like OAuth or token based authentication against our API, we could simply share our session cookies with the Rails app if we ran on the same domain. So we decided we would serve our app on the same domain – If it was at the same domain, it would share cookies and the Rails app would see it as “logged in”.

So the first thing we need to do is get it into a public directory on our existing web servers. We’ll talk about this in the deploy section below.

2. The Ember app should be environment aware so it can point to different backends

When you build your ember app, you can pass in an environment with “ember build –environment production”. To make our app aware of different endpoints, we added this into its config/environment.js:

3. What about CSRF?

Rails comes with some CSRF protection out of the box. The way it normally works is Rails will return your CSRF token as a tag in the body of the html you request. You would then submit forms back to Rails with that CSRF token. Ember does not pull html from Rails and all it’s requests are asynchronous. How to fix?

1. Make Rails return the CSRF token in a cookie for Ember to read

2. Make Ember pull that cookie and set it on every out going request


4. How to deploy?

Ok, now the fun part. What is an ember app at it’s core? It’s just static html and javascript. We know how to deploy that, we just put it in the public dir of our Rails app right? Ok, so all we need to do is:

1. compile the ember app (npm/bower/ember build)
2. upload it to an s3 bucket
3. tell all our servers to download it

This is not particularly polished, but you get the idea:

5. Bonus: make it feel like part of the app

I’ll describe this one instead of giving you code. We wanted the ember app to have the same “layout” as the rest of our admin interface. Ajax to the rescue: just make a controller to render a partial and have ember pull it using jQuery.load into a div of your choice. Style it similar to your Rails app, and the illusion is complete.

One thing to note is that the Ember app is currently fully self contained in terms of assets. So in order to mimic the look and feel of our admin (which was based on Bootstrap), we had to pull Bootstrap into the Ember project. In the future, we may want to pull assets from Rails to avoid duplicating CSS. We have some ideas on how to do this using a controller to serve up the asset paths via an API but we’ll blog about that once we have a working prototype.

Yan Pritzker – @skwp

Organizing your Grape API endpoints

The following is taken from a Reverb Architecture Decision Document


Grape endpoints (classes inheriting from Grape::API) are basically equivalent to Rails controllers. As such, they can contain many unrelated methods (index/show/delete/create). As they grow, the code becomes harder to maintain because helper methods usually only apply to one of the endpoints, similar to Rails controller private methods.


Grape endpoints should be delivered as independent classes for each action. For example, instead of:

# app/api/reverb/api/my_resource.rb
class MyResource < Grape::API
  get '/something' do

  post '/something' do

Create separate classes (and files) for each verb:

# app/api/reverb/api/my_resource/index.rb
module MyResource
  class Index < Grape::API
    get '/something' do

# app/api/reverb/api/my_resource/create.rb
module MyResource
  class Create < Grape::API
    post '/something' do

This allows us to define helper methods in each endpoint specific to that endpoint. Additionally, prefer creating model classes to one-off helper methods for endpoints when appropriate.

Positive Programming with Junior Devs

Hello, World. I’m Tam, and I am writing to you fresh from my third week on the engineering team at Reverb. I also just crossed into my second year as a professional programmer. Milestones! Growth! Vim!

I think of myself as an experienced novice. Thanks to my origins in a programming bootcamp, I know a lot of other people in my boat. It’s becoming more of a ship, actually — a sizable fleet, and we are crash-landing at your company in numbers never-before-seen! Prepare thyself accordingly:

The first few days I showed up, different team members took me out to lunch. They all already knew my name. This made me feel welcome, which goes a long way in those strange first days.

Within my first week, I received a document: “Expectations of Junior Developers.” This inspired my trust and confidence: they have invested time and thought into how they can smoothly onboard me. It also gave me a roadmap to judge my own progress. Building self-sufficiency feels good; provide people with tools that they may do so.

We share vim configurations here, and one of our key mappings is [,][t]. It maps to fuzzy file searching. Now, I have been typing since I was 10. I can type really quickly! But every comma I’ve ever typed has been followed by a whitespace.  Do you have any idea how many times I screwed up typing comma-t while my pair waited? We likely spent an entire collective day waiting on my fumbling fingers. I couldn’t even remember the keystrokes at first. Herein lies an opportunity for immense frustration on all sides. I urge you, experienced team member, to have patience. You are in a leadership position. If you get too frustrated too quickly, your junior stands no chance. Be patient: they are trying really hard, and it is exhausting.

We can teach you things
This week I unintentionally taught our CTO that you can split a git hunk. That was really exciting! There is a lot to know about software development. If you stay receptive, we may be able to teach you something in return.

The bottom line is, you have to be excited that we’re here. Every junior I know is thrilled, nervous, and doing everything they can to stay afloat. If you’ve screened them, you know they have potential. Try not to get in the way!

To the juniors of the world, don’t be afraid. You can do this. Find a supportive environment, keep friends close, and … Go!


Making inheritance less evil

Sometimes you come up against a problem that just seems to want to be solved with inheritance. In a lot of cases, you can get away from that approach by flipping the problem upside down and injecting dependencies. Sandi Metz’s new Railsconf talk Nothing is something does a really great job talking about this concept in a really fun way.

But if you have decided that inheritance is truly the right approach, here is something you can do to make your life just a little easier. It’s called DelegateClass.

Let’s quickly summarize a few reasons why inheritance is evil, especially in Ruby:
1. You inherit the entire API of your superclass including any future additions. As the superclass grows, so do the subclasses, making the system more tightly coupled as more users appear for your ever-growing API.
2. You can access the private methods of your superclass (yes, really). This means that refactorings of the superclass can easily break subclasses.
3. You can access the private instance variables of your superclass (yes, really). If you set what you think are your own instance variables, your superclass implementation can overwrite them.
4. You can override methods from the superclass and supply your own implementation. Some think this is a feature (see: template method pattern), but almost always this leads to pain as the superclass changes and affects every subclass implementation. You can invert this pattern by using the strategy pattern, which solves the same problem through composition.

Sometimes, though, there are legitimate situations where you want to inherit the entire interface to another object. A realistic example from Reverb is our view model hierarchy where various search views are all essentially “subclasses” of a parent view object that defines basics that every view uses, and then each view can define additional methods.

In these cases, one of the cleanest solutions is the DelegateClass pattern in Ruby. This is basically a decorator object that delegates all missing methods to the underlying class, just like inheritance would, but without giving you any access to the private methods of that class, or its instance variables.

Check out this example that illustrates both classical and DelegateClass-based inheritance:

– Yan Pritzker (@skwp)

iOS 9 and Charles Proxy

Using Charles Proxy to debug HTTPS requests on an iOS 9 simulator now has extra step to get it up and running. Application Transport Security (ATS) is the new technology in iOS 9 (and OS X v10.11) to enforce a set of best practices for all connections between an app and its backend. In practice, it blocks HTTP requests and some HTTPS requests that don’t meet a minimum standard, unless you provide an exception in your Info.plist. Currently, it also seems to be blocking requests when Charles is acting as a proxy for debugging purposes.

To continue to use Charles, we have to explicitly allow Insecure HTTP Loads in the Info.plist for requests on our domain to be readable in Charles. This covers (inherently) insecure HTTP connections and HTTPS connections that are not secure enough. The current beta of iOS 9 qualifies proxying through Charles as not secure, which is why we need the exception.

To do this, starting out on a fresh simulator, we’ll need to install the Charles Root Certificate

Screen Shot 2015-06-26 at 3.34.42 PM

We’ll still be seeing those SSL Handshake failures. Next, we need to add the exception in our Info.plist under a new NSAppTransportSecurity dict

NSAppTransportSecurity dict in info.plist


However, as Apple has telegraphed, exceptions shouldn’t be used unless absolutely necessary. Ideally, we’d only include this exception on DEBUG builds. To accomplish this, we can use a Run Script Phase under Build Phases. Using PlistBuddy, a command line tool preinstalled on OS X for directly reading and modifying values inside a property list, we can edit the build’s copy of the Info.plist to include the exception only when we need to. Since it is changing the build’s copy, these exceptions will only be available on that Debug build, leaving your Info.plist and its own list of exceptions alone. This also means these changes won’t be checked into version control.

Go to TARGETS->App->Build Phases then click on the plus sign in the upper left and select ‘New Run Script Phase’. Paste in the script below, changing the domain values as needed.

# Add exception for Debug builds
if [ "${CONFIGURATION}" == "Debug" ]
# Remove exception existing builds
/usr/libexec/PlistBuddy -c "Delete" "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}" 2>/dev/null
exitCode=$? #Supresses failure

/usr/libexec/PlistBuddy -c "Add dict" "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}"
/usr/libexec/PlistBuddy -c "Add bool true" "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}"
/usr/libexec/PlistBuddy -c "Add bool true" "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}"

This workaround is valid as of iOS 9 Beta 6. Things could change in the future to make this unnecessary. I’ll attempt to keep this post updated if anything changes. Edit: This continues to be necessary through the iOS 9 release, so I think it is safe to say it is here to stay.

For more info on using NSAppTransportSecurity exceptions in general, Steven Peterson has an excellent blog post:

Kevin Donnelly
Senior Mobile Developer

Disabling Animations in Espresso for Android Testing

When using Espresso for Android automated UI testing, it’s recommended that you disable system animations to prevent flakiness and ensure consistent, repeatable results. The Espresso docs provide a sample of how to disable animations programmatically, but leave out some important details. There is some discussion on that wiki page that provides good insight into solving the problems. Using those comments as a base, after lots of research and experimentation, we found a solution that works well for automatically disabling animations consistently for continuous integration tests.

Disable Animations Rule

First, we reworked the Espresso sample runner and turned it into a simple JUnit4 TestRule:

public class DisableAnimationsRule implements TestRule {
    private Method mSetAnimationScalesMethod;
    private Method mGetAnimationScalesMethod;
    private Object mWindowManagerObject;

    public DisableAnimationsRule() {
        try {
            Class<?> windowManagerStubClazz = Class.forName("android.view.IWindowManager$Stub");
            Method asInterface = windowManagerStubClazz.getDeclaredMethod("asInterface", IBinder.class);

            Class<?> serviceManagerClazz = Class.forName("android.os.ServiceManager");
            Method getService = serviceManagerClazz.getDeclaredMethod("getService", String.class);

            Class<?> windowManagerClazz = Class.forName("android.view.IWindowManager");

            mSetAnimationScalesMethod = windowManagerClazz.getDeclaredMethod("setAnimationScales", float[].class);
            mGetAnimationScalesMethod = windowManagerClazz.getDeclaredMethod("getAnimationScales");

            IBinder windowManagerBinder = (IBinder) getService.invoke(null, "window");
            mWindowManagerObject = asInterface.invoke(null, windowManagerBinder);
        catch (Exception e) {
            throw new RuntimeException("Failed to access animation methods", e);

    public Statement apply(final Statement statement, Description description) {
        return new Statement() {
            public void evaluate() throws Throwable {
                try { statement.evaluate(); }
                finally { setAnimationScaleFactors(1.0f); }

    private void setAnimationScaleFactors(float scaleFactor) throws Exception {
        float[] scaleFactors = (float[]) mGetAnimationScalesMethod.invoke(mWindowManagerObject);
        Arrays.fill(scaleFactors, scaleFactor);
        mSetAnimationScalesMethod.invoke(mWindowManagerObject, scaleFactors);

We use the same sample code to reflectively access the methods required to change the animation values, but instead of having to replace the default Instrumentation object to disable the animations, we just add a class rule to each test class that requires animations to be disabled (i.e., basically any UI instrumentation test) which disables animations for the duration of all tests in the class:

public class AwesomeActivityTest {

@ClassRule public static DisableAnimationsRule disableAnimationsRule = new DisableAnimationsRule();

public void testActivityAwesomeness() throws Exception {
// Do your testing

Getting Permission

So the rule is set up and a test is ready to run, but you need permission to change these animation values so this will fail with a security exception:
java.lang.SecurityException: Requires SET_ANIMATION_SCALE permission

To prevent this, the app under test must both request and acquire this permission.

To request the permission, simply add as you normally would for any standard permission to your AndroidManifest.xml file. However, since this is only for testing, you don’t want to include this in the main manifest file. Instead, you can include it in only debug builds (against which tests will run) by adding another AndroidManifest.xml file in your project’s debug folder (“app/src/debug”) and adding the permission to that manifest. The build system will merge this into the main manifest file for debug builds when running your tests.

To acquire the permission, you need to manually grant the permission to your app. Since it’s a system level permission, just adding a uses-permission tag will not automatically grant you the permission like other standard permissions. To grant your app the permission, execute the “grant” adb shell command on the device you’re testing on after the app has been installed:

shell pm grant android.permission.SET_ANIMATION_SCALE

Now you should be able to run your tests and disable animations for each test suite that needs them off and restore them when that suite completes. However, as soon as you uninstall the app your grant is gone and you have to manually grant the permission again for the next run.

That’s whack, yo – let’s automate this.

Automating Permission Grant

In the Espresso wiki discussions, a gist is provided that solves this issue. Since we set the permission for debug builds only, we don’t need the tasks that update the permissions in the manifest and just use the tasks that grant the permission (modified slightly). We found that you need to explicitly set the package ID since the build variable evaluates to the test package ID, not the id of the app under test.

task grantAnimationPermission(type: Exec, dependsOn: 'installDebug') {
    commandLine "adb shell pm grant android.permission.SET_ANIMATION_SCALE".split(' ')
tasks.whenTaskAdded { task ->
    if ('connected')) {
        task.dependsOn grantAnimationPermission

Now the permission will be automatically granted after the app is installed on the currently connected device. However, this presents yet another problem – this will fail if you have multiple devices attached since the adb command needs a target if there is more than one device available.

Targeting Multiple Devices

This gist provides a script that allows you to run a given adb command on each device available. If we save this in the app folder as “” the task becomes:

task grantAnimationPermission(type: Exec, dependsOn: 'installDebug') {
    commandLine "./ shell pm grant android.permission.SET_ANIMATION_SCALE".split(' ')

And there we go. Many hoops to jump through but with all of that set up you can now connect multiple devices and / or emulators and just run “./gradlew cC”. With this set up, Gradle will automatically build your app, deploy it to each device, grant it the SET_ANIMATION_SCALE permission, and run all of your tests with animations disabled as required.

Is SCrypt slowing down your tests?

If you’re using SCrypt for hashing passwords, make sure you’re not using it in test with fabrication-based techniques. This could result in unnecessarily slow fabrication times.

Here’s how you can set authlogic to use a different provider in test mode, so that your tests are faster:

acts_as_authentic do |c|
if Rails.env.test?
c.crypto_provider = Authlogic::CryptoProviders::MD5
c.crypto_provider = Authlogic::CryptoProviders::SCrypt


Documenting architecture decisions, the Reverb way

Ever make a decision in your codebase and then come back 6 months later and have no recollection of why the code is the way it is? I certainly have.

Enter the ADR – the Architecture Decision Record. For this idea, we traveled back in time to 2011 to find this blog post from  Relevance,inc. I really loved the idea of storing decision docs right in the codebase, as we all know that there are lies, damned lies, and documentation and thought that keeping things like this in the code base might help prevent documentation drift.

Here are some of the key takeaways to make architecture decision docs really useful:

  1. Store ADR docs right in your codebase. We put ours in doc/architecture. Use markdown so they read nicely on github.
  2. Document decisions, not the state of things. Decisions inherently don’t need to be kept up to date. We say why we did something, and 6 months from now, our system might look different, but we now have a record of what we used to think and why we thought it.
  3. Include a TLDR section at the top that explains the decision in a few concise sections.
  4. Include a More Details section that gives more depth to the explanation.
  5. Include a Tags section in your ADR doc. These should be things like class names, function names, business concepts, etc. That way when you’re in your code and you’re grepping for a particular thing, you’ll “stumble upon” the doc.
  6. If appropriate, link to the ADR in code comments in the area where the ADR applies. If you link to the full path like “doc/architecture/” then vim’s ‘gf’ shortcut can jump you right to the doc from the code.Bonus: blog it publicly. We have blogged one of our ADRs about timezones and we’ll have another one on Grape coming out soon.

Stay tuned,
Yan Pritzker, CTO

PayPal Express Checkout Broken – Use Webscr Fallback

If your paypal checkout suddenly started to redirect to and, the fix is to replace your checkout url from with

This morning we were alerted to users experiencing bizarre problems in our checkout. After clicking check out with paypal, they were redirected to a checkout page that was for or This page would be prefilled with a static dollar amount unrelated to what we were sending, and sometimes was prefilled with an email address of someone who was not our customer.

After checking with these websites, we found out that they too were experiencing checkout issues. We now suspect that this was affecting all websites using the new express checkout base url (
). In fact, if you just go to that url you would see the strangely cached HP or teespring checkout, even in an incognito window.

Here’s a screenshot:

We immediately rolled out a change to our checkout to disable the Paypal button, as this looked very fishy to our users, even though it was not our problem.

There was no immediate response from paypal or HP on twitter, though HP confirmed in their site support that they were having checkout issues as well. Teespring confirmed this as well.

We then discovered that the original express checkout url (
) works just fine. We were able to replace our base url quickly (thanks Chef!) and roll out a fix to our users.

Strange but true: there is one other express checkout url that works, and that is (
) – that is not a typo, the “/2” at the end actually forces the checkout into some special mode that is completely functional. However, we could not find any evidence for this URL being officially supported except for some stackoverflow posts, so until we hear more from Paypal, we’ll be using the old “webscr” url.

therubyracer and libv8 yosemite gem/bundler problems – the simplest fix of all

After doing a clean install on yosemite, some of our developers had issues compiling therubyracer/libv8. After scouring the internet, we found many awkward and horrible sounding workarounds ranging from downgrading versions to obscure command line compilation switches or compiler changes, none of which really worked.

So after the obligatory cut-n-paste-from-stackoverflow fest, we asked the underlying question: what is therubyracer/libv8, and why do we even need it?

Well, it turns out it’s used only for asset compilation by execjs. And what’s more, you don’t even need it on a mac. It turns out on MacOS, execjs can use Apple JavaScriptCore which comes as part of the system install.

So why would we want therubyracer in our Gemfile? Its entire purpose of existence is really asset compilation on Ubuntu. What else can serve the same job with zero pain? Nodejs.

So here’s the simplest possible fix:

  1. Remove therubyracer and libv8 from your Gemfile entirely.
  2. If compiling assets on ubuntu servers (e.g Jenkins), apt-get install nodejs
  3. Profit.

Enjoy the rest of your day and the countless hours saved trying to get bundler on osx to do the right thing.

till next time,

Yan Pritzker

Fun with setInterval and Turbolinks

Turbolinks is a fantastic tool that speeds up page loads by only loading the body of each page using ajax. The downside of using it, though, is that our javascript sins are no longer erased by a full page load when a user clicks on a link.

We ran into this recently while using setInterval to periodically poll the server for new information. Our initial code looked something like this:

Since the page was never reloaded, once the polling started it took place even while the user was on a different page, which resulted in a lot of unnecessary ajax requests. In addition, each time the page with polling was visited a new setInterval process was created. Obviously this could get quite out of hand.

To fix this, we knew we would need a clearInterval call of some sort. We tried this:

This seems to work except it instantly cleared any intervals after they were set. We experimented with binding to different events, but it was hard to predict the actual order of code execution regardless of the order of the lines of code or the order of the events we bound to. The only way to be absolutely sure that setInterval would be started and then a clearInterval would be bound to page:change was to unbind the clearInterval event when it fires.

Now our setInterval only runs on the desired page. If you have a lot of different setInterval events in your turbolinks app, you could easily create a function that handles all of this for you:

How not to fail at Timezones in Rails

We recently discovered a test that was failing only at night. Of course this set off all kinds of alarms in my head – we must be screwing something up with timezones! Time for an audit. Let’s review how Rails deals with timezones.

Water, fire, air, and dirt, f**king timezones, how do they work?

The following is taken almost verbatim from an Architecture Decision Record doc in our codebase.

In Rails, only methods like and are in the Rails configured timezone. Everything else like and is in system time.


What Rails does:

  • In Rails, refers to the Rails (not system) timezone, set by config.time_zone (typically in application.rb)
  • DateTime and Time are not otherwise Rails aware, therefore, and both return times in the system timezone.
  • 1.month.ago and similar methods use the Rails timezone, but uses the system timezone
  • When retrieving things from ActiveRecord, they will be timezoned to the Rails timezone, so Product.first.created_at will give you a time in the Rails timezone (not the system timezone)

What we do:

  • Our production servers run in UTC
  • Our dev machines typically run in CST/CDT
  • We are currently configuring our Rails timezone as Central Time but almost never using to use it
  • We are also using the Temporal gem which sets to the user who is browsing’s time using javascript


All systems should use UTC

Internally, all times should be stored in UTC (database, redis, elasticsearch). This will be the case because these systems are running in UTC.

If users submit an absolute date or time in a form

The form object or controller must parse that time using

If we display an absolute time to a user

  • First, try to avoid this by displaying relative times like “2 days ago”
  • If we must display an absolute time to the user, it should be shown using which should generally work if it came from ActiveRecord automatically.
  • If you want to display the current time or a specific time, you must use or“Your Specific Time”)

We will continue to use Central as our default timezone

We will continue to default the Rails Timezone to central so that if we can’t guess the user’s Timezone using Temporal, then absolute displayed times will be in central.

In tests

In tests, do not mix Rails timezone methods like “1.month.ago” with system timezone methods like “”


Yan Pritzker

Finding where a method is defined in Ruby

Ruby can sometimes look like magic, but, like all magic, if you look hard enough, you can see the sleight of hand.  With method_missing, dynamically defined methods, and being able to extend objects at runtime, sometimes it looks like voodoo as to where the method being called is actually defined. You could do a bunch of reverse engineering, or you could just ask ruby.