Skip to content

Instantly share code, notes, and snippets.

@appwebd
Forked from mdang/RAILS_CHEATSHEET.md
Last active November 29, 2021 13:46
Show Gist options
  • Save appwebd/22e44b2f22832feaeb9a71df1b76b14e to your computer and use it in GitHub Desktop.
Save appwebd/22e44b2f22832feaeb9a71df1b76b14e to your computer and use it in GitHub Desktop.
[Ruby on Rails Cheatsheet english] #architecture #cheatsheet #lewagon #rails #ruby #workflow

Ruby on Rails Cheatsheet

Architecture

Getting Started with Rails

Setup instructions for Le Wagon's students on their first day of Web Development Bootcamp

Reference: https://github.com/lewagon/setup

Generate a new Rails app w/ Postgresql support

Jump start your Rails development with Le Wagon best practices

$ rails new \
  --database postgresql \
  --webpack \
  -m https://raw.githubusercontent.com/appwebd/rails-templates/master/devise.rb \
  CHANGE_THIS_TO_YOUR_RAILS_APP_NAME

Reference: https://github.com/lewagon/rails-templates

Reference: https://github.com/appwebd/rails-templates

Models

Generate a model and create a migration for the table (files in folder app/models/)

Note: Name models in Rails is Capital case and singular

$ rails g model Movie title:string description:text photo user:references

The migration automatically created for the above command:

class CreateMovies < ActiveRecord::Migration[6.1]
  def change
    create_table :movies do |t|
      t.string :title
      t.text :description
      t.string :photo
      t.references :user, null: false, foreign_key: true

      t.timestamps
    end
  end
end

Migrate of table to database

$ rails db:migrate

Reference: http://guides.rubyonrails.org/active_model_basics.html

Migrations

Migration Data Types

  • :boolean
  • :date
  • :datetime
  • :decimal
  • :float
  • :integer
  • :primary_key
  • :references
  • :string
  • :text
  • :time
  • :timestamp

When the name of the migration follows the format AddXXXToYYY followed by a list of columns, it will add those columns to the existing table

$ rails g migration AddDateTakenToMovies date_taken:datetime

The above creates the following migration:

class AddDateTakenToMovies < ActiveRecord::Migration[5.0]
  def change
    add_column :movies, :date_taken, :datetime
  end
end

You can also add a new column to a table with an index

$ rails g migration AddDateTakenToMovies date_taken:datetime:index

The above command generates the following migration:

class AddDateTakenToMovies < ActiveRecord::Migration[5.0]
  def change
    add_column :movies, :date_taken, :datetime
    add_index :movies, :date_taken
  end
end

The opposite goes for migration names following the format: RemoveXXXFromYYY

$ rails g migration RemoveDateTakenFromPhotos date_taken:datetime

The above generates the following migration:

class RemoveDateTakenFromPhotos < ActiveRecord::Migration[5.0]
  def change
    remove_column :photos, :date_taken, :datetime
  end
end

Models simple test in console

$ rails console
 rails c
 
Running via Spring preloader in process 23453
Loading development environment (Rails 6.1.4.1)
[1] pry(main)> 

Movie.new

=> #<Movie:0x00007ff0ccb7cbf8
 id: nil,
 title: nil,
 description: nil,
 photo: nil,
 user_id: nil,
 created_at: nil,
 updated_at: nil>
[2] pry(main)> 

movie_1 = Movie.create description: "Testing"


  TRANSACTION (0.2ms)  BEGIN
  Movie Exists? (0.4ms)  SELECT 1 AS one FROM "movies" WHERE "movies"."title" IS NULL LIMIT $1  [["LIMIT", 1]]
  TRANSACTION (0.2ms)  ROLLBACK
=> #<Movie:0x00007ff0ccaa3bf0
 id: nil,
 title: nil,
 description: "Testing",
 photo: nil,
 user_id: nil,
 created_at: nil,
 updated_at: nil>
[3] pry(main)> 

movie_1.valid?


  Movie Exists? (0.5ms)  SELECT 1 AS one FROM "movies" WHERE "movies"."title" IS NULL LIMIT $1  [["LIMIT", 1]]
=> false
[4] pry(main)> 

movie_1.errors.messages


=> {:user=>["must exist"], :title=>["can't be blank"]}
[5] pry(main)>

Model Associations

A doctor has many interns

Migration to create doctors

$ rails g model Doctors first_name last_name
# db/migrate/20141027100300_create_doctors.rb
class CreateDoctors < ActiveRecord::Migration[6.0]
  def change
    create_table :doctors do |t|
      t.string      :first_name
      t.string      :last_name
      t.timestamps
    end
  end
end

Migration to create interns

$ rails g model Interns first_name last_name doctor:references
# db/migrate/20141027100400_create_interns.rb
class CreateInterns < ActiveRecord::Migration[6.0]
  def change
    create_table :interns do |t|
      t.string      :first_name
      t.string      :last_name
      t.references  :doctor, foreign_key: true
      t.timestamps
    end
  end

Note the t.references

Always add foreign_key: true to enforce referential integrity

Create 2 models

# app/models/doctor.rb
class Doctor < ActiveRecord::Base
  has_many :interns
end
# app/models/intern.rb
class Intern < ActiveRecord::Base
  belongs_to :doctor
end

Read it:

  • A Doctor has_many interns
  • An Intern belongs_to a doctor

Create interns

doctor = Doctor.new(first_name: "Gregory", last_name: "House")
doctor.save

intern = Intern.new(first_name: "Allison", last_name: "Cameron")
intern.doctor = doctor
intern.save

Retrieve interns for a given doctor:

doctor = Doctor.last
doctor.interns
# => `Array` (`ActiveRecord::Relation`) of `Intern` instances

Let’s add patients / consultations table

Migration to create patients

$ rails g model Patients first_name last_name
# db/migrate/20141027114700_create_patients.rb
class CreatePatients < ActiveRecord::Migration[6.0]
  def change
    create_table :patients do |t|
      t.string      :first_name
      t.string      :last_name
      t.timestamps
    end
  end
end

Migration to create consultations

$ rails g model Consultations doctor:reference patient:reference
# db/migrate/20141027114800_create_consultations.rb
class CreateConsultations < ActiveRecord::Migration[6.0]
  def change
    create_table :consultations do |t|
      t.references :doctor, foreign_key: true
      t.references :patient, foreign_key: true
      t.timestamps
    end
  end
end

Create 2 new models

# app/models/patient.rb
class Patient < ActiveRecord::Base
  has_many :consultations
end
# app/models/consultation.rb
class Consultation < ActiveRecord::Base
  belongs_to :patient
  belongs_to :doctor
end

What about the Doctor model?

# app/models/doctor.rb
class Doctor < ActiveRecord::Base
  has_many :interns

  # Do not forget to add this! :)
  has_many :consultations
end

How can I retrieve patients for a given doctor?

doctor = Doctor.last

patients = []
doctor.consultations.each do |consultation|
  patient = consultation.patient
  patients << patient if !patients.include?(patient)
end

# => `Array` of `Patient` instances

Use :through

# app/models/doctor.rb
class Doctor < ActiveRecord::Base
  has_many :interns
  has_many :consultations

  has_many :patients, through: :consultations
end

Then you can do:

doctor = Doctor.last
doctor.patients
# => `Array` (`ActiveRecord::Relation`) of `Patient` instance

Models validations

Reference: [https://guides.rubyonrails.org/active_record_validations.html](Active record validations)

Reference: [https://guides.rubyonrails.org/active_record_callbacks.html#available-callbacks] (Active Record Callbacks)

Seed your database

First, install the faker gem by adding it to your list of gems in your gemfile.

# for finding the version number
gem search faker | grep '^faker ('

file: Gemfile
----

gem 'faker'  

---
# finally, do the following command in the DCL (DCL: Definition Command Language)
bundle install

In “db/seeds.rb”, create some movies:

# URL faker github page: https://github.com/faker-ruby/faker

require 'faker'

puts 'Removing all the database information...'

User.destroy_all
Movie.destroy all

puts 'OK database is empty'
puts "Generating 20 users"

# generate 10 users
(1..10).each do |id|
    User.create!(
                               # each user is assigned an id from 1-10   
        id: id, 
        name: Faker::Name.name,
        email: Faker::Internet.email,
                               # issue each user the same password
        password: "password", 
        password_confirmation: "password",
                               # a user can have only one of these roles
        role: %w[customer admin agent].sample 
    )
end

puts 'Creating a new movies ...'

url = "http://tmdb.lewagon.com/movie/top_rated"
10.times do |i|
  puts "Importing movies from page #{i + 1}"
  movies = JSON.parse(open("#{url}?page=#{i + 1}").read)['results']
  movies.each do |movie|
    puts "Creating #{movie['title']}"
    base_poster_url = "https://image.tmdb.org/t/p/original"
    Movie.create(
      title: movie['title'],
      overview: movie['overview'],
      poster_url: "#{base_poster_url}#{movie['backdrop_path']}",
      rating: movie['vote_average']
    )
  end
end

puts 'Was done (all the seed information was created)'

Reference: https://github.com/faker-ruby/faker


Routes

Create a route that maps a URL to the controller action

# config/routes.rb
get 'welcome' => 'pages#home'

Shorthand for connecting a route to a controller/action

# config/routes.rb
get 'movies/show'

# The above is the same as: 
get 'movies/show', :to 'movies#show'
get 'movies/show' => 'movies#show'

Automagically create all the routes for a RESTful resource

# config/routes.rb
resources :movies 

HTTP Verb Path Controller#Action Used for
GET /movies movies#index display a list of all movies
GET /movies_new movies#new return an HTML form for creating a new movie
POST /movies movies#create create a new movie
GET /movies/:id movies#show display a specific movie
GET /movies/:id/edit movies#edit return an HTML form for editing a movie
PATCH/PUT /movies/:id movies#update update a specific movie
DELETE /movies/:id movies#destroy delete a specific movie

Create resources for only certain actions

# config/routes.rb
resources :movies, :only => [:index]

# On the flip side, you can create a resource with exceptions 
resources :movies, :except => [:new, :create, :edit, :update, :show, :destroy]

Create a route to a static view, without an action in the controller

# config/routes.rb
# If there's a file called 'about.html.erb' in 'app/views/movies', this file will be 
#   automatically rendered when you call localhost:3000/photos/about
get 'movies/about', to: 'movies#about'

Checking routes in console

you can do in the console:

rails routes

Filtering movies routes

$ rails routes | grep movies

                  movies GET    /movies(.:format)              movies#index
                         POST   /movies(.:format)              movies#create
               new_movie GET    /movies/new(.:format)          movies#new
              edit_movie GET    /movies/:id/edit(.:format)     movies#edit
                   movie GET    /movies/:id(.:format)          movies#show
                         PATCH  /movies/:id(.:format)          movies#update
                         PUT    /movies/:id(.:format)          movies#update
                         DELETE /movies/:id(.:format)          movies#destroy
$

Reference: http://guides.rubyonrails.org/routing.html


Controllers

Generate a new controller

Note: Name controllers in Ruby on Rails are pluralized and capital case.

$ rails g controller Movies

Generate a new controller with default actions, routes and views.

$ rails g controller Movies index show

Reference: http://guides.rubyonrails.org/action_controller_overview.html

Scaffolding

Scaffolding is great for prototypes but don't rely too heavily on it: http://stackoverflow.com/a/25140503

$ rails g scaffold Movie path:string caption:text
$ rake db:migrate

Rake

View all the routes in an application

$ rake routes

Seed the database with sample data from db/seeds.rb

$ rake db:seed

Run any pending migrations

$ rake db:migrate

Rollback the last migration performed

NOTE: Be VERY careful with this command in production, it's destructive and you could potentially lose data. Make sure you absolutely understand what will happen when you run it

$ rake db:rollback

Path Helpers

Creating a path helper for a route

# Creating a path helper for a route
get '/movies/:id', to: 'movies#show', as: 'movies'
# app/controllers/movies_controller.rb
@movie = Movie.find(17)
# View for the action
<%= link_to 'Movie Record', movie_path(@movie) %>

Path helpers are automatically created when specifying a resource in config/routes.rb

# config/routes.rb
resources :movies
HTTP Verb Path Controller#Action Named Helper
GET /movies movies#index movies_path
GET /movies/new movies#new new_movie_path
POST /movies movies#create movies_path
GET /movies/:id movies#show movie_path(:id)
GET /movies/:id/edit movies#edit edit_movie_path(:id)
PATCH/PUT /movies/:id movies#update movie_path(:id)
DELETE /movies/:id movies#destroy movie_path(:id)

Asset Pipeline

Access images in the app/assets/images directory like this:

<%= image_tag "rails.png" %>

Within views, link to JavaScript and CSS assets

<%= stylesheet_link_tag "application" %> 
<%= javascript_include_tag "application" %>
<!-- Filenames are fingerprinted for cache busting -->
<link href="/assets/application-4dd5b109ee3439da54f5bdfd78a80473.css" media="screen"
rel="stylesheet" />
<script src="/assets/application-908e25f4bf641868d8683022a5b62f54.js"></script>

Reference: http://guides.rubyonrails.org/asset_pipeline.html

Form Helpers

Bind a form to a model for creating/updating a resource

Use this method if you're using strong params to protect against mass assignment

# app/controllers/photos_controller.rb
def new
  @movie = Movie.new
end
# ERB view
<%= form_for @movie, url: {action: "create"}, html: {class: "nifty_form"} do |f| %>
  <%= f.text_field :path %>
  <%= f.text_area :caption, size: "60x12" %>
  <%= f.submit "Create" %>
<% end %>
<!-- HTML output -->
<form accept-charset="UTF-8" action="/movie/create" method="post" class="nifty_form">
  <input id="movies_path" name="movie[path]" type="text" />
  <textarea id="movies_caption" name="movie[caption]" cols="60" rows="12"></textarea>
  <input name="commit" type="submit" value="Create" />
</form>

Create a form with a custom action and method

<%= form_tag("/search", method: "get") do %>
  <%= label_tag(:q, "Search for:") %>
  <%= text_field_tag(:q) %>
  <%= submit_tag("Search") %>
<% end %>
<form accept-charset="UTF-8" action="/search" method="get">
  <input name="utf8" type="hidden" value="&#x2713;" />
  <label for="q">Search for:</label>
  <input id="q" name="q" type="text" />
  <input name="commit" type="submit" value="Search" />
</form>

Reference: http://guides.rubyonrails.org/form_helpers.html


Views

Reference: https://uikit.lewagon.com/documentation

Reference: https://getbootstrap.com/docs/4.6/getting-started/introduction/

Reference: https://get.foundation/sites/docs/

Reference: https://tailwindcss.com/docs

Reference: https://bulma.io/documentation/


Other sources of information

Reference: [https://www.ruby-lang.org/en/documentation/] (Docuimentation in English)

Reference: [https://www.ruby-lang.org/es/documentation/] (Docuimentation in spanish)

Reference: [https://docs.ruby-lang.org/en/] (Documentation for Ruby classes and methods)

Reference: [https://guides.rubyonrails.org/](Ruby on Rails Guides)

Reference: [https://rubygems.org/] (Ruby Gems)

Reference: [https://github.com/heartcombo/devise] (Devise An authentication gem for Rails)

Reference: [https://github.com/tigrish/devise-i18n](devise-i18n github)

Reference: [https://github.com/varvet/pundit](pundit github)

Reference: https://www.rubydoc.info/gems/pundit/0.3.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment