Password Protect Staging

I wanted to password protect my staging environment on Heroku.  Here’s a simple way to do it.

In your application controller, enter:

if Rails.application.secrets.auth
  http_basic_authenticate_with \
  name: Rails.application.secrets.auth_name,
  password: Rails.application.secrets.auth_pass
end
Then in your environment variables in Heroku (for your staging app), enter these variables:
AUTH = true
AUTH_NAME = <user name you want to use>
AUTH_PASS = <password you want to use>
Advertisements

Abbreviating Numbers in Rails

I needed to abbreviate numbers in Rails so that they were shorter and easier to read.  Rails has a great built in method, number_to_human.  However, I didn’t like how number_to_human displays without any customization.

My main issue was that instead of spelling out the entire number, I just wanted to put a letter abbreviation.  In addition, I didn’t want a space between the number and its text description.

For example, “out of the box”, if you do:

number_to_human(1234)

You will get:

“1.23 Thousand”

Instead, I wanted 1.23K.

Luckily, I found this StackOverflow answer by jdoe.

To format it like this, you just need to add these values to config/locales/en.yml (or whatever you’re using as your 18n locale):

(under "en:")
  number:
    human:
      decimal_units:
        format: "%n%u"
        units:
          unit: ""
          thousand: K
          million: M
          billion: B
          trillion: T
          quadrillion: Q

Hiding Values from Appearing in Rails Logs

I had some fields that were sensitive, so I didn’t want the values appearing in the logs.  The solution was filtering them.  Doing that was easy.

In config/initializers/filter_parameter_logging.rb, and your fields, like so:

Rails.application.config.filter_parameters += [:password, :secret_field]

Now, when I look at the logs, I see this:

“user”=>{“password”=>”[FILTERED]”, “secret_field”=>”[FILTERED]”

NoMethodError undefined method `[]’ for “image”:Sass::Script::Value::String

When upgrading my Rails app to 4 (from 3), I was getting the error:

NoMethodError undefined method `[]’ for “image”:Sass::Script::Value::String

Eventually I found out that the asset-path / asset-url methods changed to only accept one argument.

For example,

asset-url(‘profile.png’, image)

now should be:

asset-url(‘profile.png’)

In my particular case, this code was in some of my css files.

Useful Rails Testing Gems

Here’s a list of Rails gems that have been helpful in testing for me:

RSpec Rails – for using the RSpec framework for testing

Capybara – for testing the app like a visitor would interact with the web app

Factory Girl Rails – makes it easy to create instances of models and associations

Shoulda Matchers – makes it easier to test and verify things with methods that use easy to understand language

Database Cleaner – to help keep your test environment from having a bunch of extra and redundant data

Warden – since I use Devise, this makes it easy to sign in in my Capybara tests without having to go to the login screen each time (and then to the pages I really want to test)

Guard – allows me to automatically test the code and specs that I change so I don’t need to remember to manually kick off a test each time a change is made

Launchy – useful with Capybara tests when I can’t figure out why a test is failing.  Launchy launches a browser so you can see the contents of the page.’save_and_open_page’ line to your spec when you want to do this.

 

Simple_Form Custom Errors

I had some error messages not appearing in simple_form because the fields they were related to did not appear in the simple_form.  Normally, simple_form will highlight the field in the form that has a problem and display the error message next to it.  However, since the field related to the error wasn’t in the form, there was no message being shown.

To solve this, I had to add some additional code to display the text of the error message.

I fixed it by adding this to my simple_form forms:

<%= render 'shared/error_messages', object: f.object %>

and then created a partial, _error_messages (shared/_error_messages):

<% if object.errors.any? %>

<% end %>