Rails

new rails project

rails new <project_name>

start rails server

rails s

routing

in config/routes.rb

Rails.application.routes.draw do
    # root route is special
    root 'articles#index'

    # non-root route like this
    # trigger `index` action in `articles` when GET request on `articles`
    get 'articles', to: 'articles#index'
    
    # route with variable use `:`
    # the variable is passed to controller in the hash `params`
    # in this case `params[:id]`
    get 'articles/:id', to: 'articles#show'

end

more

resourceful routing

Rails.application.routes.draw do
    resources :articles
end

this map route

URI patterncontroller#action
articlesarticles#index
articles/newarticles#new
articles/:idarticles#show
(POST) articlesarticles#create
articles/:id/editarticles#edit
(PATCH) article/:idarticles#update
(DELETE) article/:idarticles#destroy

and set up URL and path helper method

methodreturn
article_path“articles/#{article.id}”

model

in app/models

  • singular name

generate model

generate model Article with two field

rails g model Article title:string body:text
  • also generate database migration

generate and save new model object

# generate new article object
article = Article.new(title: 'Example', body: 'Example text.')

# save to database
article.save # => true

update model object

article.update # => true

validation of model object when save or update

# declare a `article_params` method to validate
def article_params
    params.require(:article).permit(:title, :author, :body, :status)
end

# use the method when try saving or updating
if @article.update(article_params)
    redirect_to @article
else
    render :edit, status: :unprocessable_entity
end

query model object from database

# query article by id
Article.find(1) # => 1 Article object or Nil

# query all articles
Article.all # => 1 ActiveRecord::Relation object

view

in app/views

html.erb file

embedded Ruby in HTML

  • run ruby code

    <% … %>
    
  • run ruby code and render the return value

    <%= … %>
    
  • write comment that does not render in result

    <%# comment %>
    

access instance variable in view

<ul>
    <% @articles.each do |article| %>
        <li>
            <%= article.title %>
        </li>
    <% end %>
</ul>
  • product a link with some_text to article_path

    <%= link_to some_text, article %>
    
  • redirect to show a model object

    redirect_to @article
    
    • the browser make a new request
    • use redirect_to to mutate database
  • render image

    <%= image_tag image_path %>
    
  • link to the same page with different params

    <%= link_to some_text,
      url_for(params.permit!.merge(field_to_change: field_value)) %>
    

partial template

partial has name starting with _

e.g.

_form.html.erb

access partial template from another view

<%= render 'comments/form' %>
  • relative path without _

  • add argument

    render 'form', article: @article
    
    # or the longer format
    render partial: 'form', locals: { article: @article }
    
    # or even longer format
    render partial: 'form', object: @article, as: 'article'
    
  • render a collection

    render @products
    
    # or longer format
    render partial: 'product', collection: @products    
    

    or even longer format

    <% @products.each do |product| %>
        <%= render partial: "product", locals: { product: product } %>
    <% end %>
    

controller

in app/controllers

controller for articles is articles_controller.rb

  • plural name

generate controller

generate ArticlesController and its index action

rails g controller Articles index

by default, index action of Articles render app/views/articles/index.html.erb

instance variable in controller

instance variable in controller can be accessed in view

# this will be accessed in `articles/index.html.erb`
    def index
        @article = Article.all
    end

controller method for resourceful routing

index method in controller

show method in controller

need to query model object by params[:id]

new method in controller

only initialize new model object

create method in controller

assign value to new model object and attempt to save it

def create
    @article = Article.new(title: '…', body: '…')
    if @article.save
        redirect_to @article
    else
        render :new, status: :unprocessable_entity
end
  • strong parameter

database

SQLite3 by default

migration

in db/migrate

rails db:migrate

console

open a rails irb console

rails console

Hotwire

Turbo

Turbo events