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 alsoget
,patch
anddelete
method requestentries_url
is url pathparams
is request bodyassert_difference('Entry.count')
assert to make sure data is inserted to database if delete the assert would beassert_difference('Entry.count', -1)
Run test specific line
rails test test/models/entry_test.rb:4