Routing rspec with nested routes

Problem

You would like to add a routing rspec test in your rails application that tests for a nested route.
So while you have something like the following in your config/routes.rb file:

namespace :admin do
  resources :users do
    resources :audits, only: [:index]
  end
end

you want to add the following test for your route:

expect(get: '/admin/users/:user_id/audits').to route_to(controller: 'admin/audits', action: 'index')

but you are getting an error like the following:

The recognized options <{"controller"=>"admin/audits", "action"=>"index", "user_id"=>":user_id"}> did not match <{"controller"=>"admin/audits", "action"=>"index"}>, difference:.
       --- expected
       +++ actual
       @@ -1 +1 @@
       -{"controller"=>"admin/audits", "action"=>"index"}
       +{"controller"=>"admin/audits", "action"=>"index", "user_id"=>":user_id"}

Solution

You will need to change your rspec to the following using any number for the user_id:

expect(get: '/admin/users/42/audits').to route_to(controller: 'admin/audits', action: 'index', user_id: '42')

Solution adapted from here

ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: ERROR: …

Problem

You have a Ruby on Rails application/engine with some tests in Minitest and using postgresql as the db. In the original development environment all the tests that use fixtures and foreign key validations pass, but when you try to move to a different environment with new database some or all of you tests fail with a message that refers to the ForeignKeyViolation as in:

ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: ERROR:  insert or update on table "tbl_name" violates foreign key constraint "tbl_name_cln_name_fk_tbl_name_fk"
DETAIL:  Key (col_name)=(VALUE) is not present in table "fk_tbl_name".

Solution

Since active record disables the foreign keys before loading the fixtures in the database, the user that you run the tests with needs to have superuser permissions in the test database. Otherwise the fixtures are not loaded. So add the superuser permissions to your user:

psql -U super_user
alter role use_for_tests superuser;

You may need to drop and create your test database.

Running a specific Cop in Rubocop

Problem

You are working on an existing rails project with many rubocop warnings and you would like to fix certain types or warnings by getting only the specified files.

Solution

So for example when you use rubocop you first get the following for all the files in the project:

rubocop
799 files inspected, 17214 offenses detected

You can get a grouping of the errors by using the following:

rubocop --format offenses
7176 Style/StringLiterals
3596 Metrics/LineLength
1031 Style/VariableName
790  Style/IndentationConsistency
548  Style/SpaceAroundOperators
423  Style/Documentation
415  Style/HashSyntax
386  Style/TrailingWhiteSpace
198  Style/SpaceAfterComma
...

If you would like to know only the files for a certain type of warning to be able to fix them you could try the following:

rubocop --only Style/TrailingWhitespace
..... list of files
799 files inspected, 386 offenses detected

Using Array.wrap in Rails when the results could either be a string or an array

Problem

You want to use some array method in a value returned, which can either be a single value or an array of values.

Solution

Rails ActiveSupport Array, provides a method called wrap, that can be used to:

Wraps its argument in an array unless it is already an array (or array-like)

Full explanation of the method here.

Thanks Miles

SSL received a record that exceeded the maximum permissible length.

Problem

You want to install rbenv, but when you are trying to clone the code with:

git clone https://github.com/rbenv/rbenv.git ~/.rbenv

you get the following error:

fatal: unable to access 'https://github.com/rbenv/rbenv.git/': SSL received a record that exceeded the maximum permissible length.

Solution

If you are behind a proxy server make sure that you add your proxy server details in your ~/.bash_profile and source the file afterwards.

So first add the details of your proxy like:

export http_proxy=http://xxx.xxx.xxx.xxx:8080
export https_proxy=https://xxx.xxx.xxx.xxx:8080

And finally source the file before running the installation again:

source ~/.bash_profile

Creating a simple rails docker image for testing in cloud deployment

Trying to deploy a rails application in a cloud provider ie dreamhost, that uses OpenStack these are the steps needed:

  1. Install docker in your development machine and your cloud provider by following the installation instructions from here
  2. Create an account in Docker Hub, that will be needed later on to push your docker image with the application
  3. Pull the official rails docker image to your development environment:
    sudo docker pull rails:latest
    
  4. Create a new simple rails application:
    rails new docker_test
  5. Change to the application directory and add a Dockerfile in the root directory containing the following:
    FROM rails:onbuild
  6. Build your new image by using:
    sudo docker build -t rails_docker_test .
  7. Check that your image was build by using:
    sudo docker images
  8. Start the container with:
    sudo docker run --name rails_test -p 0.0.0.0:3000:3000 -d rails_docker_test
  9. Make sure that you can see the initial rails page by using your browser to go to http://127.0.0.1:3000
  10. Push your image to your Docker Hub account by first logging in to it from the command line:
    sudo docker login --username=yourhubusername --email=youremail@company.com

    , and then when you get ‘Login Succeeded’, push your image to your account:

    sudo docker push yourhubusername/rails_docker_test
  11. TBC

Capturing output with UnitTest in Ruby

Problem

You have some ruby code, a rake task for example, that outputs some results in the standard output, but you would like to test it in your unit tests.
MiniTest has capture_io and capture_subprocess_io, but there is nothing similar in UnitTest.

Solution

Looking at the code of the above MiniTest assertions you can create your own assertion to be used in your tests.

Create a new file under your test folder called MyAssertions and use the following code (taken from MiniTest), for your capture_output assertion:

module MyAssertions
  module CaptureOutput
    # Use as:
    # out = capture_output { method_to_call(param1, param2) }
    # output = out[0], error = out[1] or
    # output = out.first, error = out.last
    def capture_output
      require 'stringio'

      captured_stdout, captured_stderr = StringIO.new, StringIO.new
      orig_stdout, orig_stderr = $stdout, $stderr
      $stdout, $stderr         =  captured_stdout, captured_stderr

      begin
        yield
      ensure
        $stdout = orig_stdout
        $stderr = orig_stderr
      end
      return captured_stdout.string, captured_stderr.string
    end

    def capture_subprocess_output
      require 'tempfile'

      captured_stdout, captured_stderr = Tempfile.new("out"), Tempfile.new("err")
      orig_stdout, orig_stderr = $stdout.dup, $stderr.dup
      $stdout.reopen captured_stdout
      $stderr.reopen captured_stderr

      begin
        yield

        $stdout.rewind
        $stderr.rewind

        [captured_stdout.read, captured_stderr.read]
      ensure
        captured_stdout.unlink
        captured_stderr.unlink
        $stdout.reopen orig_stdout
        $stdout.reopen orig_stderr
      end
    end
  end

  include CaptureOutput
end 

Then include it in your test_helper.rb file with:

require './test/my_assertions.rb'

and use it in your tests like:

out = capture_output { method_called(prm1, prm2) }

assert_match(/required_value/, out.first)

Could not find libv8-3.16.14.9 in any of the sources

Problem

You are trying to upgrade one of your gems (ie uglifier) and at the same time you are using a new gemset (ie for rails 4.2.4), and you get the following error when you are trying to bundle:

Could not find libv8-3.16.14.9 in any of the sources

Solution

Upgrade to rails 4.2.4 first and bundle and afterwards change the other gem and do bundle again.

make the unpermitted parameters errors in Ruby on Rails more obvious

Problem

When you are adding new attributes to your model after the initial creation, they are not by default included in the permitted parameters list. Sometimes the error is not so obvious to see when testing, unless you look at the test log files.

Solution

To make the error more obvious, there is the following configuration option that you can set up in config/environments/test.rb (tip taken from Rails 4 In Action):

config.action_controller.action_on_unpermitted_parameters = :raise