Rails Note and Cheatsheet

Kuroun Seung
5 min readJan 29, 2018

--

Catastrophic Consequence of Prepared Statement in Rails < 5

Rails 5 Routes: Nest resources and shallow option

Whether you shallow on action new, create, index or not, it is still not shallow. For example:

resources :users do 
resources :payments, only: %i(create), shallow: true
end
resources :users do
resources: :payment, only: %i(create), shallow: true
end

will produce the same routes:

user_payments POST /users/:user_id/payments(.:format) payments#create

present? vs any? vs exist?

  • In Rails 4, present? retrieves all records. any? counts record. exists? retrieves one record. Always use exists? though.
  • any? and exists? in Rails 5 is the same thing.

Don’t confuse with file? or present? vs exists? in rails paper clip. file? or present? check if there is paper clip object while exists? performs TCP connection to cloud storage to check if file exists. In this case, file? or present performance much better but use exists? if only you want to check file exist in the cloud storage.

Postgresql Time Zone

  • Always use timezone across database server as UTC and don’t dare to switch time zone to anywhere else even even you change database location. With this golden rule, you don’t have to care if you use timestamp or timestamptz.
  • No matter how many applications you access to database server, no matter how you config time zone at application server, always persist timestamp in UTC.

How to start conversation. First what is your timezone? Is it in UTC? Otherwise, conversation is terminated.

includes and eager_load

include will make multiple queries but with some condition where on included resources, includes will make single query. However we can force includes to use single query by adding references. On the other hand, eager_load will always make single query with or without some condition where on included resources. Thus, why do Rails have single query and multiple queries strategy? Using single query when small data set OR with some condition where. Using multiple queries when large data set AND without condition where. On the order hand, preload is not smart as includes , it will use multiple queries strategy to load data, while includes will swap to use single query left outer join if there are condition where or order.

Two kind of strategies to store session in Rails

  1. Cookie store: store all data in the cookie
  2. Everything else (memory store and database store): Store a pointer to data in the cookie

The user of `:inverse_of`

  • Memory optimization, no necessary query to database
  • Creating child nest attributes with the validation of presence of its parent
  • Auto creating join model in has_many :through

Request caching > object memoization

It is a wake up call ever to understand the what is actually request caching differs from object memoization. Request caching works like caching the result of request in the memory and and then if there is the same request, it won’t query database call again. It will retrieve result from memory and it needs to expire sometimes.

Unlike object memoization, in Rails object life cycle along with request, so per request Rails can instantiate many objects in the memory and those objects life cycle will end after a request ends too. Similarly, object can be memoized in the memory too. During a request, if object that make database call is already instantiated, it won’t be instantiated again, because it is memoized in the memory. Because of object life cycle is short, it is normally not to be expired.

Even request caching and object memoization is technique in different context, but they generally use the same data structure such as hash to store key and value in the memory.

Rails Funny and Weird Learning

With save, if something went wrong, it quietly cancels saving. Unlike, bang save (save!) cancels saving loudly with error exception. To me, Save! save me life.

Two types of debug: application level and service level (nginx, database…etc.). Thus, don’t just debug your application. Occasionally debug your system. Maybe it is memory leaking…You won’t know!

Rails App Optimization

Pagination, Caching, Background jobs

Rails has a great love to RESTful web service

Why REST?

  • give API for free
  • simplicity and convenience
  • turn code into resource
  • HTTP verbs

PUT vs PATCH

  • use PUT to replace resource
  • use PATCH to update resource
  • Rails uses PATCH rather than PUT

HTTP status codes

  • 1xx : information
  • 2xx: success
  • 3xx: redirect
  • 4xx: client error
  • 5xx: server error

API in Rails

  • use namespace to keep controllers organized (module API….)
  • write API integration test with ActionDispatch::IntegrationTest
  • status: 200 == status: ok
  • Try CURL
  • Try JBuilder gem
  • Try http_accept_languae gem
  • We should use empty session because REST API is stateless:
  • protect_from_forgery with: :null_session

API versioning

  • URL versioning: namespace on route
  • test with assert_generate (ActionDispatch::IntegrationTest)
  • module on controller
  • Try versionist gem
  • 2 ways to version API:
  1. Add version to URL
  2. Add version to request header

API Authentication

  • Basic Auth: Basic + base64 encoding (not encrypted)
  • use authenticate_with_http_basic method
  • custom realm
  • http token: it is more secure and flexible than basic auth because it can be expired or generated base on client user.
  • In the header: token = abc123…789xyz
  • digest authentication: work like basic auth but the user name and password are encrypted during communication.
  • Oauth (Open Authorization): is better because it works same as user login/out. Oauth with Doorkeeper or Oauth2. Allow provider to give access to users without exchange of credentials. User does not have problem when provider changes password. Oauth has client_id, token_secret, access_token. Try omni_auth gem: use at client application. Try oauth2 gem

Oauth Token

Token is the key that mobile app uses to request resource from resource server. There are two types of token, access token and refresh token.

How token get generate?

  1. A client (third party, mobile app) requests a token.
  2. An issuer issues a token.
  3. A resource server consumes a token (has a trust relationship with the issuer).

What is Token?

Tokens represent specific scopes and durations of access, granted by the resource owner , and enforced by the resource server

API Best Practice

We should better handle unauthorized request by not halting the request. Instead we should return the boolean check and create method to handle the unauthorized request gracefully. For example, 401 is unauthorized code.

Service Object in Rails

A service object’s job is to hold the code for a particular bit of business logic. ~ DAVE COPELAND, from Anatomy of a Rails Service Objects.

--

--