Create a Cross-Platform Mini Photo Gallery With NativeScript and Angular2

android-ios-nativescript

In this post, I’ll guide you through the creation of a mini photo gallery using NativeScript and Angular2, that you’ll be able to reuse within other components of your application. The sample will run on both iOS and Android Platforms.

Initial Setup

I’ll suppose that you already have NativeScript and all the dependencies installed. If it’s not the case, take a look at the official documentation.
When this is done, go ahead and create a new project using Angular using the NativeScript CLI:

tns create tns-photo-gallery --ng

Creation of the component

The goal here is to create a Component that you could use everywhere throughout your application. We’ll then create a dedicated component called PhotoGalleryComponent. Go ahead and create the initial skeleton for it:

// app/photo-gallery.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'photo-gallery',
  templateUrl: 'photo-gallery.component.html',
  styleUrls: ['photo-gallery.component.css']
})
export class PhotoGalleryComponent {
}

Setup nativescipt-ng2-fonticon

The first thing I recommend, is using the nativescript-fonticon plugin which allows to use fonticons such as the one from FontAwesome with ease.
Start installing the package, by running:

npm install nativescript-ng2-fonticon --save

Once this done, you’re going to have to download the actual fonts and place it somewhere into your {N} project:

curl -O http://fontawesome.io/assets/font-awesome-4.6.3.zip
unzip font-awesome-4.6.3
cp font-awesome-4.6.3/css/font-awesome.css app/
mkdir app/fonts
cp font-awesome-4.6.3/fonts/fontawesome-webfont.ttf app/fonts
rm -rf font-awesome-4.6.3*

Next, add:

.fa {
  font-family: FontAwesome, fontawesome-webfont;
}

To the app.css file.
Finally, edit your app/main.ts file to register the TNSFontIconService dependency:

  provide(TNSFontIconService, {
    useFactory: () => {
      return new TNSFontIconService({
        'fa': 'font-awesome.css'
      });
    }
  })
]

Take a Photo and Display it

For our first step, we’re going to use the device camera to take a photo, and display it within a placeholder that we’ll define on our template. Let’s start with the following basic template:

<!--app/photo-gallery.component.html->

<StackLayout>
  <Image 
    #displayedPicture 
    stretch="aspectFill"
    [src]="picturePlaceholderPath"
    class="picture-placeholder"></Image>
  <StackLayout 
    class="take-picture-icon-wrapper"
    (tap)="takePicture()">  
    <Label
      ="'fa-camera' | fonticon"
      class="fa take-picture-icon"></Label>
  </StackLayout>
</StackLayout>

We display a StackLayout containing two elements: the Image that will contain the displayed picture from the camera, and a button to take the picture.
We use the “aspectFill” stretch property to make the source picture fill the Image element while keeping its aspect ratio. For more information about the available stretch properties, visit the NativeScript API reference. The default src is bound to the Component picturePlaceholderPath property, which we’ll define in a minute.
The button is composed of a StackLayout acting as a wrapper and a camera icon using a fonticon from FontAwesome. The wapper is bound to the takePicture() function that we’ll define in the Component as well.

Let’s style this a little bit:

/* app/photo-gallery.component.css* /

Image.picture-placeholder {
  height: 250;
}

StackLayout.take-picture-icon-wrapper {
  horizontal-align: right;
  margin: 15;
  padding: 15;
  border-width: 1;
  border-color: #CCCCCC;
  border-radius: 8;
}

Label.take-picture-icon {
  font-size: 25;
}

Since space is a rather scarce resource on a mobile, we limit the height of the displayed picture to 250 dip.

And finally, the Component itself:

// app/photo-gallery.component.ts

import {Component, ViewChild, ElementRef} from '@angular/core';
import {TNSFontIconService, TNSFontIconPipe} from 'nativescript-ng2-fonticon';
import {Image} from 'ui/image';

import {ImageSource} from 'image-source';
import * as camera from 'camera';

@Component({
  selector: 'pg-photo-gallery',
  templateUrl: 'photo-gallery.component.html',
  styleUrls: ['photo-gallery.component.css'],
  pipes: [TNSFontIconPipe]
})
export class PhotoGalleryComponent {
  @ViewChild('displayedPicture') displayedPictureRef: ElementRef;

  constructor(private fonticon: TNSFontIconService){
  }

  get picturePlaceholderPath(): string {
    return '~/images/placeholder-img.jpg'
  };

  takePicture(): void {
    camera.takePicture({ 
      width: 400, height: 400, keepAspectRatio: true 
    })
    .then((picture) => {
      this.display(picture);
    });
  }

  display(picture: ImageSource) {
    const displayedPictureView = <Image>this.displayedPictureRef.nativeElement;
    displayedPictureView.imageSource = picture;
  }
}

Few things here. First, notice the injection of the TNSFontIconService, which is necessary for the use of the TNSFontIconPipe. Then, the picturePlaceholderPath() getter that we referenced in the template. The picture used is the following:

placeholder-img

Just download it and place it to the app/images directory.

The takePicture() function makes use of the NativeScript camera module. We call the camera.takePicture() function with a maximal resolution of 400 * 400 (dip). Finally, when we get access to the taken picture, we display it by setting it to the imageSource property of the Image identified by #displayedPicture.

To test this, just reference the Component selector into the app.component.html Template:

<pg-photo-gallery></pg-photo-gallery>

And the result should look like this (on Android):


Display Multiple Pictures

Let’s modify the Component to be able to display multiple photos through their thumbnails. Let’s declare an Array that will contain all the taken pictures. Each time we’ll take a picture, we want to store it in this array as well:

[...]
import {GC} from 'utils/utils';
[...]
export class PhotoGalleryComponent {
  @ViewChild('displayedPicture') displayedPictureRef: ElementRef;

  pictures: Array<ImageSource> = new Array<ImageSource>();

  constructor(private fonticon: TNSFontIconService){
  }

  get picturePlaceholderPath(): string {
    return '~/images/placeholder-img.jpg'
  };

  takePicture(): void {
    camera.takePicture({ 
      width: 400, height: 400, keepAspectRatio: true 
    })
    .then((picture) => {
      this.display(picture);
      this.pictures.unshift(picture);
      GC();
    });
  }
[...]

The GC() function is called to clean up the mess in the memory let by camera.takePicture(). Without this, the application on Android will constantly crash after some pictures, leaving us with nothing but OutOfMemory exceptions. Notice that we use the Array.unshift() function to add the pictures. It’s because we will display the pictures from left to right instead of the other way around.

Now, we want to display all the taken photos as thumbnails. Edit the template file:

<StackLayout>
  <Image 
    #displayedPicture 
    stretch="aspectFill"
    [src]="picturePlaceholderPath"
    class="picture-placeholder"></Image>
  <GridLayout 
    rows="auto"
    columns="*, auto" 
    orientation="horizontal"
    class="thumbnails-bar">
    <ScrollView 
      col="0"
      orientation="horizontal">
      <StackLayout 
        class="thumbnails-container"
        orientation="horizontal">
        <Image 
          stretch="aspectFit"
          *ngFor="let picture of pictures" 
          [src]="picture"
          class="thumbnail"
          (tap)="display(picture)">
        </Image>
      </StackLayout>
    </ScrollView>
    <StackLayout 
      col="1"
      class="take-picture-icon-wrapper"
      (tap)="takePicture()">  
      <Label
        ="'fa-camera' | fonticon"
        class="fa take-picture-icon"></Label>
    </StackLayout>
  </GridLayout>
</StackLayout>

We now have a GridLayout to host both the thumbnail bar and the take-picture button. We want the rows to have an automatic height, but we want the first column (the one with the thumbnail bar) to occupy as much width as possible. The thumbnail bar in question is wrapped into an horizontal ScrollView. We use a *ngFor directive in an Image to loop through each picture of the pictures the array. We bind the picture to the src property of the Image, and the (tap) event to the display() function that we already have.

For the styling:

[...]
GridLayout.thumbnails-bar {
  margin-top: 10;
}

StackLayout.thumbnails-container,
Image.thumbnail {
  margin-left: 10;
  margin-right: 10;
}

Image.thumbnail {
  height: 50;
}

This should now look like this:


Delete the Pictures

Now that we can take multiple pictures and display them, we would like to be able to delete them as well. Let’s add a delete button. We will display it only if we have at least one taken picture.
First, let’s wrap the #displayedPicture Image into a GridLayout, and add the delete icon:

[...]
  <GridLayout rows="auto">
    <Image 
      #displayedPicture 
      stretch="aspectFill"
      [src]="picturePlaceholderPath"
      class="picture-placeholder"></Image>
    <StackLayout 
      [visibility]="deleteButtonVisibility"
      class="delete-picture-icon-wrapper"
      (tap)="deleteDisplayedPicture()">
      <Label 
        verticalAlignement="middle"
        ="'fa-trash' | fonticon"
        class="fa delete-picture-icon"></Label>
    </StackLayout>
  </GridLayout>
[...]

The GridLayout has one row, set to an automatic height. This avoids the childs to take the whole screen when displayed.
The delete button uses also a fonticon, and has its (tap) event bound to the deleteDisplayedPicture() function. The visibility is set dynamically through the deleteButtonVisibility property of the Component.

The styling:

StackLayout.delete-picture-icon-wrapper {
  background-color: #000000;
  border-width: 1;
  border-radius: 8;
  color: #FFFFFF;
  border-color: #FFFFFF;
  margin: 15;
  vertical-align: bottom;
  horizontal-align: right;
}

Label.delete-picture-icon {
  margin: 7;
  font-size: 15;
}

Now, we’re going to implement the deleteButtonVisibility property in the Component:

  get deleteButtonVisibility(): string {
    return this.noPicturesTaken? 'collapsed': 'visible'
  }

  private get noPicturesTaken(): boolean {
    return this.pictures.length == 0;
  }

This is pretty straightforward. We return ‘collapsed’ if there is no pitures in the array, ‘visible’ otherwise.

For the deleteDisplayPicture() function now, we’re going to have to do a few things. First, let’s introduce a getter to extract the Image View out of the displayedPictureRef variable:

private get displayedPictureView(): Image {
return this.displayedPictureRef.nativeElement;
}

And before going any further, let’s refactor the display() method to use this getter:

  display(picture: ImageSource) {
    this.displayedPictureView.imageSource = picture;
  }

Finally, let’s implement the deleteDisplayedPicture() function:

  deleteDisplayedPicture() {
    let indexToDelete = this.pictures.indexOf(this.displayedPictureView.imageSource);
    this.pictures.splice(indexToDelete, 1);
  }

Result:


You can clearly see that there’s something weird though: a deleted picture shouldn’t be displayed anymore.
Let’s correct this:

[...]
import * as imageSourceModule from 'image-source';
[...]

  deleteDisplayedPicture() {
    let pictureIndex = this.pictures.indexOf(this.displayedPictureView.imageSource);
    this.pictures.splice(pictureIndex, 1);
    if (this.noPicturesTaken) {
      this.concealPicture();
    }
    else this.displayClosestPictureFrom(pictureIndex);
  }

  concealPicture(): void {
    this.displayedPictureView.imageSource = 
      imageSourceModule.fromFile(this.picturePlaceholderPath);
  }

  private displayClosestPictureFrom(pictureIndex: number): void {
    let pictureToDisplay = this.pictures[pictureIndex];
    if (this.pictures[pictureIndex] === undefined) {
      pictureToDisplay = this.pictures[pictureIndex - 1];
    }
    this.display(pictureToDisplay);
  }

After having deleted the picture from the array, we conceal the picture if the array is empty (noPictureTaken). Otherwise, we display the closest picture from the deleted index (from the left). We do this by picking the picture having the previously deleted one’s index. If the current picture is undefined, this means that we’re out of the bound of the array, in other words: we deleted the last picture. In that case, we just take the one directly to the left.

Result (with iOS this time):


Integration With Another Component

In itself, the Component is not really useful. But you can now integrate it into another component and use it, for example, to send the pictures to a backend or to process the given pictures. For this last example, we will use the PhotoGalleryComponent within the AppComponent and apply a grayscale filter on the displayed picture, to make it appear on the screen.
First, let’s make the displayedPictureView property public instead of private, so we can access it in the outer Component:

  get displayedPictureView(): Image {
    return this.displayedPictureRef.nativeElement;
  }

Then, modify the app.component.html Template to add a button to trigger the image transformation, and a placeholder to display the result:

<ScrollView>
  <StackLayout>
    <pg-photo-gallery></pg-photo-gallery>
      <Label 
        verticalAlignement="middle"
        ="'fa-cogs' | fonticon"
        (tap)="transformDisplayedPictureToGrayScale()"
        class="fa process-picture-icon"></Label>
    <Image
      #transformedPicture 
      stretch="aspectFit"
      class="transformed-picture"></Image>
  </StackLayout>
</ScrollView>

The app.css stylesheet now:

.fa {
  font-family: FontAwesome, fontawesome-webfont;
}

Image.transformed-picture {
  margin-top: 5;
  height: 250;
}

Label.process-picture-icon {
  font-size: 20;
  horizontal-align: center;
}

Now, for the transformation, we will have to dig into the native APIs. Let’s create a new file called image-processing.ts that we’ll place into app/utils:

// app/utils/image-processing.ts

import {Image} from 'ui/image';

declare const android: any;
declare const CGRectMake: any;
declare const CGColorSpaceCreateDeviceGray: any;
declare const CGBitmapInfo: any;
declare const CGImageAlphaInfo: any;
declare const CGBitmapContextCreate: any;
declare const CGBitmapContextCreateImage: any;
declare const UIImage: any;
declare const CGContextDrawImage: any;
declare const CGColorSpaceRelease: any;
declare const CGContextRelease: any;
declare const CFRelease: any;

export function transformToGrayScale(args: { source: Image, destination: Image }): void {
  const sourceImage = args.source.imageSource;
    if (args.source.ios) {
      const rect = CGRectMake(0, 0, sourceImage.width, sourceImage.height);
      const colorSpace = CGColorSpaceCreateDeviceGray();
      const context = CGBitmapContextCreate(
        null, 
        sourceImage.width, 
        sourceImage.height, 
        8, 
        0, 
        colorSpace,
        CGImageAlphaInfo.kCGImageAlphaNone);
      CGContextDrawImage(
        context, 
        rect, 
        sourceImage.ios.CGImage);
      const imageRef = CGBitmapContextCreateImage(context);
      const image = UIImage.imageWithCGImage(imageRef);

      args.destination.ios.image = image;
    }
    else if (args.source.android) {
      args.destination.imageSource = sourceImage;
      var colorMatrix = new android.graphics.ColorMatrix();
      colorMatrix.setSaturation(0);
      var colorFilter = new android.graphics.ColorMatrixColorFilter(colorMatrix);
      args.destination.imageSource.android.setColorFilter(colorFilter);
    }
}

And finally, we need to implement the transformDisplayedPictureToGrayScale() function to apply the transformToGrayScale() function we’ve just defined. The source is the displayedPictureView from the PhotoGalleryComponent and the destination is the placeholder referenced by #transformedPicture:

import {Component, ViewChild, ElementRef} from '@angular/core';
import {Image} from 'ui/image';

import {PhotoGalleryComponent} from './photo-gallery.component';
import {TNSFontIconService, TNSFontIconPipe} from 'nativescript-ng2-fonticon';

import * as imageProcessingModule from './utils/image-processing';

@Component({
  selector: 'my-app',
  templateUrl: 'app.component.html',
  directives: [PhotoGalleryComponent],
  pipes: [TNSFontIconPipe]
})
export class AppComponent {
  @ViewChild(PhotoGalleryComponent) photoGalleryComponent: PhotoGalleryComponent;
  @ViewChild('transformedPicture') transformedPictureRef: ElementRef;

  constructor(private fonticon: TNSFontIconService) {
  }

  transformDisplayedPictureToGrayScale(){
    imageProcessingModule.transformToGrayScale({
      source: this.photoGalleryComponent.displayedPictureView,
      destination: this.transformedPictureView
    });
  }

  private get transformedPictureView(): Image {
    return this.transformedPictureRef.nativeElement;
  }
}

The final result on iOS looks like this:


And that’s it. You now have a reusable Component which is able to take pictures accessible for manipulation in another one.

If you found this article useful, don’t hesitate to share it or leave a comment. Please let me now if you encounter any trouble.
You can also find the whole source code on GitHub.

Vim Configuration for TypeScript and Angular2 Development

Slice 1

Some weeks ago, I’ve posted an article explaining my configuration for effective Rails development with Vim.
The goal of this article is to share the one I’m using for TypeScript / Angular2, through plugins and some customization. There is probably a lot more stuff available out there, but the following resources are what I consider a reasonable base to use Vim with these technologies.

typescript-vim, for TypeScript syntax support

The first must-have plugin is typescript-vim which provides support for syntax highlighting, indentation and also some in-Vim compilation features:

Screen Shot 2016-08-27 at 09.49.34

I use it mainly for the syntax / indenting but you can configure the plugin to display compilation errors in the QuickFix window. Add the following lines to your .vimrc:

let g:typescript_compiler_binary = 'tsc'
let g:typescript_compiler_options = ''
autocmd QuickFixCmdPost [^l]* nested cwindow
autocmd QuickFixCmdPost    l* nested lwindow

then, run :make while editing a TypeScript file to execute the tsc compiler and display errors in the QuickFix window:

Screen Shot 2016-08-27 at 10.07.35

vim-js-pretty-template, for Template Strings syntax support

Even if your Template Strings should never be bigger than 2 or 3 lines, it’s still useful to have syntax highlighting support for it. That’s exactly what vim-js-pretty-template provides.

After having installed the plugin, you can automatically load the configuration with TypeScript files, by putting the following to your .vimrc:

autocmd FileType typescript JsPreTmpl html
autocmd FileType typescript syn clear foldBraces

Result:
Screen Shot 2016-08-27 at 10.36.47

Tsuquyomi, to bring IDE-like features to Vim

Tsuqyomi is a powerful plugin that makes use of the TSServer (provided by TypeScript with its installation) behind the scenes to provide features such as auto-completion, symbols navigation and syntax / semantics errors display. The plugin depends on vimproc.vim which you have to install first.

Completion

The TypeScript completion is available through the Vim omni-completion (by default, accessed using ). You can also use YouCompleteMe to get the completion suggestions automatically triggered:


Automatic Files Import

Something you have to do quite often with TypeScript is import other files to make use of their exported interface. Tsquyomi makes this process really easy with the :TsuImport command. Just place the cursor over the symbol for which you’d like to have the corresponding file imported, and run the :TsuImport command:


Navigate to Symbols Definition

The plugin allows to navigate to Symbols by jumping to its definition. Place the cursor to the symbol you want to reach the definition and run :TsuDefinition:


In the previous example, I jumped to the definition of LoginComponent declared within the directives array. This brought me to the import statement on top of the file. I then pressed @: to repeat the command, which made the jump to the actual LoginComponent source file. Finally, I used C-T to jump back to the location I was before the move (exactly how you would do using CTags).

Show Symbol References

You can also use the plugin to display the references to a symbol in the QuickFix windows. use the :TsuReferences command:


Integration with syntastic, for in-editor syntax checking

syntastic is a syntax analyzer for Vim, displaying errors directly within the editor. You can configure it to get them as you save the file, without waiting to compile your code to be notified. The plugin uses external ‘checkers’ to delegate the syntax analysis. Tsuquyomi is one of those. Here are the configuration lines I use in my .vimrc to configure syntastic and Tsuquyomi:

set statusline+=%#warningmsg#
set statusline+=%{SyntasticStatuslineFlag()}
set statusline+=%*
let g:syntastic_check_on_open = 1
let g:syntastic_check_on_wq = 0
let g:tsuquyomi_disable_quickfix = 1
let g:syntastic_typescript_checkers = ['tsuquyomi'] 

As you can see, I’ve disabled the QuickFix window display while analyzing the syntax, as for me the combination of the markers and status line are enough. The last line is the actual checker declaration for typescript files.


auto-pairs, to automatically close wrapping elements

TypeScript is still JavaScript, which means that we have to deal with the kinda verbose syntax anyways. auto-pairs helps us automatically close open wrapping elements such as parenthesis, brackets, quotes… in a really smart way. It supports for example the automatic indentation when pressing Enter, or to jump the wrapping characters by typing them, instead of inserting them twice.


The documentation is pretty well written, take a look at it for more information regarding the use of the plugin.

angular-cli.vim, to control angular-cli in Vim

angular-cli.vim is a plugin I have written in order to be able to use the angular-cli directly within Vim. I have also added some navigation features that are similar to the vim-rails plugin from Tim Pope.
After having installed it, you can use the ng command through :Ng and use whatever arguments behind it.

The :E command allows you to edit an angular type quickly, using completion. The following types are supported:

  • Component
  • Template (HTML files)
  • Directive
  • Service
  • Pipe
  • Spec
  • Ng (every other file type: Class, Interface, Enum…)

To open up a component for example, start typing :EComponent with the component name and press tab to complete it:


You can also use the alternative V command, to open up the file in a virtual split instead:


You can use ESpec or VSpec the same way we did for the previous example, but you can also omit the argument to try to open the spec corresponding to the currently open file:


To generate a file, use the :G command:


For more information regarding the plugin, check out the github page. If you’d like to contribute, suggest a feature or report an issue, don’t hesitate to do so or to contact me.

I hope these information will help you being more productive with TypeScript and Angular, if you encounter any trouble during the installation or the use of one of the plugins, please write a comment and I’ll try to help. You can also checkout my dotfiles at this address.

Use Android API in NativeScript and Angular2 to Manipulate Images

nativeangular

One of the great things with NativeScript is the possibility to use standard web styling and templating tools (namely HTML and CSS) to build your cross-platform mobile application. Unfortunately, some features are not (yet) available, like for example the CSS background: linear-gradient property or filter. Fortunately though, NativeScript provides an almost full access to both iOS and Android native API, allowing to access powerful features, such as advanced image processing.
In this article, I will show you how to perform 3 image processing manipulation, using the Android API with TypeScript.

Before heading to the cases, go ahead and create a new NativeScript project using Angular2

tns create ImageProcessingApp --ng

Then, add the android platform support to the newly created application

tns platform add android

We will also need to add the package to be able to access the Android API withing a TypeScript source file. Run the following command within the ImageProcessingApp directory:

npm -i tns-platform-declarations

Then, add the following line to the reference.d.ts file

/// <reference path="./node_modules/tns-platform-declarations/tns-core-modules/android17.d.ts" />

Add a Linear Gradient Effect

This section will show you how to add a gradient background to a NativeScript View. To do this, we’re going to use the Android class GradientDrawable. Open up app.component.ts and add an AbsoluteLayout to the template, which will serve as the placeholder for the gradient background.

import {Component} from "@angular/core";

@Component({
    selector: "my-app",
    template: "<AbsoluteLayout #background></AbsoluteLayout>",
})
export class AppComponent {
}

Notice the id we gave to the Layout. We’re going to need it in order to access it and start manipulate it via the Android API. Let’s start doing this right now:

import { Component } from "@angular/core";
import { ViewChild } from "@angular/core/src/metadata";
import { ElementRef } from "@angular/core/src/linker/element_ref";

@Component({
    selector: "my-app",
    template: "<AbsoluteLayout #background></AbsoluteLayout>"
})
export class AppComponent {
  @ViewChild("background") background: ElementRef;
}

We’ve used the ViewChild decorator around the background property, giving the id corresponding to the view we want to capture (#background). This is of type ElementRef.
Now, let’s create a new TypeScript file, hosting the function to apply a gradient background through the Android native API. We’ll place it in app/utils folder

// app/utils/background-processing.ts

import { View } from "ui/core/view";
import { Color } from "color";

export function setBackgroundGradient(args: { view: View, colorCodes: string[] }) {
  var backgroundDrawable = new android.graphics.drawable.GradientDrawable();
  var colors = [];
  args.colorCodes.forEach(function(c) {
    let color = new Color(c);
    colors.push(color.android);
  });
  backgroundDrawable.setColors(colors);
  backgroundDrawable.setGradientType(0); // Linear Gradient
  var orientation = android.graphics.drawable
  .GradientDrawable.Orientation.LEFT_RIGHT;
  backgroundDrawable.setOrientation(orientation);
  args.view.android.setBackgroundDrawable(backgroundDrawable);
}

We’e using a GradientDrawable object from the Android API. We take an array of color codes in input, transform them into an Android Color object and pass them to the GradientDrawable. The rest is pretty straightforward. And since we’re using TypeScript, we can get autocompletion suggestions straight to the objects from the library, which is really useful.

Now, we need to call this function within the app.component, with the given background View in input, and the colors we want for the gradient. Open up app.component.ts and update it like this:

import { Component } from "@angular/core";
import { View } from "ui/core/view";
import { ViewChild } from "@angular/core/src/metadata";
import { ElementRef } from "@angular/core/src/linker/element_ref";
import { OnInit } from "@angular/core/src/metadata/lifecycle_hooks";
import { setLinearGradient } from "./utils/background-processing"

@Component({
    selector: "my-app",
    template: "<AbsoluteLayout #background></AbsoluteLayout>",
})
export class AppComponent implements OnInit {
  @ViewChild("background") background: ElementRef;

  ngOnInit(){
    let backgroundView = <View>this.background.nativeElement;
    setLinearGradient({
      view: backgroundView,
      colorCodes: ['#FA7EFE', '#9F14FC']
    });
  }
}

We use the OnInit hook access the background View (we can’t do it within the constructor, because it would be too early as the view would not be created already). We then call the setLinearGradient function with the nativeElement of the View in input, as well as an array composed of the #FA7EFE and #9F14FC colors. The result:

gradient

Add a grayscale filter

For this effect, we’re going to use an existing image which we’ll put to the app/images folder. I’ll use the following image, so go ahead and download it:

NativeScript_Angular_logo

Open up utils/background-processing.ts und add the following method:

export function transformToGrayScale(view: View){
  var colorMatrix = new android.graphics.ColorMatrix();
  colorMatrix.setSaturation(0);
  var colorFilter = new android.graphics.ColorMatrixColorFilter(colorMatrix);
  view.android.setColorFilter(colorFilter);
}

Then, open up app.component.ts and write the following content:

import { Component } from &quot;@angular/core&quot;;
import { View } from &quot;ui/core/view&quot;;
import { ViewChild } from &quot;@angular/core/src/metadata&quot;;
import { ElementRef } from &quot;@angular/core/src/linker/element_ref&quot;;
import { OnInit } from &quot;@angular/core/src/metadata/lifecycle_hooks&quot;;
import { transformToGrayScale } from &quot;./utils/background-processing&quot;

@Component({
    selector: &quot;my-app&quot;,
    template: <code>
    &lt;Image #image
    src=&quot;~/images/NativeScript_Angular_logo.png&quot; 
    stretch=&quot;none&quot; 
    verticalAlignment=&quot;middle&quot;
    horizontalAlignment=&quot;center&quot;&gt;&lt;/Image&gt;
    </code>,
})
export class AppComponent implements OnInit {
  @ViewChild(&quot;image&quot;) image: ElementRef;

  ngOnInit(){
    let imageView = &lt;View&gt;this.image.nativeElement;
    transformToGrayScale(imageView);
  }
}

The result:

grayscale

Add a Blur Effect Using RenderScript

For this effect, we’re going to need a direct access to the picture we want to manipulate, and pass it to a RenderScript object. The picture I’m going to use can be downloaded here. Make sure to download the “Large” format (1356 x 2048). Then, implement the applyBlurredBackground() function, in background-processing.ts like this:

export function applyBlurredBackground(args:{ image: ImageSource, view: View }){
  const RADIUS = 25;
  var inputBitmap = android.graphics.Bitmap.createBitmap(args.image.android);
  var outputBitmap = android.graphics.Bitmap.createBitmap(inputBitmap);
  var rs = android.renderscript.RenderScript.create(app.android.context);
  var intrinsic = android.renderscript.ScriptIntrinsicBlur.create(rs, android.renderscript.Element.U8_4(rs));
  var tmpIn = android.renderscript.Allocation.createFromBitmap(rs, inputBitmap);
  var tmpOut = android.renderscript.Allocation.createFromBitmap(rs, outputBitmap);
  intrinsic.setRadius(RADIUS);
  intrinsic.setInput(tmpIn);
  intrinsic.forEach(tmpOut);
  tmpOut.copyTo(outputBitmap);
  var backgroundDrawable = new android.graphics.drawable.BitmapDrawable(app.android.context.getResources(), outputBitmap);
  args.view.android.setBackgroundDrawable(backgroundDrawable);
}

This one is slightly more complicated than the two others. The code related to the proccessing with RenderScript is actually an adapted version of the one I found on this article. You can adjust the radius constant to fit your needs, 25 is the max value (goes from 1 to 25). We need to pass two arguments: the actual image against wihch we want to apply the blur effect, and the view we want to use as a container.
Finally, we can use this function like this in app.component.ts:

import { Component } from &quot;@angular/core&quot;;
import { View } from &quot;ui/core/view&quot;;
import { ViewChild } from &quot;@angular/core/src/metadata&quot;;
import { ElementRef } from &quot;@angular/core/src/linker/element_ref&quot;;
import { OnInit } from &quot;@angular/core/src/metadata/lifecycle_hooks&quot;;
import { applyBlurredBackground } from &quot;./utils/background-processing&quot;
import * as imageSource from &quot;image-source&quot;;

@Component({
    selector: &quot;my-app&quot;,
    template: <code>
    &lt;AbsoluteLayout #background&gt;&lt;/AbsoluteLayout&gt;
    </code>,
})
export class AppComponent implements OnInit {
  @ViewChild(&quot;background&quot;) background: ElementRef;

  ngOnInit(){
    let backgroundView = &lt;View&gt;this.background.nativeElement;
    let image = imageSource.fromFile(&quot;~/images/background.jpg&quot;);
    applyBlurredBackground({image: image, view: backgroundView });
  }
}

Just like we did for the Gradient effect in the first section, we define an AbsoluteLayout as a template, and give it the #background id. This allows us to retrieve it as ElementRef, through the @ViewChild decorator. We use the image-source library to retrieve the background from the images folder, and then, we pass them together to the applyBlurredBackground() function, which provides the following result:

blur

Create a Simple Calculator With NativeScript and Angular2

NativeScript_Angular_logo
NativeScript is a really exiting technology, which enables the development of native mobile applications using JavaScript, as well as CSS and HTML. Everything has been thought to make the transition from web to mobile development almost seamless, and this creates the possibility to build parts of your application that are usable for the web, and both Android and iOS mobile platforms. The best part: NativeScript also uses Angular2 and all the greatness that come with it (including TypeScript). This is what we’ll be using for this tutorial, which will show you how to build a really basic calculator for mobile. Let’s get started:

Setting up NativeScript

The easiest way to perform this step is to go and visit the official setup page from NativeScript. I’m personnaly using the Genymotion emulator and I really recommend it. The tutorial will use exclusively Android but since there is nothing really platform specific, this should work for iOS as well.

Starting the ns-calculator Project

To create the application using the NativeScript cli, run:

tns create ns-calculator --ng

The –ng flag indicates that we’ll be using Angular2. We then need to add the platform we want to support. As already said, I’ll be using Android, which is done through the following command:

tns platform add android

If you’d like to add iOS as well:

tns platform add ios

If this worked well, you should now have the following structure in place:
tree

the app folder is where we’ll spend all our time. For the first step, let’s open up app/app.component.ts and do some clean up in order to start from a healthy state:

import {Component} from "@angular/core";

@Component({
    selector: "my-app",
    templateUrl: "app.component.xml"
})
export class AppComponent {
}

The only thing I did is to delete the content from the AppComponent class, as well as replacing app.component.html with a .xml version. Both will actually do the job, and it’s just a matter of preference.

Next, let’s create the initial layout. Open up the app/app.component.xml, and put the following content:

<GridLayout columns="*, *, *, *" rows="auto, auto, *, *, *, *, *" >
  <Label class="result" text="RESULT" colSpan="4"></Label>
  <Label text="OPERATON" row="1" colSpan="4"></Label>
  <Button row="2" col="0" text="7"></Button>
  <Button row="2" col="1" text="8"></Button>
  <Button row="2" col="2" text="9"></Button>
  <Button row="2" col="4" text="+"></Button>
  <Button row="3" col="0" text="4"></Button>
  <Button row="3" col="1" text="5"></Button>
  <Button row="3" col="2" text="6"></Button>
  <Button row="3" col="3" text="6"></Button>
  <Button row="3" col="4" text="-"></Button>
  <Button row="4" col="0" text="1"></Button>
  <Button row="4" col="1" text="2"></Button>
  <Button row="4" col="2" text="3"></Button>
  <Button row="4" col="3" text="X"></Button>
  <Button row="5" col="0" text="0"></Button>
  <Button row="5" col="1" text="."></Button>
  <Button row="5" col="2" text="("></Button>
  <Button row="5" col="3" text=")"></Button>
  <Button row="6" col="0" text="UNDO"></Button>
  <Button row="6" col="1" text="CLEAR"></Button>
  <Button row="6" col="2" colSpan="2" text="="></Button>
</GridLayout>

We’ve created a GridLayout with 4 columns and 7 rows. We indicate that all the columns should use all the space available to them (through the ‘*’ symbol). Since We set this up for all of them, they should share the space equally between them. For the rows, we did the same apart from the two first ones. We just want them to occupy only the space they need (which is their default height).

We’re going to add a little bit of CSS to style this up. Edit app/app.css with the following content:

button, label{
  horizontal-align: center;    
}

label {
  font-size: 36;
}

label.result {
  font-size: 42;
  horizontal-align: left;
}

button {
  font-size: 36;
  width: 100%;
}

The result should look like this:

calcu

This is nice, but this doesn’t do much for the moment, so let’s work on this. Edit app.component.ts with the following content:

import {Component} from "@angular/core";

@Component({
    selector: "my-app",
    templateUrl: "app.component.xml"
})
export class AppComponent {
  operation: string = '';

  append(element: string){
    this.operation += element;
  }
}

We declare an operation variable of type string. The only operation for now is append(), which takes a string in input and add it to the operation variable. We need to do two things in order to put this in use: bind the operation variable to one of the labels in our layout, and call append for every button, with the corresponding elements as parameter. Edit app.component.xml with the following content:

<GridLayout columns="*, *, *, *" rows="auto, auto, *, *, *, *, *" >
  <Label class="result" text="RESULT" colSpan="4"></Label>
  <Label text="{{ operation }}" row="1" colSpan="4"></Label>
  <Button (tap)="append('7')" row="2" col="0" text="7"></Button>
  <Button (tap)="append('8')" row="2" col="1" text="8"></Button>
  <Button (tap)="append('9')" row="2" col="2" text="9"></Button>
  <Button (tap)="append('+')" row="2" col="4" text="+"></Button>
  <Button (tap)="append('4')" row="3" col="0" text="4"></Button>
  <Button (tap)="append('5')" row="3" col="1" text="5"></Button>
  <Button (tap)="append('6')" row="3" col="2" text="6"></Button>
  <Button (tap)="append('6')" row="3" col="3" text="6"></Button>
  <Button (tap)="append('-')" row="3" col="4" text="-"></Button>
  <Button (tap)="append('1')" row="4" col="0" text="1"></Button>
  <Button (tap)="append('2')" row="4" col="1" text="2"></Button>
  <Button (tap)="append('3')" row="4" col="2" text="3"></Button>
  <Button (tap)="append('*')" row="4" col="3" text="X"></Button>
  <Button (tap)="append('0')" row="5" col="0" text="0"></Button>
  <Button (tap)="append('.')" row="5" col="1" text="."></Button>
  <Button (tap)="append('(')" row="5" col="2" text="("></Button>
  <Button (tap)="append(')')" row="5" col="3" text=")"></Button>
  <Button row="6" col="0" text="UNDO"></Button>
  <Button row="6" col="1" text="CLEAR"></Button>
  <Button row="6" col="2" colSpan="2" text="="></Button>
</GridLayout>

We’ve now bound the operation variable to the second label through string interpolation. For every Button, we’ve bound the append method to the ‘tap’ event (equivalent to ‘click’ with Angular2 for the web), and we pass the corresponding element as parameter.
You should now be able to tap the buttons and see the operation building up on the second row of the screen:

The three last buttons require more specific behaviors. Let’s implement the undo() function. What we basically want, is to delete the last element from the whole operation. Add the following function to AppComponent:

  undo(){
    if (this.operation != ''){
      this.operation = this.operation.slice(0, -1)
    }
  }

We use the JavaScript slice method on operation in order to keep everything except the last character. Now, update the app.component.xml in order to bind this function to the tap event of the corresponding button:

  <Button (tap)="undo()" row="6" col="0" text="UNDO"></Button>

You should now be able to delete the last entered element:


Next, comes the clear() function. This one is pretty straightforward, we just want to empty the operation variable:

  clear(){
    this.operation = '';
  }

Alright, only one step left, which is the most important: the evaluation of the operation to get the result. Let’s introduce a new variable: result, of type string as well, which will host the result of the operation. Then, we’ll use the JavaScript eval() function on the operation variable, and stock the result in the result one:

import {Component} from "@angular/core";

@Component({
    selector: "my-app",
    templateUrl: "app.component.xml"
})
export class AppComponent {
  operation: string = '';
  result: string= '';

  append(element: string){
    this.operation += element;
  }

  undo(){
    if (this.operation != ''){
      this.operation = this.operation.slice(0, -1)
    }
  }

  clear(){
    this.operation = '';
  }
  
  evaluate(){
    this.result = eval(this.operation);
  }
}

Now, within app.component.xml, we need to do two things. First, bind the result to the first label. Then, attach the evaluate method to the ‘=’ button:

<GridLayout columns="*, *, *, *" rows="auto, auto, *, *, *, *, *" >
  <Label class="result" text="{{ result }}" colSpan="4"></Label>
  <Label text="{{ operation }}" row="1" colSpan="4"></Label>
  <Button (tap)="append('7')" row="2" col="0" text="7"></Button>
  <Button (tap)="append('8')" row="2" col="1" text="8"></Button>
  <Button (tap)="append('9')" row="2" col="2" text="9"></Button>
  <Button (tap)="append('+')" row="2" col="4" text="+"></Button>
  <Button (tap)="append('4')" row="3" col="0" text="4"></Button>
  <Button (tap)="append('5')" row="3" col="1" text="5"></Button>
  <Button (tap)="append('6')" row="3" col="2" text="6"></Button>
  <Button (tap)="append('6')" row="3" col="3" text="6"></Button>
  <Button (tap)="append('-')" row="3" col="4" text="-"></Button>
  <Button (tap)="append('1')" row="4" col="0" text="1"></Button>
  <Button (tap)="append('2')" row="4" col="1" text="2"></Button>
  <Button (tap)="append('3')" row="4" col="2" text="3"></Button>
  <Button (tap)="append('*')" row="4" col="3" text="X"></Button>
  <Button (tap)="append('0')" row="5" col="0" text="0"></Button>
  <Button (tap)="append('.')" row="5" col="1" text="."></Button>
  <Button (tap)="append('(')" row="5" col="2" text="("></Button>
  <Button (tap)="append(')')" row="5" col="3" text=")"></Button>
  <Button (tap)="undo()" row="6" col="0" text="UNDO"></Button>
  <Button (tap)="clear()" row="6" col="1" text="CLEAR"></Button>
  <Button (tap)="evaluate()" row="6" col="2" colSpan="2" text="="></Button>
</GridLayout>

And we should have the behavior we expects:

Now, if you try to evaluate an invalid operation, you’ll notice a crash of the application, as the eval() function throws an exception if the input is not valid JavaScript. Let’s catch the exception and alert the user saying that he tries to do an invalid operation. We’ll use NativeScript dialogs and specifically, the alert function. First, let’s import the dialogs module:

import dialogs = require("ui/dialogs");

Then, we update the evaluate method to catch the exception and display an error through dialogs.alert():

  evaluate(){
    try {
      this.result = eval(this.operation);
    }
    catch(e){
      dialogs.alert({title: 'Error', message: 'Cannot evaluate expression!', okButtonText: 'OK'});
    }
  }

I figured out this function definition as I wanted to change the default title which is ‘Alert’. I basically navigated to the definiton of the function, and noticed that this one was available:

    export function alert(options: AlertOptions): Promise<void>;

Navigating further to AlertOptions:

    /**
     * Provides options for the alert.
     */
    export interface AlertOptions extends DialogOptions {
        /**
         * Gets or sets the OK button text.
         */
        okButtonText?: string;
    }

And DialogOptions:

    export interface DialogOptions extends CancelableOptions {
        /**
         * Gets or sets the dialog title.
         */
        title?: string;

        /**
         * Gets or sets the dialog message.
         */
        message?: string;

    }

So I figured out the way to use alert(options: AlertOptions) without having to leave my editor: this is the power of TypeScript.

Let’s check out the error handling:

That’s it! we now have a simple mobile calculator (which should work on iOS as well).
You can checkout the code of this tutorial is available on GitHub.

Tips to Work Efficiently With Buffers in Vim

Vimlogo.
One of the things that determines your productivity in your text editor or IDE is the number of files you’re working with simultaneously. Ideally, you would have to be working with one single file at a time in order to focus your attention and limit the context switching which results in a costly loss of time and focus. But in reality, this isn’t likely to happen, since we’re not working within a single concern at a time (are you?). This implies having to go back and forth between the files, and Vim provides the possibility to handle this switching in a smart way, using buffers.

What is a buffer?

A buffer in Vim is simply a file that is loaded in memory so it can get accessed quickly. This is done automatically as soon as you open it up (typically using the :e command). You can also add a buffer associated to a file without having to edit it directly using :badd filename command.

Interact with buffers

To displays the open buffers, use the command:

:buffers

buffers
You’ll get a list with the buffers as well as their corresponding data. The first column is the unique number identifying the buffer. The second is the set of attributes. In the above example, there is:

  • a buffer with the attribute #, which corresponds to the ‘alternate’ (last edited buffer). You can open it directly using :e #
  • a buffer with the attribute %a, which means that it’s displayed in the current window (%), and visible (a). This is technically possible for a buffer to be visible, but not in the current window when working with splits for example.

For more information regarding the :buffers command, consult the official documentation.

You can close one or multiple buffers using:

:bdelete buffer1 buffer2 ...

To switch between buffers you can use:

:bnext

To open the next buffer in the list

:bprevious

To open the previous one.

:ball

will open up all the available buffers.

Another useful command is :bufdo which enables you to execute an operation on all open buffers. For example, to do a search replace through all buffers, you can execute:

:bufdo %s/search_tearm/replace_term/g | update

The update keyword at the end automatically saves the buffer if a replace actually takes place. To avoid having to do it every time I’m operating through multiple buffers, I have put:

set autowrite

in my .vimrc which takes care of saving the changes when vim automatically switch buffers.

To learn more about commands related to buffers manipulation, read the Vim FAQ on the subject.

Useful tips to work with buffers

Now, I’ll give you a few tips to work efficiently and move quickly around buffers.

buffers line with vim-airline

vim-airline is considered as a must-have plugin for Vim, as it adds up the graphics features cruelly missing from the default version. To me, the most useful feature is the bar displaying the list of open buffers. This is really useful because it makes you notice when you’re tending to have a list getting too big (which becomes a clear brake to your productivity).
To install vim-airline using Vundle, just place the following line in your .vimrc:

Plugin 'vim-airline/vim-airline'

And run :PluginInstall
vim-airline uses the Powerline patched fonts in order to display graphics elements within the terminal. The easiest way is to use this GitHub repository.
Clone it using:

git clone https://github.com/powerline/fonts

Then switch to the created repository and run the install script:

./install.sh

The next step is to configure your terminal to use one of the installed fonts (ending with for Powerline). Just be aware that all the fonts won’t necessarily work well with your airline configuration and you might notice graphic bugs. But there will be a few of them that’ll do the job properly though. The one I use is called Liberation Mono for Powerline (I’m using Ubuntu).

fonts

I won’t go into the features of vim-airline because it’s not the topic of this article but I’ll share the (basic) configuration I’ve set for it within my .vimrc:

let g:airline#extensions#tabline#enabled = 1
let g:airline_powerline_fonts = 1
let g:airline_theme='powerlineish'
let g:airline#extensions#syntastic#enabled = 1
set laststatus=2

The first parameter is what I’m talking about when I say the line displaying the list of open buffers. The second is here to make airline work with the Powerline patched fonts which is mandatory to have the graphics displayed properly. Then, we set the theme, the Syntastic integration and finally we use the status bar everywhere (displayed only when you open a split otherwise).

Now, start Vim and open up a bunch of files sequentially. You’ll have the associated buffers displayed in the top bar, and have the currently open one highlighted:

Swap and close buffers quickly

Here are mappings that I use quite often:

:nnoremap <Tab> :bnext<CR>
:nnoremap <S-Tab> :bprevious<CR>
:nnoremap <C-X> :bdelete<CR>

They allow you to switch buffers: Tab for the next one, Shift-Tab for the previous one. To quickly close a buffer, I use Ctrl-X. The cool thing is that you can actually see what happens with the vim-airline buffer line:

Fuzzy Search within Buffers with ctrlp.vim

ctrlp.vim is a Vim plugin providing fuzzy finding features for files, MRU (Most Recently Used files), and Buffers. Install it with Vundle:

Plugin 'ctrlpvim/ctrlp.vim'

To open the list of buffers and start searching through it, use:

:CtrlPBuffer

I’ve decided to map this command to Leader-B:

nmap <Leader>b :CtrlPBuffer<CR>

Now press Leader-B and start fuzzy navigating through the open buffers:

The alternate buffer is always the one selected by default, so to come back to it, just press Leader-B + Enter and there you are.

That’s it ! for any trouble / advice, please go ahead and write a comment.

You can checkout my dotfiles here.

My Vim Configuration for Rails Development

vim-rails

Vim is the editor of choice for many rails developers (including me). One of the reasons is the almost infinite level of configuration and customization it provides, as well as the massive choice of already existing plugins from the community. In this article, I’ll share my configuration which is really rails oriented, although there are some general tips you can use for something else.

Tmux and dispatch.vim

I’ve recently written an article to show the benefits of using Tmux and Time Pope’s dispatch.vim for quick and effective testing feedback. But you can actually achieve much more and we’ll see some example of integrations that are natively supported later in the article.
To install Tmux using Mac OS X:

brew install tmux

Using Debian / Ubuntu

sudo apt-get install tmux

You can install the dispatch plugin using Vundle:

Plugin 'tpope/vim-dispatch'

Rails Integration With vim-rails

If you had to choose only one vim plugin for Rails development, it would definitely be this one. It provides features such as inter (Rails) resources navigation, improved syntax highlighting, built-in Rake / Rails commands within Vim.
To make all this wonder available, just install it using Vundle:

Plugin 'tpope/vim-rails'

Resources Navigation

The navigation has been made easy yet extremely powerful. You just have to use the command with the following pattern :Eresource_type resource_name
For instance, opening up the UsersController file would simply be:

Econtroller users

To open the User model:

Emodel user

Without any parameter, the :Eresource will try to open up the resource linked to the one currently open one. For instance, if you have user.rb open, Econtroller will open up the associated users_controller.rb

E is actually using the Vim :e command under the hood. You can also use the alternatives like S (for :split), V (:vsplit) or T (:tabedit). If you’d like to open a controller in a new vertical split, you could do:

Vcontroller users

There are a lot of resources supported by the navigation mechanism, but here are the one I use the most often:

controller
model
spec
view
migration
helper

Navigate to Alternate File

Another helpful command is the :A (for Alternate) which takes you to the corresponding spec (or test) file. the plugin will first look for a MiniTest file if it exists, and then a spec file otherwise, so make sure that you don’t use generators automatically creating MiniTest files if you use RSpec instead. the :A command is compatible with the previously mentioned modes as well (S, V, T…).
For instance, opening the spec corresponding to the currently opened file in a new vertical split is done by calling :AV (mode placed at the end)

Navigate to Related File

We sometimes have to jump to file that is closely related to the one we’re currently editing. The command for this is :R (again, works with the S, V and T). The related files mappings are the following:

  • Model -> Schema definition
  • Controller -> View
  • Migration -> Next Migration (Previous Migration accessible using :A)

Jump to a File

the vim gf command is originally used to jump to the file described under the cursor. rails-vim extends this behavior by allowing to edit the file corresponding to the resource pointed by the cursor.

This works with multiple resources: Class / Module names, Active Record associations, layouts, stylesheets…

I usually work with vertical splits so I’ve used the key binding from this page to be able to open the file under the cursor to a new vertical split:

:map <F8> :vertical wincmd f<CR>

Command Line Integration

rails-vim enables the integration of rails and rake commands directly within Vim. The rails and rake commands are respectively accessible via :Rails and :Rake.
You can use them as you would normally do, but there are also some additional uses available. For instance, :Rgenerate model <model> will call the normal rails generate model user, and open the corresponding migration at the end of the process. :Rgenerate controller <model> will run the process and open the newly created controller:

You can also integrate with rails server using the :Rserver command. Now, if you have followed my advice, you probably have installed Tmux and the Dispatch.vim plugin. After having run a Tmux session with Vim, try to run :Rserver:

Instead of running the rails server in background as the :Rserver command normally does, it creates a new Tmux windows and run the command in it. You can now restart the server by running :Rserver! or kill it using :Rserver!- (or simply switch to the corresponding Tmux window and press Ctrl-C).

Concern and Partial Extraction

Concern and Partial extraction are made possible through the :Rextract command.
If the current opened file is a model, the result will be a concern extraction. For example, if I have the user model open and I want to select three methods for extraction. I can just go into visual mode, highlight the methods and run:

:'<,'>Rextract <concern_name>

This works with line numbers as well:

:9,19Rextract <concern_name>

The extracted methods will be put in a new file placed in app/models/concerns and inherits from ActiveSupport::Concern

The same mechanism applies for Partial extraction. Run:

:'<,'>Rextract <partial_name>; 

on the selected lines of one of your views and it will automatically create the partial with the _ prefix and replace the lines with the partial reference:

Fuzzy Finding With ctrlp.vim

ctrlp.vim is one of my favorite multi-purpose plugins for Vim. It enables to search through a directory of light using a fuzzy logic (and more). Start by installing it using Vundle:

Plugin 'ctrlpvim/ctrlp.vim'

Then go ahead and use it executing Vim in any directory and pressing Ctrl-P. You can then just type whatever you’re looking for in a fuzzy manner and press Enter to open up the found file (Ctrl-V to open in a new vertical split, Ctrl-T in a new tab):

You can also mark multiple files to open by cycling around using Ctrl-K (up) and Ctrl-J (down), then Ctrl-Z (mark file) and finally Ctrl-O to open:

You can also cycle through the available Search modes (File by default) to MRU (Most Recent Used) or opened Buffers by pressing Ctrl-F and Ctrl-B:

There is also a feature I find particularly useful: the file creation. Open up ctrlp, type the file you want to create and then press Ctrl-Y:

Why not simply use the :e command? well, this method will also create the corresponding folders if they don’t exist, which prevents you from having to manually create them before writing the new file.

The main downside with ctrlp.vim is to have to manually refresh the cache when something changes withing your current project structure (file renamed, deleted or added). you can do this by pressing F5 while ctrlp.vim open. But fortunately, there is a way around this which we’ll see later in the article.

Find Your Way in Your Source Code With CTags

Moving quickly between the references of your Rails project becomes a must when its size reaches a certain point. CTags enables you to do just that, by creating tags indexing the references of your project, in order to be reached wherever you are. You can read the following article which gives a good overview of the possibilities of using CTags with Rails.
Go ahead and generate the tags of your Rails project by running the following command, at the root:

ctags -R --languages=ruby --exclude=.git --exclude=log .

Or if you want to tag the external bundle dependencies as well (extremely useful):

ctags -R --languages=ruby --exclude=.git --exclude=log . $(bundle list --paths)

One of the common use cases is to reach a method definition while pointing at one of its calls. Point the cursor to the method for which you’d like to know the definition, and press Ctrl-] to jump to it:

Going back to your previous location is as easy as pressing Ctrl-T.
You can also do exactly the same by entering the method name instead of having to point to it by using the command:

:ta method_name

Blazing Fast Searching With the Silver Searcher

The Silver Searcher or is a searching tool which started as a clone of ack. Its creator claims a speed improvement of 5 to 10 times. Making it the default grepping command of Vim will make your search operations executed with the speed of light.
First of all, install it using:

brew install the_silver_searcher

For Mac OS X
and:

sudo apt-get install silversearcher-ag

For Debian / Ubuntu.
Note: I had to compile from the sources in order to get the latest version of ag on Ubuntu. You might have to do this if you notice that your .gitignore is not respected while using the command.

Then, do as it’s suggested in this article from Thoughtbot and write the following lines into your .vimrc:

" The Silver Searcher
if executable('ag')
  " Use ag over grep
  set grepprg=ag\ --nogroup\ --nocolor

  " Use ag in CtrlP for listing files. Lightning fast and respects .gitignore
  let g:ctrlp_user_command = 'ag %s -l --nocolor -g ""'

  " ag is fast enough that CtrlP doesn't need to cache
  let g:ctrlp_use_caching = 0
endif

This sets ag as the default grep command, as well as the ctrlp.vim files listing one. The speed provided by ag allows us to disable the cache, which solves the F5 problem we mentioned previously !

Then, you can map the :Ag command for instance to the \ key:

nnoremap \ :Ag<SPACE>

Using it with the text you want to search within your current project’s directory will display the result in the Vim Quickfix window. You can then press Enter on the row you want to open the corresponding file:

You can also pass an argument, like the folder in which you want to search:

:Ag app/controllers

Global Replace With qfdo.vim

qfdo.vim is a simple Vim plugin allowing to run a command for each line within the Quickfix window. Mixed with the :Ag command, it allows you to perform a two step global search replace.
Go ahead and install the plugin using Vundle:

Plugin 'karlbright/qfdo.vim'

Then write the following line to your .vimrc, which allows to auto save buffers after being automatically switched (needed for the replace withing multiple files which has to open and close multiple buffers sequentially):

set autowrite

Now suppose you want to change a method name. You can just search it using the :Ag command (through the \ key we previously mapped), then run:

:Qfdo s/method_to_search/method_to_replace_with/gce

With using the gce suffix, you’ll be prompted each time in order to confirm or reject the change. You could also replace all at one time using simply g. In action:

Syntax analysis with Syntastic and RuboCop

Syntastic is a plugin enabling the check the syntax of your source files. It displays potential warning as well as errors directly in the Vim interface and where it’s actually detected. The default checker for Ruby is RuboCop and we’ll see how to integrate it with Syntastic. First, install syntastic using Vundle:

Plugin 'scrooloose/syntastic'

Then, write the following configuration in your .vimrc:

set statusline+=%#warningmsg#
set statusline+=%{SyntasticStatuslineFlag()}
set statusline+=%*
let g:syntastic_check_on_open = 1
let g:syntastic_check_on_wq = 0
let g:syntastic_ruby_checkers = ['rubocop']

I use a minimal configuration to automatically check the syntax on open and omit on close. I also set the ruby checker to RuboCop which you can install either using:

gem install rubocop

Or by referencing the gem within your Gemfile:

gem 'rubocop', require: false

Now, you can start writing and get noticed from syntax warning and error as you save your buffers:

There is another cool trick that turns out to be really useful to do some refactoring. Go ahead and install the vim-rubocop plugin:

Plugin 'ngmy/vim-rubocop'

It enables you to use the RuboCop command directly in vim using :RuboCop. using it with the –auto-correct flag This can correct automatically some content marked as warning, use the best practices of the Ruby community instead and display the results within the QF window. Since I’m using I quite often, have mapped it to the Ctrl-A key. In action:

vim-rspec and Asynchronous Specs Run

I’ve already described this workflow in this article. It basically uses the combination of Tmux, Dispatch.vim and vim-rspec to run the specs asynchronously, and display the errors if some in the QF window. Install vim-rspec using Vundle:

Plugin 'thoughtbot/vim-rspec'

Configure the key mappings to run the appropriate specs:

map <Leader>t :call RunCurrentSpecFile()<CR>
map <Leader>s :call RunNearestSpec()<CR>
map <Leader>l :call RunLastSpec()<CR>
map <Leader>a :call RunAllSpecs()<CR>

Then, configure vim-rspec to start the rspec command using Dispatch:

let g:rspec_command = "Dispatch rspec {spec}"

When there are errors after the spec execution, the output is displayed within the QF Window. There is another plugin I use to toggle the QF maximization called vim-maximizer. It enables you to maximize / minimize the current focused window by pressing F3.
Installation with Vundle:

Plugin 'szw/vim-maximizer'

I also use the following mapping to be able to interact quickly with resulted errors:

map <F2> :Copen

To open the QF (or focus it if already open)
and:

map , :ccl

To close it.

Since you’re still in Vim while looking at the error, you can use the usual workflow to move around and for instance copy an error message to the clipboard.

vim-surround

vim-surround is another multi-purpose plugin that can’t miss from your .vimrc. It enables you to work with surrounding elements (parenthesis, quotes, tags…). You can either add one, change it or delete it. It’s also compatible with the usual Vim motions (i for inside, a for around, w for word…).

Surround a word using ysiw and then the surrounding character you want, for instance ysiw' (add surrounding character ' in word):

You can also change the surround to another character, like " with csi' (change surround inside '):

It also works in visual mode. Just select the text you want to surround, and then press S. The following example uses first a tag, and then the character ' for the final output:

Installation with Vundle:

Plugin 'tpope/vim-surround'

vim-endwise

Simple yet very handy plugin to automatically close blocks as you open them (def, if, do …). There is not much more to say about it apart that it saves a lot of time:

Installation with Vundle:

Plugin 'tpope/vim-endwise'

Git Integration with fugitive.vim

fugitive.vim is another great plugin from Tim Pope allowing you to use Git without making even a step out of Vim. You can basically use git as you would normally do using the :Git command but there’s obviously more.
Use for example :Gstatus to manage the staging area. You can select one (or many using visual mode) to commit and then press the - key. With :Gcommit, you can then write the commit message (by entering the edit mode) and save the buffer to execute your commit. Then, you can push using :Gpush. If you use the Tmux and Dispatch workflow, the push output will be displayed in a Tmux pane instead of blocking the window. In action:

Another great example is the use of :Gblame. Executing the command will open a vertical split with the output of a normal git blame. You can then select one row and press o to display the result into a split:

To execute git checkout on the current file, run :Gread:

For more detailed use cases, I suggest the following Vim Cast.

To install it using Vundle:

Plugin 'tpope/vim-fugitive'

Final Words

This is not the entire description of the configuration I use for Vim, but definitely the plugins I use the most often for my Rails development workflow. I hope you’ll be able to benefit from the tips and if you have anything useful to share or find a potential weakness / enhancements, please write a comment!
My dotfiles (Tmux, Vim) are available here.

Configure CORS to Allow Cross-Domain Requests in a Rails 5 API Application

If you have already tried to integrate a JavaScript Single Page Application with an API sitting in another domain, you’ve probably encountered blocked requests (and some frustration). This typically happens because most of the browsers don’t allow cross-domain HTTP requests originated from scripts, for security reasons. This is typically the case of the AJAX requests (XMLHttpRequests) sent by your JavaScript application.
Fortunately, there is a way to allow these requests, using the CORS mechanism.
A Rails 5 application created with the –api flag comes shipped with the rack-cors gem which provides full support for CORS. After your app creation, you’ll notice the file: config/initilizers/cors.rb which is commented out by default:

# Be sure to restart your server when you modify this file.

# Avoid CORS issues when API is called from the frontend app.
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.

# Read more: https://github.com/cyu/rack-cors

# Rails.application.config.middleware.insert_before 0, Rack::Cors do
#   allow do
#     origins 'example.com'
#
#     resource '*',
#       headers: :any,
#       methods: [:get, :post, :put, :patch, :delete, :options, :head]
#   end
# end

The only thing to do is to uncomment the lines corresponding to the actual configuration and adapt it to your needs. One example would be:

# Be sure to restart your server when you modify this file.

# Avoid CORS issues when API is called from the frontend app.
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.

# Read more: https://github.com/cyu/rack-cors

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'myfrontendapp.example.com'

    resource '*',
             headers: :any,
             methods: [:get, :post, :put, :patch, :delete, :options, :head],
             expose: ['access-token', 'expiry', 'token-type', 'uid', 'client'],
             max_age: 0
  end
end

The ‘*’ symbol means no restriction. We could have also used origins '*' to allow requests coming from anywhere but this is highly unrecommended. We also added an option to expose some header values. In this example, we want to allow the usual headers needed for a token-based authentication.

And that’s basically everything you need to do to make CORS working with your Rails API. For more information on the subject, I recommend reading this article.

Behavior-Driven Development of a Rails REST API With Cucumber and RSpec (Part III)

In the previous post of this series, we covered the creation of an offer for an existing ad.
In this part, we will focus on the two remaining use cases: The retrieval of all the ads, and the retrieval of offers corresponding to an existing ad.

Retrieve ads

Let’s start by creating a Feature file:

Feature: Retrieve ads

  Scenario: Retrieve ads
    Given following ads:
      | id |  title                | description                                 | price |
      | 1  | Old computer to sell  | I'm selling my computer as it's getting old | 125   |
      | 2  | Give away my camera   | To the one making the best offer            | 0     |
    When I make a GET /ads
    Then response shoud have status 200 and JSON:
    """
    [ { "id": 1, "title": "Old computer to sell", "description": "I'm selling my computer as it's getting old", "price": 125 },
    { "id": 2, "title": "Give away my camera", "description": "To the one making the best offer", "price": 0 }]
    """

In the first Given step, we’re giving a table in input with two ads and their corresponding attribute values. After making the GET request against the /ads path, we’re expecting to get back a JSON array with the two existing ads.
We’re going to have to implement the first two steps of this Scenario, so let’s grab the generated snippets and paste them into the ad_steps.rb file that we already have:

Given(/^following ads:$/) do |ads_table|
  # table is a Cucumber::Core::Ast::DataTable
  pending # Write code here that turns the phrase above into concrete actions
end

When(/^I make a GET \/ads$/) do
  pending # Write code here that turns the phrase above into concrete actions
end

Let’s go and implement the first step. Since we get a Cucumber Table in input, we can do the following:

Given(/^following ads:$/) do |ads_table|
  ads_table.hashes.each do |ad_hash|
    FactoryGirl.create(:ad, ad_hash)
  end
end

We iterate through the table hashes (where the keys are the columns of the first row of the table), and create a new Ad with the given hash, corresponding to the attributes. Again, we use FactoryGirl to make sure we create valid models (here, the users associations will be provided for us).
The second step is relatively simple:

When(/^I make a GET \/ads$/) do
  get "/ads"
end

But it won’t pass until we adapt the routes.rb file like this:

Rails.application.routes.draw do
  resources :ads, only: [:index, :create] do
    resources :offers, only: [:create]
  end
end

We’ve just added the :index method to the :ads resources definition. Now, after running the Scenario again, we get the following:

The action 'index' could not be found for AdsController (AbstractController::ActionNotFound)

So we go ahead and create an empty index method to the AdsController:

class AdsController < ApplicationController
  include ResourceController

  def index
  end

  private

  def permitted_params
    params.permit(:title, :price, :description, :user_id)
  end
end

Now we get:

expected #<Fixnum:401> => 200
     got #<Fixnum:409> => 204

Which tells us that we get no content and we’ll have to come up with something more than an empty method. Let’s now work on this. It’s time to get the ads_controller_spec.rb file from its grave and start writing the specification of the index method:

require 'rails_helper'
require 'controller_shared_contexts'

RSpec.describe AdsController, type: :controller do
  describe 'GET index' do
    before do
      first_ad = Ad.new(id: 1, title: 'First title', description: 'First description', price: 1)
      second_ad = Ad.new(id: 2, title: 'Second title', description: 'Second description', price: 2)
      expect(Ad).to receive(:all).and_return([first_ad, second_ad])
    end
    it_responds_with 'a success status'
    it_responds_with 'JSON body',
                     '[{ "id": 1, "title": "First title", "description": "First description", "price": 1 },
                      { "id": 2, "title": "Second title", "description": "Second description", "price": 2 }]'
  end
end

Since we’ve gained confidence by writing the previous specs, we can do a slightly bigger batch of testing and assertion. As you can see, I’m already assuming that we’ll have to call Ad.all and stubbing it out. To me, that’s still acceptable since we’re talking about recurring patterns that come to mind right away.
If we run this spec now, we get the following failure:

  1) AdsController GET index responds with a success status should respond with a success status code (2xx)
     Failure/Error: Unable to find matching line from backtrace
       (<Ad(id: integer, title: string, description: string, created_at: datetime, updated_at: datetime, user_id: integer, price: integer) (class)>).all(any args)
           expected: 1 time with any arguments
           received: 0 times with any arguments

Let’s then update the AdsController like this:

class AdsController < ApplicationController
  include ResourceController

  def index
    render json: Ad.all
  end

  private

  def permitted_params
    params.permit(:title, :price, :description, :user_id)
  end
end

We’re just rendering a JSON response containing the result of Ad.all that we’ve stubbed out in our spec. Running rspec again now gives us the following failure:

  1) AdsController GET index responds with JSON body should eq [{"id"=>1, "title"=>"First title", "description"=>"First description", "price"=>1}, {"id"=>2, "title"=>"Second title", "description"=>"Second description", "price"=>2}]
     Failure/Error: expect(JSON.parse(response.body))
       
       expected: [{"id"=>1, "title"=>"First title", "description"=>"First description", "price"=>1}, {"id"=>2, "title"=>"Second title", "description"=>"Second description", "price"=>2}]
            got: [{"id"=>1, "title"=>"First title", "description"=>"First description", "created_at"=>nil, "updated_at"=>nil, "user_id"=>nil, "price"=>1}, {"id"=>2, "title"=>"Second title", "description"=>"Second description", "created_at"=>nil, "updated_at"=>nil, "user_id"=>nil, "price"=>2}]
       
       (compared using ==)
       
       Diff:
       
       @@ -1,9 +1,15 @@
        [{"id"=>1,
          "title"=>"First title",
          "description"=>"First description",
       +  "created_at"=>nil,
       +  "updated_at"=>nil,
       +  "user_id"=>nil,
          "price"=>1},
         {"id"=>2,
          "title"=>"Second title",
          "description"=>"Second description",
       +  "created_at"=>nil,
       +  "updated_at"=>nil,
       +  "user_id"=>nil,
          "price"=>2}]

The problem is that we’re getting back too many attributes. We really want just title, description and price (at least, for now). We could make this attributes restriction in the controller, but pushing this responsibility to the model makes more sense to me. So will consider that by the time we call the all method on the Ad model, we’ll already get a list of ads with a list of filtered attributes:

require 'rails_helper'
require 'controller_shared_contexts'

RSpec.describe AdsController, type: :controller do
  describe 'GET index' do
    before do
      first_ad = Ad.new(id: 1, title: 'First title', description: 'First description', price: 1)
      second_ad = Ad.new(id: 2, title: 'Second title', description: 'Second description', price: 2)
      expect(Ad).to receive(:all).and_return([sliced(first_ad), sliced(second_ad)])
      get :index
    end
    it_responds_with 'a success status'
    it_responds_with 'JSON body',
                     '[{ "id": 1, "title": "First title", "description": "First description", "price": 1 },
                      {"id": 2, "title": "Second title", "description": "Second description", "price": 2 }]'
  end
  def sliced(ad)
    ad.slice('id', 'title', 'description', 'price')
  end
end

We use the slice method in order to select only the attributes we’re interesting in (we’ll actually get hashes instead of actual Objects but that’ll work just fine for us). This modification should make the spec pass already.
Now, let’s run the Cucumber Scenario once more. As expected, we get the following failure:

expected: [{"id"=>1, "title"=>"Old computer to sell", "description"=>"I'm selling my computer as it's getting old", "price"=>125}, {"id"=>2, "title"=>"Give away my camera", "description"=>"To the one making the best offer", "    price"=>0}]                                                                                                                                                                                                                               
got: [{"id"=>1, "title"=>"Old computer to sell", "description"=>"I'm selling my computer as it's getting old", "created_at"=>"2016-06-19T10:49:49.192Z", "updated_at"=>"2016-06-19T10:49:49.192Z", "user_id"=>1, "price"=>12    5}, {"id"=>2, "title"=>"Give away my camera", "description"=>"To the one making the best offer", "created_at"=>"2016-06-19T10:49:49.194Z", "updated_at"=>"2016-06-19T10:49:49.194Z", "user_id"=>2, "price"=>0}]                           

Let’s head down to the Ad model to correct its behavior. Open up the ad_spec.rb file and add the following lines:

  describe '.all' do
    before { FactoryGirl.create(:ad) }
    let(:ad_attributes) { Ad.all.first.attributes }
    it 'includes default attributes attribute' do
      expect(ad_attributes).to include('id', 'title', 'description', 'price')
    end
  end

We just make sure that we get the attributes we need when calling Ad.all. This should already pass. But now if we add this:

    it 'includes 4 attributes' do
      expect(ad_attributes.count).to be(4)
    end

We get the failure:

     Failure/Error: expect(ad_attributes.count).to be(4)
       
       expected #<Fixnum:9> => 4
            got #<Fixnum:15> => 7

This makes sense, we’re still getting too many attributes. Now that we have caught this into a spec, let’s adjust this. The easiest way to do it is to add a default scope to the Ad model, to limit the attributes to the list we need. For now, we only need id, title, description and price. We can do this by adding the following line to ad.rb:

  default_scope { select('id', 'title', 'description', 'price') }

At this stage, we should have a 100% green wave so we’re good to move further.

Retrieve offers

The last Feature we need to implement is the retrieval of offers, corresponding to a given ad. As always, let’s start with a Cucumber Feature and Scenario:

Feature: Retrieve offers

  Scenario: Retrieve offers
    Given an ad with id "1"
    Given following users:
      | id |
      | 2  |
      | 3  |
      | 4  |
    And following offers:
      | id | message                    | price | ad_id | user_id |
      | 1  | Exactly what I need !      | 500   | 1     | 2       |
      | 2  | Would you lower the price? | 25    | 1     | 3       |
      | 3  |                            | 75    | 1     | 4       |
    When I make a GET /ads/1/offers
    Then response should have status 200 and JSON:
    """
    [{ "id": 1, "message": "Exactly what I need !", "price": 500, "user_id": 2 },
    { "id": 3, "message": "", "price": 75, "user_id": 4 },
    { "id": 2, "message": "Would you lower the price?", "price": 25, "user_id": 3}]
    """

We start with an existing ad and 3 users. We attach 3 offers to the created ad using the different user ids. Then we make the GET request to /ads/1 and we finally expect to get a JSON array with the existing offers and their attributes, sorted by price (descending).
Alright, so let’s implement the missing steps here. First, the two Given:

Given(/^following users:$/) do |users_table|
  users_table.hashes.each do |user_hash|
    FactoryGirl.create(:user, user_hash)
  end
end

Given(/^following offers:$/) do |offers_table|
  offers_table.hashes.each do |offer_hash|
    FactoryGirl.create(:offer, offer_hash)
  end
end

We’ve already used this pattern for the creation of the ad table on the previous Feature. Now for the When step:

When(/^I make a GET \/ads\/(\d)\/offers$/) do |ad_id|
  get "/ads/#{ad_id}/offers"
end

Next step, update the routes:

Rails.application.routes.draw do
  resources :ads, only: [:index, :create] do
    resources :offers, only: [:index, :create]
  end
end

Now, before we go and add the index method to the OffersController, let’s think about how it’ll actually look like. Again, this will be exactly the same as for the AdsController. So let’s push this behavior direct into the ResourceController that we have and write a test for it. Open up the resource_controller_spec.rb file and do the following:
First of all, we need to update the Foo Fake model to implement an empty all class method that we want to stub out:

class Foo
  include ActiveRecord::Persistence
  include ActiveModel::Model
  attr_accessor :id, :name
  def self.all
  end
end

We have to do it that way since the method is originally included in ActiveRecord::Base. We didn’t want to inherit from it in order to avoid the overhead of creating a table definition for our test model.
Then, we can add the spec description for the GET index action:

  describe 'GET index' do
    before do
      first_foo = Foo.new(id: 1, name: 'First foo')
      second_foo = Foo.new(id: 2, name: 'Second foo')
      expect(Foo).to receive(:all).and_return([first_foo, second_foo])
      get :index
    end
    it_responds_with 'a success status'
    it_responds_with 'JSON body',
                     '[{"id": 1, "name": "First foo"},
                      {"id": 2, "name": "Second foo"}]'
  end

Now, running rspec indicates that there is no ‘index’ method defined in ResourceController, so let’s add it:

  def index
    resource_name = controller_name.classify
    render json: resource_name.constantize.all
  end

This makes the resource_controller_spec file pass. Let’s eliminate some duplication within the module:

module ResourceController
  def create
    resource = resource_class.create!(permitted_params)
    render json: { message: "#{resource_name} created successfully", id: resource.id }
  rescue ActiveRecord::RecordInvalid => invalid
    render json: { errors: invalid.record.errors }, status: :unprocessable_entity
  end

  def index
    render json: resource_name.constantize.all
  end

  private

  def resource_name
    controller_name.classify
  end

  def resource_class
    resource_name.constantize
  end
end

Let’s run the Retrieve Offers Scenario again:

expected: [{"id"=>1, "message"=>"Exactly what I need !", "price"=>500, "user_id"=>1}, {"id"=>3, "message"=>"", "price"=>75, "user_id"=>3}, {"id"=>2, "message"=>"Would you lower the price?", "price"=>25, "user_id"=>2}]        
got: [{"id"=>1, "price"=>500, "message"=>"Exactly what I need !", "user_id"=>2, "ad_id"=>1, "created_at"=>"2016-06-19T19:18:31.889Z", "updated_at"=>"2016-06-19T19:18:31.889Z"}, {"id"=>2, "price"=>25, "message"=>"Would you lower the price?", "user_id"=>3, "ad_id"=>1, "created_at"=>"2016-06-19T19:18:31.892Z", "updated_at"=>"2016-06-19T19:18:31.892Z"}, {"id"=>3, "price"=>75, "message"=>"", "user_id"=>4, "ad_id"=>1, "created_at"=>"2016-06-19T19:18:31.894Z", "updated_at"=>"2016-06-19T19:18:31.894Z"}]                 

Ok, so we still made a step forward, but we need one more thing to do in order to make the Scenario pass: The limitation of returned attributes from the model. As always, we start by defining the behavior that we want within the corresponding spec file:

  describe '.all' do
    before { FactoryGirl.create(:offer) }
    let(:offer_attributes) { Offer.all.first.attributes }
    it 'includes default offer attributes' do
      expect(offer_attributes).to include('id', 'message', 'price', 'user_id')
    end
    it 'includes 4 attributes' do
      expect(ad_attributes.count).to be(4)
    end
  end

Since we’re now hitting the database in a spec file for the first time, we need to configure RSpec to clean up the mess between each test. We’ll use the DatabaseCleaner gem that we already use for Cucumber. Open up the rails_helper.rb file and add the following content:

  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
    DatabaseCleaner.strategy = :transaction
  end
  config.around(:each) do |example|
    DatabaseCleaner.cleaning do
      example.run
    end
  end

We tell RSpec to clean everything before running the suite using the truncation method. Then, we use the transaction method between each test to isolate them from each other.
We can now run the spec, which gives us the following failure:

     Failure/Error: before { FactoryGirl.create(:offer) }
     ActiveRecord::RecordInvalid:
       Validation failed: User must exist, Ad must exist

That’s because we didn’t declare any association to our :offer Factory as we didn’t really need it so far. Looks like we do know, so let’s do this:

FactoryGirl.define do
  factory :offer do
    message Faker::Lorem.sentence
    price Faker::Number.number(2)
    association :ad
    association :user
  end
end

Run again. Now we get:

     Failure/Error: expect(offer_attributes.count).to be(4)
       
       expected #<Fixnum:9> => 4
            got #<Fixnum:15> => 7
class Offer < ApplicationRecord
  belongs_to :user
  belongs_to :ad
  validates :price, presence: true

  default_scope { select('id', 'message', 'price', 'user_id') }
end

If we get back to the Cucumber Scenario and try to run it again, we get:

      expected: [{"id"=>1, "message"=>"Exactly what I need !", "price"=>500, "user_id"=>1}, {"id"=>3, "message"=>"", "price"=>75, "user_id"=>3}, {"id"=>2, "message"=>"Would you lower the price?", "price"=>25, "user_id"=>2}]
           got: [{"id"=>1, "price"=>500, "message"=>"Exactly what I need !", "user_id"=>2}, {"id"=>2, "price"=>25, "message"=>"Would you lower the price?", "user_id"=>3}, {"id"=>3, "price"=>75, "message"=>"", "user_id"=>4}]

We get the sorting wrong. As we said, we expect the offers to be sorted by price descending. So let’s update the Offer.all method description like this:

  describe '.all' do
    before { FactoryGirl.create(:offer, id: 1, price: 3) }
    let(:offer_attributes) { Offer.all.first.attributes }
    it 'includes default offer attributes' do
      expect(offer_attributes).to include('id', 'message', 'price', 'user_id')
    end
    it 'includes 4 attributes' do
      expect(offer_attributes.count).to be(4)
    end
    it 'sorts by price descending' do
      FactoryGirl.create(:offer, id: 2, price: 8)
      FactoryGirl.create(:offer, id: 3, price: 5)
      expect(Offer.all.collect(&:id)).to eq([2, 3, 1])
    end
  end

We’ve extended the previously created offer by giving it an id and a price. Then, in the price sorting description, we create two additional offers with given ids and prices. Finally, we assert on the correct offer ids order when calling the all method. As we expect, the result is the following:

     Failure/Error: expect(Offer.all.collect(&:id)).to eq([2, 3, 1])
       
       expected: [2, 3, 1]
            got: [1, 2, 3]

To make this one pass, we’ll update the default scope to add the sorting by price, like this:

class Offer < ApplicationRecord
  belongs_to :user
  belongs_to :ad
  validates :price, presence: true

  default_scope { select('id', 'message', 'price', 'user_id').order(price: :desc) }
end

And that was basically the last step of our acceptance loop! we should be in a green state on both RSpec and Cucumber sides.

Final thoughts

That was the last post of this series of three articles. We went through an outside-in process enabling us to first define how the outcomes of the requests our system should look like through Cucumber Features. We worked our way down to the Models, going through the Controllers using RSpec tests. You’ve noticed that I have chosen to isolate the Controllers specs from the Models which is a bit different from the conventional practices of the Rails community, tending to be more Integration tests. I personally prefer to do it that way I did because we’re getting much more focused feedback in case of failures, and since we don’t hit the database, we also get a speed advantage. The price however, is that we have to stub out the Model behavior which can makes us lose some confidence, and add some overhead (but rspec and the dynamic nature of ruby make it really easy).
In any case, we managed to shape the API by doing some incremental steps, each time, stating how we would like the behavior of each component under our radar. This also allowed us to manage safely some refactoring steps, for instance, by extracting the common behavior of our two controllers into a concern module which we could also test in isolation. For any remarks, troubles or enhancements tips, please write a comment !
The code is also available on GitHub at this address.

Behavior-Driven Development of a Rails REST API With Cucumber and RSpec (Part II)

In the previous article of this series, we covered the Ad creation use case given a title, a description, a price and the corresponding user id. Now will focus on enabling a user to place an offer on an existing ad. We said that an offer contains a price and a message. We’ll consider it as valid if it has at least a price (message being optional).

Make an offer to an existing Ad

  Scenario: using valid data
    Given an ad with id "1"
    And a user with id "2"
    When the client makes a valid POST /ads/1/offers with user_id: "2"
    Then response should have status 200 and JSON:
    """
      {"message": "Offer created successfully", "id": 1}
    """

The implementation of the first step simply makes use of FactoryGirl to create a new ad, with the given id:

 Given(/^an ad with id "([^"]*)"$/) do |id|
   FactoryGirl.create(:ad, id: id)
 end

Running the Cucumber Scenario after this gives us the following error:

Validation failed: User must exist (ActiveRecord::RecordInvalid)

That’s because we didn’t declare any relation to the default Ad factory yet. Let’s correct this:

FactoryGirl.define do
  factory :ad do
    title Faker::Lorem.word
    price Faker::Number.number(2)
    description Faker::Lorem.sentence
    association :user
  end
end

This tells FactoryGirl to automatically associate the ad with a user when using the create method. The :user factory needs to be existing, and since we have already defined one during the first part of the article, we’re good to go. Now for the second step:

When(/^the client makes a valid POST \/ads\/(\d+)\/offers with user_id: "([^"]*)"$/) do |ad_id, user_id|
  params = FactoryGirl.attributes_for(:offer).merge(user_id: user_id)
  post "/ads/#{ad_id}/offers", params
end

We also use FactoryGirl but only to generate the parameters we need to make the request, in addition to the given user_id.
We need to introduce the :offer factory as well as the corresponding model. Let’s start by the model generation:

rails g model offer price:integer message:string user:references ad:references
rails db:migrate

And then the factory, using Faker generated attributes:

FactoryGirl.define do
  factory :offer do
    message Faker::Lorem.sentence
    price Faker::Number.number(2)
  end
end

We’re now ready to run the Scenario again, and we come to the following failure:

No route matches [POST] "/ads/1/offer" (ActionController::RoutingError)

Which brings us to the following update of routes.rb:

Rails.application.routes.draw do
  resources :ads, only: [:create] do
    resources :offers, only: [:create]
  end
end

Again, we just define the route we actually need for the moment. Now the OffersController containing an empty create method:

class OffersController < ApplicationController
  def create
  end
end

Before going any further, let’s start the implementation of the OffersController spec. It’ll be very similar as the AdsController one and we’ll see how we can refactor to eliminate duplications afterwards:

require 'rails_helper'

RSpec.describe OffersController, type: :controller do
  describe 'POST create' do
    let(:permitted_params) { ActionController::Parameters.new(params) }
    let(:params) { FactoryGirl.attributes_for(:offer).merge(ad_id: '1', user_id: '2') }
    let(:execute_request) { post :create, params: params }

    before(:all) do
      ActionController::Parameters.permit_all_parameters = true
    end

    context 'with valid parameters' do
      before do
        execute_request
      end
      it 'returns a successful response' do
        expect(response).to have_http_status(:success)
      end
      it 'returns returns success message with offer id' do
        expect(JSON.parse(response.body))
          .to eq(JSON.parse('{ "message": "Offer created successfully", "id": 1 }'))
      end
    end
  end
end

Let’s then update the OffersController with the code required to make these examples pass:

class OffersController < ApplicationController
  def create
    offer = Offer.create!(offer_params)
    render json: { message: 'Offer created successfully', id: offer.id }
  end
end

private

def offer_params
  params.permit(:message, :ad_id, :user_id)
end

But now, running this spec file throws the following failure:

     Failure/Error: let(:execute_request) { post :create, params: params }
     ActiveRecord::RecordInvalid:
       Validation failed: User must exist, Ad must exist

which is related to the validation of the model. Since we’re interested in the controller behavior only for now, let’s stub out the Offer.create! method to return a valid model, that we declare through a let variable:

require 'rails_helper'
require 'controller_shared_contexts'

RSpec.describe OffersController, type: :controller do
  describe 'POST create' do
    let(:permitted_params) { ActionController::Parameters.new(params) }
    let(:offer) { FactoryGirl.build(:offer, id: 1) }
    let(:params) { FactoryGirl.attributes_for(:offer).merge(ad_id: '1', user_id: '2') }
    let(:execute_request) { post :create, params: params }

    before(:all) do
      ActionController::Parameters.permit_all_parameters = true
    end

    context 'with valid parameters' do
      before do
        expect(Offer)
          .to receive(:create!)
          .with(permitted_params)
          .and_return(offer)
        execute_request
      end
      it 'returns a successful response' do
        expect(response).to have_http_status(:success)
      end
      it 'returns returns success message with offer id' do
        expect(JSON.parse(response.body))
          .to eq(JSON.parse('{ "message": "Offer created successfully", "id": 1 }'))
      end
    end
  end
end

And we now have two passed examples. So let’s stop for a minute and try to eliminate some of the duplications we have introduced between this spec and the AdsController one.
First of all, there is the mechanism for the permitted parameters, which is common to the two specs. Let’s create a new RSpec shared context file:

#spec/controller_shared_context.rb

shared_context 'permit_params' do
  let(:permitted_params) { ActionController::Parameters.new(params) }
  before(:all) do
    ActionController::Parameters.permit_all_parameters = true
  end
end

Now we can make use of the shared_context we declared, by including it into our spec (and requiring the associated file on top):

require 'rails_helper'
require 'controller_shared_contexts'

RSpec.describe OffersController, type: :controller do
  describe 'POST create' do
    include_context 'permit_params'
    let(:offer) { FactoryGirl.build(:offer, id: 1) }
    let(:params) { FactoryGirl.attributes_for(:offer).merge(ad_id: '1', user_id: '2') }
    let(:execute_request) { post :create, params: params }

    context 'with valid parameters' do
      before do
        expect(Offer)
          .to receive(:create!)
          .with(permitted_params)
          .and_return(offer)
        execute_request
      end
      it 'returns a successful response' do
        expect(response).to have_http_status(:success)
      end
      it 'returns returns success message with offer id' do
        expect(JSON.parse(response.body))
          .to eq(JSON.parse('{ "message": "Offer created successfully", "id": 1 }'))
      end
    end
  end
end

Next, let’s tackle the successful response assertion. We can also use a shared_context like the following:

# spec/controller_shared_contexts.rb

RSpec.configure do |c|
  c.alias_it_should_behave_like_to :it_responds_with, 'responds with'
end
shared_context 'a success status' do
  it { expect(response).to have_http_status(:success) }
end

We created an alias for the it_should_behave_like method to it_responds_with, which enables us to change

it 'returns a successful response' do
  expect(response).to have_http_status(:success)
end

to

it_responds_with 'a success status'

This enables us to reuse the response status expectation, but staying expressive enough at the same time.
Let’s now create a shared_context for the response body assertion as well:

shared_context 'JSON body' do |json|
  it do
    expect(JSON.parse(response.body))
      .to eq(JSON.parse(json))
  end
end

which we can now use like this:

it_responds_with 'JSON body',
                 '{ "message": "Offer created successfully", "id": 1 }'

Now, our OffersController spec file should look like:

require 'rails_helper'
require 'controller_shared_contexts'

RSpec.describe OffersController, type: :controller do
  describe 'POST create' do
    include_context 'permit_params'
    let(:offer) { FactoryGirl.build(:offer, id: 1) }
    let(:params) { FactoryGirl.attributes_for(:offer).merge(ad_id: '1', user_id: '2') }
    let(:execute_request) { post :create, params: params }

    context 'with valid parameters' do
      before do
        expect(Offer)
          .to receive(:create!)
          .with(permitted_params)
          .and_return(offer)
        execute_request
      end
      it_responds_with 'a success status'
      it_responds_with 'JSON body',
                       '{ "message": "Offer created successfully", "id": 1 }'
    end
  end
end

This should make our Cucumber Scenario pass as well. So let’s write the unsuccessful case within the Feature file:

  Scenario: using blank price
    When the client makes a POST /ads/1/offers request with blank price and user_id: "2"
    Then response should have status 422 and JSON:
    """
      {"errors": {"price": ["can't be blank"]}}
    """

Before implementing the new When step, let’s change the helper method:

def valid_ad_creation_params(user_id)
  FactoryGirl.attributes_for(:ad).merge(user_id: user_id)
end

to:

def valid_creation_params_for(resource, user_id)
  FactoryGirl.attributes_for(resource).merge(user_id: user_id)
end

Now, let’s push it as well as the Transform method into a new file in order to bring a little organization:

# features/support/step_helpers.rb

module StepHelpers
  def valid_creation_params_for(resource, user_id)
    FactoryGirl.attributes_for(resource).merge(user_id: user_id)
  end
end
World(StepHelpers)

Transform /(\d+)$/ do |number|
  number.to_i
end

And adapt the step definitions file like this:

# features/step_definitions/ad_steps.rb

Given(/^a user with id "([^"]*)"$/) do |id|
  FactoryGirl.create(:user, id: id)
end

Given(/^an ad with id "([^"]*)"$/) do |id|
  FactoryGirl.create(:ad, id: id)
end

When(/^the client makes a valid POST \/ads request with user_id: "([^"]*)"$/) do |user_id|
  post '/ads', valid_creation_params_for(:ad, user_id)
end

When(/^the client makes a POST \/ads request with blank title and user_id: "([^"]*)"$/) do |user_id|
  params = valid_creation_params_for(:ad, user_id).merge(title: '')
  post '/ads', params
end

When(/^the client makes a valid POST \/ads\/(\d+)\/offers with user_id: "([^"]*)"$/) do |ad_id, user_id|
  params = valid_creation_params_for(:offer, user_id)
  post "/ads/#{ad_id}/offers", params
end

When(/^the client makes a POST \/ads\/(\d+)\/offers request with blank price and user_id: "([^"]*)"$/) do |ad_id, user_id|
  params = valid_creation_params_for(:offer, user_id).merge(price: '')
  post "/ads/#{ad_id}/offers", params
end                                                                                                                  
Then(/^response should have status (\d+) and JSON:$/) do |status, json_string|
  expect(last_response.status).to be(status)
  expect(JSON.parse(last_response.body)).to eq(JSON.parse(json_string))
end

Now we are ready to deal with the error provided by Cucumber when running the Scenario:

    Then response should have status 422 and JSON:
      """
        {"errors": {"price": ["can't be blank"]}}
      """

      expected #<Fixnum:845> => 422
           got #<Fixnum:401> => 200

We’re still getting a success status because we don’t have any other possible path yet.
So, time to jump back to the OffersController spec. We can now add the following context:

# spec/controllers/offers_controller_spec.rb

  context 'with validation error' do
    before do
      offer.errors.add(:price, "can't be blank")
      expect(Offer)
        .to receive(:create!)
        .with(permitted_params)
        .and_raise(ActiveRecord::RecordInvalid.new(offer))
      execute_request
    end
    it_responds_with 'a unprocessable entity status'
    it_responds_with 'JSON body',
                     '{ "errors": {"price": ["can\'t be blank"] }}'
  end

We need to add the following shared context as well:

# spec/controller_shared_contexts.rb

shared_context 'a unprocessable entity status' do
  it { expect(response).to have_http_status(:unprocessable_entity) }
end

And we should be now have a green state within our OffersController spec. Let’s see what Cucumber has to say to us when executing the Scenario:

    Then response should have status 422 and JSON:    
      """
        {"errors": {"price": ["can't be blank"]}}
      """

      expected #<Fixnum:845> => 422
           got #<Fixnum:401> => 200

We get a success response again because we miss the model validation. Let’s write a spec for the Offer model:

require 'rails_helper'

RSpec.describe Offer, type: :model do
  it { should belong_to(:user) }
  it { should belong_to(:ad) }
  it { should validate_presence_of(:price) }
end

And update the model accordingly:

class Offer < ApplicationRecord
  belongs_to :user
  belongs_to :ad
  validates :price, presence: true
end

At this stage, everything should be green.

Refactoring the Resource Creation Pattern

Now, compare the two controllers and associated spec. They are pretty similar, right? Since our back is covered by all sort of tests, we can go on safely and try to refactor the pattern out of the controllers. Let’s introduce a module called ResourceController.

# app/concerns/resource_controller.rb

module ResourceController
  def create
    resource_name = controller_name.classify
    resource = resource_name.constantize.create!(permitted_params)
    render json: { message: "#{resource_name} created successfully", id: resource.id }
  rescue ActiveRecord::RecordInvalid => invalid
    render json: { errors: invalid.record.errors }, status: :unprocessable_entity
  end
end

We start by extracting the model name out of the controller using the classify method. Then, we get the actual resource by calling create! on the result of the constantize method (which transform the model name into a class).
The implementation also implies having a permitted_params method, which is the responsibility of the concrete controller itself to declare it. The rest is the logic you already know: we either render a successful response using the resource name and the created instance id, or we render an error response with the generated errors from the validation process.
Now, we can simplify the AdsController like this:

class AdsController < ApplicationController
  include ResourceController

  private

  def permitted_params
    params.permit(:title, :price, :description, :user_id)
  end
end

And run the tests to make sure everything is working as it was before. Since it does, we can do the same with the OffersController:

class OffersController < ApplicationController
  include ResourceController

private

def permitted_params
  params.permit(:message, :price, :ad_id, :user_id)
end

Good ! but we’re not quite over yet. Now that we’ve extracted the logic into a new module, we need cover it with its own spec. We basically have the main logic already, but since we are now testing a concern, we have to do some tweaks:

# spec/concerns/resource_controller_spec.rb

require 'rails_helper'

require 'controller_shared_contexts'

class Foo
  include ActiveRecord::Persistence
  include ActiveModel::Model
  attr_accessor :id, :bar
end
class FoosController < ApplicationController; end

RSpec.describe ResourceController, type: :controller do
  controller FoosController do
    include ResourceController

    def permitted_params
      params.permit(:bar)
    end
  end
  describe 'POST create' do
    include_context 'permit_params'
    let(:foo) { Foo.new(id: 1) }
    let(:params) { { bar: 'foo' } }
    let(:execute_request) { post :create, params: params }

    context 'with valid parameters' do
      before do
        expect(Foo)
          .to receive(:create!)
          .with(permitted_params)
          .and_return(foo)
        execute_request
      end
      it_responds_with 'a success status'
      it_responds_with 'JSON body',
                       '{ "message": "Foo created successfully", "id": 1 }'
    end
    context 'with validation error' do
      before do
        foo.errors.add(:bar, "can't be foo")
        expect(Foo)
          .to receive(:create!)
          .with(permitted_params)
          .and_raise(ActiveRecord::RecordInvalid.new(foo))
        execute_request
      end
      it_responds_with 'a unprocessable entity status'
      it_responds_with 'JSON body',
                       '{ "errors": {"bar": ["can\'t be foo"] }}'
    end
  end
end

First, we create a fake model with the ActiveRecord modules containing the methods that we need for our spec (typically, create! and initialize), as well as the attribute accessors. We could also directly inherit from ApplicationRecord but that would require to create a database table which we don’t need. Then, we create a FoosController to serve the model. We use it as context for our spec, and include the ResourceController module, and declare the permitted_params method. The rest is similar to the specs we’ve already created for the Ad and Offer models.

At this stage, we should remain 100% green. We can now delete the ad_spec.rb and offer_spec.rb files as we’re already covering the ResourceController module with what we have just written.

And that was it for the second part of the series. For the next one, we’ll focus on the retrieval of ads and offers.
If you have any remark, critiques or potential enhancements regarding the content of this article, don’t hesitate to let a comment !

Behavior-Driven Development of a Rails REST API With Cucumber and RSpec (Part I)

Some weeks ago, I’ve written an article on how to behavior-driven develop a SPA application using AngularJS and a completely mocked out back-end.
This time, I want to show you how to tackle the back-end side of things, through the development of a RESTful API using Rails 5 and an outside-in approach.
The tutorial will focus on a simplified marketplace application where users are able to create ads. We will specifically concentrate on the following use cases:

  • Users are able to create ads containing a title, a description and a price.
  • Users can make an offer to an existing ad, with a message and a price which can be different.
  • The client can retrieve all existing ads.
  • The client can retrieve an ad with its corresponding offers, sorted by price.

To simplify the process, we won’t go through the authentication of the user.
For the different tests, we will use Cucumber and RSpec. We’ll run on Rails 5, so if you haven’t upgraded yet, follow this link.

Setting up the Boilerplate

Let’s first create the application, using the –api parameter:

rails new marketplace --api -T

We also use -T in order to skip the creation of MiniTest dependencies which we won’t use.
Open up the Gemfile and setup the following gems, that we’ll use:

group :test do
  gem 'cucumber-rails', require: false
  gem 'rspec-rails'
  gem 'database_cleaner'
  gem 'factory_girl_rails'
  gem 'faker'
end

and run bundle install
Then, run the generate commands for both RSpec and Cucumber:

rails generate rspec:install
rails generate cucumber:install

Let’s also configure the test environment to use Factory Girl. Edit the config/environment/test.rb file and add the following line:

config.gem 'factory_girl'

Ad creation Feature

Let’s start with the ad creation feature. We want to be able to send a request to create an new ad, and if successful, get a response back containing the id of the created ad and a message saying “Ad created successfully”. We come up with the following Cucumber Feature:

Feature: Create an ad
  In order to sell an object
  I want to create an ad

  Scenario: using valid data
    Given a user with id "1" 
    When the client make a valid POST /ads request with user_id: "1"
    Then response should have status 200 and JSON:
    """
      {"message": "Ad created successfully", "id": "1"}
    """

You might first find this incorrect to find things like POST and user_id within a Feature file. Isn’t it supposed to be readable by all the involved stakeholders after all? well yes, but since the other party involved in this case is the consumer of the API, it is also another technical stakeholder. And we’re describing exactly what he’s supposed to do: make a POST request to a defined path, with a JSON containing fields like user_id.

So, when we now run the cucumber command on this, it will give us the following snippets, that we will put in a new file features/step_definitions/ad_steps.rb:

Given(/^a user with id "([^"]*)"$/) do |id|
  pending # Write code here that turns the phrase above into concrete actions
end

When(/^the client make a valid POST /ads request with user_id: "([^"]*)"$/) do |id|
  pending # Write code here that turns the phrase above into concrete actions
end

Then(/^response should have status (\d+) and JSON:$/) do |status, string|
  pending # Write code here that turns the phrase above into concrete actions
end

We will consider a valid request a one containing non-blank fields (title, price, description). The purpose of the first step is to consider the system provided with a user, having the id 1. We don’t know anything about the user apart from that, so let’s keep things simple:

Given(/^a user with id "([^"]*)"$/) do |id|
  FactoryGirl.create(:user, id: id)
end

Our next step is to create the actual User model:

rails generate model User

Let’s add the corresponding factory as well:

# spec/factories/users.rb

FactoryGirl.define do
  factory :user do
  end
end

now after a rake db:migrate, we should be able to make the first step pass. Let’s work on the request:

When(/^the client make a valid POST \/ads request with user_id: "([^"]*)"$/) do |id|
  params = FactoryGirl.attributes_for(:ad).merge(user_id: id)
  post '/ads', params
end

We use FactoryGirl to delegate the generation of the fields we don’t care about (we just want them to be valid). Let’s create an Ad model with the three fields we need:

rails generate model Ad title:string price:integer description:string
rake db:migrate

as well as the corresponding factory:

# spec/factories/ads.rb

FactoryGirl.define do
  factory :ad do
    title Faker::Lorem.word
    price Faker::Number.number(2)
    description Faker::Lorem.sentence
  end
end

After running cucumber again, we get the error:

No route matches [POST] "/ads" (ActionController::RoutingError)

Let’s fix this by editing the routes.rb file:

Rails.application.routes.draw do
  resources :ads, only: [:create]
end

This is the only path we need for now. Let’s now write enough code to make the second step path. If you now run cucumber again, it should complain about the missing AdsController. Let’s create it with an empty create action:

# app/controllers/ads_controller.rb

class AdsController < ApplicationController
  def create
  end
end

And that should make the second step pass. Now if we go further to the third step implementation, we come up with this:

Then(/^response should have status (\d+) and JSON:$/) do |status, json_string|
  expect(last_response.status).to be(status)
  expect(JSON.parse(last_response.body)).to eq(JSON.parse(json_string))
end

As you can see, we can use the last_response helper from Rack::Test available through Cucumber.
Since we want to capture a number for the status, we need to tell cucumber how to transform it into the correct format (captured as a string by default). We can use the Cucumber Transform helper for this. Add the following method to the step definitions file:

Transform /(\d+)$/ do |number|
  number.to_i
end

Now we need to implement the create action to provide the client with the response it expects:

class AdsController < ApplicationController
  def create
    Ad.create(ad_params)
    render json: { message: 'Ad created successfully', id: ad.id }
  end

  private

  def ad_params
    params.permit(:title, :price, :description, :user_id)
  end
end

Now, running cucumber again should provoke the following error:

unknown attribute 'user_id' for Ad. (ActiveModel::UnknownAttributeError)

We’re missing the association with the User model. Let’s work on this right now. First, generate the migration:

rails generate migration AddUserToAds user:references
rake db:migrate

Then, make the actual association between the Ad model:

class Ad < ApplicationRecord
  belongs_to :user
end

Let’s move on to the unhappy scenario (invalid data). We’ll take the blank title case. First, let’s move the Given step onto a Background section, since it’ll be common to the two scenarios:

  Background:
    Given a user with id "1"

Then, update the first scenario to remove the Given step

  Scenario: using valid data
    When the client make a valid POST /ads request with user_id: "1"
    Then response should have status 200 and JSON:
    """
      {"message": "Ad created successfully", "id": 1}
    """

And then add a second scenario:

  Scenario: using blank title
    When the client make a POST /ads request with blank title and user_id: "1"
    Then response should have status 422 and JSON:
    """
      {"errors": {"title": ["can't be blank"]}}
    """

We now have a new step we need to implement. Let’s first extract the parameters retrieve into a reusable method:

def valid_ad_creation_params(user_id)
  FactoryGirl.attributes_for(:ad).merge(user_id: user_id)
end

Then, implement the step like this

When(/^the client make a POST \/ads request with blank title and user_id: "([^"]*)"$/) do |id|
  params = valid_ad_creation_params(id).merge(title: '')
  post '/ads', params
end

Now, running cucumber provokes a failure at the statuses comparison:

expected #<Fixnum:845> => 422
     got #<Fixnum:401> => 200

We actually get a success response here. This is because we don’t have any validation yet. Let’s correct this in the Ad model:

class Ad < ApplicationRecord
  belongs_to :user
  validates :title, presence: true
end

We now need to modify the create method to handle the invalid model case. I think it’s a good time to introduce a unit tests for the Controller, since it’s starting to expand. Let’s add a spec file and start with the successful case:

# spec/controllers/ads_controller_spec.rb

require 'rails_helper'

RSpec.describe AdsController, type: :controller do
  describe 'POST create' do
    let(:params) { FactoryGirl.attributes_for(:ad).merge(user_id: '1') }
    let(:execute_request) { post :create, params: params }

    context 'with valid parameters' do
      before do
        ActionController::Parameters.permit_all_parameters = true
        permitted_params = ActionController::Parameters.new(params)
        expect(Ad)
          .to receive(:create)
          .with(permitted_params)
          .and_return(FactoryGirl.build(:ad, id: 1))
        execute_request
      end
      it 'returns a success response' do
        expect(response).to have_http_status(:success)
      end
      it 'returns returns success message with ad id' do
        expect(JSON.parse(response.body))
          .to eq(JSON.parse('{ "message": "Ad created successfully", "id": 1 }'))
      end
    end
  end
end

As you can see, we isolate the controller by explicitly setting the behavior of the Ad model, when receiving the create method. We basically want to avoid going into the actual validation process which is the responsibility of the model.
Now we need to handle the invalid parameters case.
We want to be notified whenever a validation problem occurs when creating a new Ad model. This is something we can’t actually get with the create method, which returns the instance of the model in both cases (valid and invalid). We can use create! instead which throws an ActiveRecord::RecordInvalid exception, along with the invalid record. Let’s do some preparatory refactoring first:

RSpec.describe AdsController, type: :controller do
  describe 'POST create' do
    let(:ad) { FactoryGirl.build(:ad, id: 1) }
    let(:params) { FactoryGirl.attributes_for(:ad).merge(user_id: '1') }
    let(:permitted_params) { ActionController::Parameters.new(params) }
    let(:execute_request) { post :create, params: params }

    before(:all) do
      ActionController::Parameters.permit_all_parameters = true
    end

    context 'with valid parameters' do
      before do
        expect(Ad)
          .to receive(:create)
          .with(permitted_params)
          .and_return(ad)
        execute_request
      end
      it 'returns a success response' do
        expect(response).to have_http_status(:success)
      end
      it 'returns returns success message with ad id' do
        expect(JSON.parse(response.body))
          .to eq(JSON.parse('{ "message": "Ad created successfully", "id": 1 }'))
      end
    end

Then, let’s implement the unsuccessful case, and stub out the call of create!:

    context 'with validation error' do
      let(:ad) { FactoryGirl.build(:ad, id: 1) }
      before do
        ad.errors.add(:title, "can't be blank")
        expect(Ad)
          .to receive(:create!)
          .with(permitted_params)
          .and_raise(ActiveRecord::RecordInvalid.new(ad))
        execute_request
      end
      it 'returns model validation errors' do
        expect(JSON.parse(response.body))
          .to eq(JSON.parse('{ "errors": {"title": ["can\'t be blank"] }}'))
      end
    end

Let’s edit the Controller create method like this:

  def create
    ad = Ad.create!(ad_params)
    render json: { message: 'Ad created successfully', id: ad.id }
  rescue ActiveRecord::RecordInvalid => invalid
    render json: { errors: invalid.record.errors }
  end

Here, we are catching the exception thrown by create! in case of invalid parameters and rendering a response containing the errors of the retrieved record.
Let’s add the expectation on the correct status:

      it 'returns unprocessable entity response' do
        expect(response).to have_http_status(:unprocessable_entity)
      end

And update the method accordingly:

  def create
    ad = Ad.create!(ad_params)
    render json: { message: 'Ad created successfully', id: ad.id }
  rescue ActiveRecord::RecordInvalid => invalid
    render json: { errors: invalid.record.errors }, status: :unprocessable_entity
  end

And this should make the unsuccessful case pass. Now let’s run a full rspec. You’ll notice that the two first tests are now failing:

Failures:

  1) AdsController POST create with valid parameters returns a success response
     Failure/Error: expect(response).to have_http_status(:success)
       expected the response to have a success status code (2xx) but it was 422
     # ./spec/controllers/ads_controller_spec.rb:23:in `block (4 levels) in <top (required)>'

  2) AdsController POST create with valid parameters returns returns success message with ad id
     Failure/Error: expect(JSON.parse(response.body))
       
       expected: {"message"=>"Ad created successfully", "id"=>1}
            got: {"errors"=>{"user"=>["must exist"]}}

The problem here is that we’re still stubbing out the wrong method: create instead of create!. This basically let the application go into the normal flow until the model validation mechanism. Here, we’re in front of the case where there is no user corresponding to the given id. This validation is ensured by the belongs_to keyword we used to describe the Ad model. This type of ‘wrong’ failure is actually good because it gives you confidence in the behavior of the application, even if it’s not a case we want to test directly. Let’s update the context:

    context 'with valid parameters' do
      before do
        expect(Ad)
          .to receive(:create!)
          .with(permitted_params)
          .and_return(ad)
        execute_request
      end
      it 'returns a success response' do
        expect(response).to have_http_status(:success)
      end
      it 'returns returns success message with ad id' do
        expect(JSON.parse(response.body))
          .to eq(JSON.parse('{ "message": "Ad created successfully", "id": 1 }'))
      end
    end


4 examples, 0 failures

What about our Cucumber tests?

2 scenarios (2 passed)
6 steps (6 passed)

So far so good. But we’re not completely done in terms of acceptance criteria. We’ve said that in order to be valid, an Ad needs to have non-blank title, description and price. We’ve put an expectation on the title, but not on the other fields.
What we can do now, is to write a spec file for the Ad model, and expect the actual presence validations. I know that a lot of developers find that doing this falls into over-testing because of the ridiculously inexpensive way Rails provides the validation mechanism. But how else do you make sure that this validation takes place? We certainly don’t want to test every single field validation error within slow Cucumber tests, but at the same time, we don’t want our suite to tell us that everything is fine, although the user could potentially create an ad without a description or price which would be a business rule violation.
Let’s use Thoughtbot’s shoulda gem which allows us to do this in a nice and cheap way. Add the gem into your Gemfile:

gem 'shoulda-matchers'

And run bundle install. Then, we need to configure Shoulda to integrate with both RSpec and ActiveRecord. Open up spec/rails_helper.rb and add the following lines

Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end

And we can now write the following spec file:

require 'rails_helper'

RSpec.describe Ad, type: :model do
  it { should belong_to(:user) }
  it { should validate_presence_of(:title) }
  it { should validate_presence_of(:description) }
  it { should validate_presence_of(:price) }
end

I have included the belong_to relation as well. The two first cases should actually already pass. Now let’s update the Ad model:

class Ad < ApplicationRecord
  belongs_to :user
  validates :title, presence: true
  validates :description, presence: true
  validates :price, presence: true
end

Which brings us to a fully green suite and accepted Feature.

That’s it for the first part! The next one will focus on the next requirement which is the placing of offers.
Don’t hesitate to leave a comment if you have any question / remark regarding the content.