Ruby on Rails 5 Essential Training: https://www.lynda.com/Ruby-Rails-tutorials/Ruby-Rails-5-Essential-Training/500551-2.html
Notice: Record every problem when i learned ruby on rails. I hope my experience can help you to learn ruby on rails better.
name is simple_cms, use mysql database
Use "mysql.server start" to start the server of mysql;
The default password of the root is blank, just type "Enter" will be OK.
Use "GRANT ALL PRIVILEGES ON simple_cms_test.* TO 'rails_user'@'localhost' IDENTIFIED BY 'secretpassword';";
simple_cms_test is the name of database, rails_user is the name of user,
localhost is the server of the user, secretpassword is the password of this database
(c) After changing the username and password in database.yml, using "rails db:schema:dump" to connect to the data base and dump to the text, get "rails aborted! Mysql2::Error: Access denied for user 'rails_user'@'localhost' ..."
Made mistake when setting the password in database.yml file, set the password as "secretspassword", the password set in the mysql is "secretpassword". Foolish mistake.
Start: rails s
Stop: control + c
Create a controller named 'demo' with an action named 'index'(the name of views).
'demo' is the folder name, 'index' is view template name.
Use "localhost:3000/demo/index" can check this view in the controller
web server first looks for a matching file on the public folder.
in browser, input "localhost:3000/demo/static_page.html" can visit this page
get ':controller(/:action(/:id))'
root 'demo#index', tells which controller and action should route to.
In app/controllers/demo_controller.rb, use:
def index
render('hello')
end
so when you visit /demo/index, you will view the template of "hello.html.erb".
render(:template => 'demo/hello')
It need the combination of config/routes.rb and apps/controllers/demo_controller.rb.
in routes.rb:
def other_hello
redirect_to(:action => 'hello')
end
in demo_controller.rb
get 'demo/other_hello'
the routes parse the address of browser and get other_hello string and send it to controller to handle it.
In demo_controller.rb, define an instance variable like this followed by @,
def hello
@array = [1,2,3,4,5]
render('hello')
end
In hello.html.erb, we can use this array like:
<% @array.each do |n|>
the link in ruby on rails like this: <%= link_to(text, target) %>
<%= link_to("one link", {:action => 'index'}) %>
aa) In index.html.erb, construct a url link with parameters:
<%= link_to('Hello with parameters', {:action => 'hello', :page => 5, :id => 20}) %><br />
bb) In demo_controller.rb, fetch the parameters in url:
@id = params[:id]
@page = params[:page]
these instance variables can be used in templates
cc) In hello.html.erb, display this paramters:
ID: <%= @id %>
ID: <%= params[:id] %>
rails generate migration DoNothingYet
aa) rails generate model User,
get an xxx_create_users.rb in db/migrate
bb) t.column "first_name", :string, :limit => 25
database = application
table = model
column = attribute of model
Forget to start mysql server.
aa) rails -u rails_user -p simple_cms_development
bb) SHOW TABLES;
cc) SHOW FIELDS FROM users;
down: rails db:migrate VERSION=0;
use 'rails db:migrate:status' to find the version you want to up;
up: rails db:migrate VERSION=...;
schema file will keep track the version
These names should be sync, for example:
file name: admin_user.rb
classe name: class AdminUser < ApplicationRecord
table name: admin_users
Use 'rails console' to access rails console.
Then we can use activerecord of the table, eg:
subject = Subject.new
subject.name = 'test'
aa) subject = Subject.new(:name => "First Subject", position: 1, visible: true, created_at: nil, updated_at: nil)
it does not save automatically
bb) subject = Subject.create(:name => "Second Subject", :position => 2)
it save the record automatically
aa) subject = Subject.find(1)
subject.name = "Initial Subject"
subject.save
it does not save automatically
bb) subject = Subject.find(2)
subject.update_attributes(:name => "Next Subject", :visible => true)
it save the record automatically
subject = Subject.find(3)
subject.destroy
This record will be deleted from database
aa) subject = Subject.find(1)
bb) subject = Subject.find_by_name("Initial Subject")
cc) subjects = Subject.all
aa) subject = Subject.where(:visible => true)
bb) subject = Subject.where("visible = true")
cc) subject = Subject.where(["visible = ?", true])
aa) subjects = Subject.order(:position)
bb) subjects = Subject.order("position ASC")
cc) subjects = Subject.limit(1).offset(2)
In app/models/subject.rb, we can define some named scopes, these variable can be used in rails console. eg:
scope :visible, lambda { where(:visible => true) }
scope :invisible, lambda { where(:visible => false) }
scope :sorted, lambda { order("position ASC") }
scope :newest_first, lambda { order("created_at DESC") }
scope :serach, lambda { |query| where(["name LIKE ?", "%#{query}%"])}
in rails console, we can use like this:
Subject.invisible
in subjec.rb: has_one :page
in page.rb: belongs_to :subject
subject = Subject.find(1)
first_page = Page.new(...)
subject.page = first_page
subject.page = nil
subject.page.destroy
in subject.rb: has_many :pages
in page.rb: belongs_to :subject
subject.pages << first_page
subject.pages << second_page
subject.pages.delete(second_page)
aa) Create a join table
generate migration CreateAdminUsersPagesJoin
in /dbmigrate file:
class CreateAdminUsersPagesJoin < ActiveRecord::Migration[5.1]
def up
create_table :admin_users_pages, :id => false do |t|
t.integer "admin_user_id"
t.integer "page_id"
end
add_index("admin_users_pages", ["admin_user_id", "page_id"])
end
def down
drop_table :admin_users_pages
end
end
the name of the page is admin_users_pages
bb) set relationship
in admin_user.rb: has_and_belongs_to_many :pages
in page.rb: has_and_belongs_to_many :admin_users
cc) build relationship
me.pages << first_page
aa) rails generate model SectionEdit
bb) in db/migrate file:
class CreateSectionEdits < ActiveRecord::Migration[5.1]
def up
create_table :section_edits do |t|
t.integer "admin_user_id"
t.integer "section_id"
t.string "summary"
t.timestamps
end
add_index("section_edits", ['admin_user_id', 'section_id'])
end
def down
drop_table :section_edits
end
end
cc) rails db:migrate
dd) in admin_user.rb:
has_many :section_edits
in section.rb:
has_many :section_edits
in section_edit.rb
belongs_to :admin_user
belongs_to :section
ee) edit = SectionEdit.new(:summary => "test edit", :admin_user => me, :section => section)
by using through
aa) in admin_user.rb: has_many :sections, :through => :section_edits
bb) in section.rb: has_many :admin_users, :through => :section_edits
cc) me.sections
(a) Create a controller with CRUD action.
rails generate controller Subjects index show new edit delete
aa) create a controller named SubjectController
in this file, it added some actions:
def index
end
...
bb) create a view folder named subjects
this folder contains this correspoding views such as delete.html.erb ...
cc) create corresponding routes in routes.rb
such as: get 'subjects/delete'
index - get
show - get
new - get
create - post
edit - get
update - patch
delete - get
destroy - delete
delete get 'subjects/delete' and add code:
resources :subject do
member do
get :delete
end
end
this block of code add delete action
aa) in url use /subjects
bb) Rails took the url and determine to use resourceful routes SubjectsController#index
cc) in subjects_controller, in index action, it operate some operations, the default render it to 'index.html.erb'
dd) in 'index.html.erb' view, show corresponding info
ee) the view sends back to the browser
aa) index.html.erb
<%= link_to("Show", subject_path(subject), :class => 'action show') %>
or
<%= link_to("Show", {:controller => "subjects", action => "show", :id => "subject.id"}, :class => 'action show') %>
bb) subjects_controller.rb
def show
@subject = Subject.find(params[:id])
end
use instance variable and get parameter from url
cc) show.html.erb
use @subject to use the instance variable