Note When I Learn Ruby On Rails

Ruby on rails is one of the best full stack web framework, laravel took a lot of inspiration from it. This is my note when i learn rails, hopefully it will be useful for you if you want to learn rails too.

I learn it from this YouTube: https://www.youtube.com/watch?v=B3Fbujmgo60

Rails Command Line

Create new rails application

rails new foodlog

Generate rails CRUD Scaffolding

rails generate scaffold Entry field:type[string,integer,etc] 

Active record types

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

Or you can see from rails command line rails generate model -h

Delete generated controller

rails delete controller archives

Don't use

  • Do not use <%= when working with loop use <% instead

Syntax for render partials

Make sure to use <%= when working with one line erb

<%= render "shared/header" %>

Working with variable in erb

<% if notice.present? %>
   <p class="notification is-link is-light"><%= notice %></p>
<% end %>

Link in View

<%= link_to "View all entries", archives_index_path, class: "button is-link is-outlined is-centered" %>

Add customization on initialize rails app

You can add custom helper inside folder /config/initializers example time_format.rb

Time::DATE_FORMATS[:nice_date] = "%B %e, %Y"

Then we can use it in view like this

<%= DateTime.now.to_s(:nice_date) %>

Useful time helper in ruby

Make date more readable for human

<%= time_ago_in_words(model.created_at) %> ago // Logged 3 hour ago

Debugging Params in rails

<%= params %>

Example value would be like this

{"controller"=>"entries", "action"=>"show", "id"=>"1"}

Use do when wrapping link with child elements

<%= link_to entry_path(entry) do %>	...<% end %>

Grouping Model Collection

Setup the model first

class Entry < ApplicationRecord
    def day
        self.created_at.strftime("%b %e, %Y")
    end
end

Query on controller

@entries = Entry.all.group_by(&:day)

Consume it on the view

<% @entries.each do |day, entries| %>
    <% entries.each do | entry | %>
        ...
    <% end %>
<% end %>

Model Validation

Define attributes to validate in the model

class Entry < ApplicationRecord
    validates    :calories, :proteins, :carbohydrates, :fats, :meal_type, presence: true
end

Display error validation in the form

<%= form_with(model: entry) do |form| %>
    <% if entry.errors.any? %>
        <div class="message is-danger">
            <div class="message-header">
                <h2><%= pluralize(entry.errors.count, "error") %> prohibited this entry from being saved:</h2>
            </div>
            <div class="message-body">
                <ul>
                    <% entry.errors.each do |error| %>
                        <li><%= error.full_message %></li>
                    <% end %>
                </ul>
            </div>
        </div>
    <% end %>
    ...
<%end>

Updating Data from CLI

Run console

rails console

Get last entry

entry = Entry.last

Update the date to yesterday

entry.created_at = Date.yesterday

Save entry

entry.save

Rails Tests

Mock database done in fixtures it create in yaml file.

# tests/fixtures/entries.yml

breakfast:
  meal_type: "Breakfast"
  calories: 12
  proteins: 142
  carbohydrates: 101
  fats: 11

lunch:
  meal_type: "Lunch"
  calories: 21
  proteins: 311
  carbohydrates: 27
  fats: 95

Run db migration for test

bin/rails db:migrate RAILS_ENV=test

Then run the test

rails test test/controllers/entries_controller_test.rb

If you found error ActionView::Template::Error: Permission denied

Go to test/test_helper.rb comment out this line

# parallelize(workers: :number_of_processors, with: :threads)

Example test create entry

test "should create entry" do
  assert_difference('Entry.count') do
    post entries_url, params: { entry: { calories: @entry.calories, carbohydrates: @entry.carbohydrates, fats: @entry.fats, meal_type: @entry.meal_type, proteins: @entry.proteins } }
  end

  assert_redirected_to entry_url(Entry.last)
end

Explanation

  • post is POST request there is also get , patch and delete method request
  • entries_url is url path
  • params is request body
  • assert_difference('Entry.count') assert to make sure data is inserted to database if delete the assert would be assert_difference('Entry.count', -1)

Run test specific line

rails test test/models/entry_test.rb:4