DHS / 13 May 2019
Active Record
Active Record is the M in MVC - the model - which is the layer of the system responsible for representing business data and logic. Active Record facilitates the creation and use of business objects whose data requires persistent storage to a database. It is an implementation of the Active Record pattern which itself is a description of an Object Relational Mapping system.
Active Record Pattern
In Active Record, objects carry both persistent data and behavior which operates on that data. Active Record takes the opinion that ensuring data access logic as part of the object will educate users of that object on how to write to and read from the database.
ORM (Object Relational Mapping)
Object Relational Mapping, commonly referred to as its abbreviation ORM, is a technique that connects the rich objects of an application to tables in a relational database management system. Using ORM, the properties and relationships of the objects in an application can be easily stored and retrieved from a database without writing SQL statements directly and with less overall database access code.
Buffet / 10 May 2019
Để xem “gia phả” của một class => gọi hàm ancestors
của class đó. Mảng trả về chứa thông tin theo thứ tự sau:
- calling class
- Module mà class đó include
- Ông già của class đó
- Module mà ông già của class đó include
- Ông già của ông già của class đó (ông nội :v)
Ví dụ:
irb> String.ancestors
=> [String, Comparable, Object, Kernel, BasicObject]
Buffet / 09 May 2019
Concern là gì
Concern thực chất là các đoạn code được tách nhỏ ra cho phép chúng ta có thể tổ chức code một cách mạch lạc, “sạch sẽ” hơn.
Chức năng của Concern
Chức năng của Concern = Module + extends methods in included callback
Module cho phép gom methods lại thành nhóm và sau đó các methods này được sử dụng bằng cách include module chứa chúng vào trong module/class khác.
# ../model/concerns/engine.rb
module Engine
def start_engine
"Jarvis, start the engine!"
end
end
# ../model/tank.rb
class Tank < ActiveRecord::Base
include Engine
def run
"I'm running."
end
end
# ../model/iron_man.rb
class IronMan < ActiveRecord::Base
include Engine
def snap_fingers
"I am Iron Man!"
end
end
Sử dụng
$ rails c
$ puts Tank.new.start_engine
Jarvis, start the engine!
$ puts IronMan.new.start_engine
Jarvis, start the engine!
Hạn chế của việc class include module đó là class đó chỉ có thể truy cập tới instance methods của module mà không thể truy cập tới các class methods
Một cách giải quyết là ta nhóm các class methods trong một module khác và extend nó trong included callback, đồng thời trong callback này, có thể viết các method về validates, quan hệ, scope.. để các model có thể tái sử dụng
# ../model/concerns/engine.rb
module Engine
def self.included klass
klass.extend ModuleMethods
klass.class_eval do
has_one :piston
validates :engine_type, presence: true
end
end
module ModuleMethods
def missile_launch
"Fire!!"
end
end
def start_engine
"Jarvis, start the engine!"
end
end
# ../model/tank.rb
class Tank < ActiveRecord::Base
include Engine
end
# ../model/iron_man.rb
class IronMan < ActiveRecord::Base
include Engine
end
$ rails c
$ puts IronMan.new.start_engine #OK
$ puts IronMan.missile_launch #OK
Refactor lại 2 ví dụ trên sử dụng Concern
# ../model/concerns/engine.rb
module Engine extend ActiveSupport::Concern
included do
has_one :piston
validates :engine_type, presence: true
def start_engine
"Jarvis, start the engine!"
end
class << self
def missile_launch
"Fire!!"
end
end
end
end
# ../model/tank.rb
class Tank < ActiveRecord::Base
include Engine
end
# ../model/iron_man.rb
class IronMan < ActiveRecord::Base
include Engine
end
Giải quyết vấn đề về dependency
Trong ví dụ sau, module Bar sẽ phụ thuộc và module Foo, để sử dụng module Bar, cần include đồng thời cả Foo lẫn Bar trong class Test:
# test_dependency.rb
module Foo
def self.included base
base.class_eval do
def self.method_of_foo
puts "inside method of Foo"
end
end
end
end
module Bar
def self.included base
base.method_of_foo
end
end
class Test
include Foo # Cần include module này do module Bar phụ thuộc vào module Foo
include Bar # Bar mới là module thực sự cần dùng
end
Khá là vô lý khi sử dụng một module mà còn phải quan tâm xem nó phục thuộc vào module nào khác nữa. Vì vậy có thể thử include trực tiếp module Foo trong module Bar
# test_dependency_fail.rb
module Foo
def self.included base
base.class_eval do
def self.method_of_foo
puts "inside method of Foo"
end
end
end
end
module Bar
include Foo
def self.included base
base.method_of_foo
end
end
class Test
include Bar
end
==> gây lỗi undefined method 'method_of_foo' for Test:Class
, bởi trong hoàn cảnh này, base
là Bar chứ không phải class Test, nên chương trình sẽ không thực hiện đoạn code trong block base.class_eval
Giải quyết vấn đề này bằng việc dùng Concern
# test_dependency_success.rb
require "active_support/concern"
module Foo extend ActiveSupport::Concern
included do
class << self
def method_of_foo
puts "inside method of Foo"
end
end
end
end
module Bar extend ActiveSupport::Concern
include Foo
included do
self.method_of_foo
end
end
class Test
include Bar # Class Test không quan tâm đến các module mà Bar phụ thuộc nữa
end
DHS / 08 May 2019
Asset pipeline là gì
Asset pipeline cung cấp việc concatenate và minify/compress JavaScript, CSS assets (Cũng có thể là CoffeeScript, Sass và ERB).
Mặc định nó đã có sẵn, có thể disable nếu không muốn dùng.
Lợi ích
- Concatenate
- combine thành 1 file => browser chỉ tốn 1 request để get assets
- dùng fingerprint để tạo unique name cho mỗi file sau khi nối => cache hiệu quả hơn
- Minification or compression
- xóa space, comment… để giảm size của file assets
- Precompilation
- dịch bọn scss, coffee… thành css và js để dùng
Bonus:
Fingerprint là kỹ thuật sử dụng nội dung của file để tạo ra tên file unique, hỗ trợ cho caching.
Khi nội dung file thay đổi thì tên file cũng thay đổi.
Ví dụ: application.css sẽ được đổi tên thành
application-908e25f4bf641868d8683022a5b62f54.css
Đoạn hex kia đc gen ra bằng MD5 hexdigest từ nội dung của file.
DHS / 06 May 2019
All about ruby arguments
Minh / 22 Apr 2019
Request: Browser -> Nginx -> Puma/Unicorn -> Rack (Middleware) -> Routing -> Controller (-> Model) -> Views -> Controller (response được tạo ra)
Response: Controller -> Routing -> Rack (Middleware) -> Puma/Unicorn -> nginx -> Browser
Tại sao cần cả Nginx và Puma/Unicorn
- Nginx gọi là web server. Puma/Unicorn gọi là Application server
- Tầng nginx thường sử lý để redirect
- Nginx viết bằng C nên rất nhanh
- Những request động cần vào server thì redirect request vào Puma/Unicorn
- Những request tĩnh, ví dụ 404.html, 500.html, images tĩnh v.v, /public (phân biệt với /public ở Rails app) mà không cần khởi động application server (giả sử App server chết thì nginx vẫn trả về trang 500.html cho người dùng được)
- http redirects to https
- Xử lý multi threads, bundle nhiều request vào file gửi cho Puma/Unicorn hiệu quả về performance hơn
- nginx xử lý DDos attack
- Tầng Puma/Unicorn
- App server là thứ thật sự “chạy” app của bạn, chạy ở đây tức là load code và lưu nó ở trong memory.
- Trong khi nginx không cần thiết ở môi trường development, application server bắt buộc ở cả môi trường dev/prod
Rack là gì
Tại sao cần Rack
Nói 1 cách đơn giản, Rack là bridge giữa App server và Rails app. Vì mỗi app server có thể nói 1 ngôn ngữ khác nhau. Nên cần 1 thằng ở giữa để dịch.
Ví dụ:
Puma gửi request object (Array) -> Rack -> Rails -> Rack nhận response object, parse thành Array -> Puma
Unicorn gửi request object (Hash) -> Rack -> Rails -> Rack nhận response object, parse thành Hash -> Unicorn
Viết 1 Rack app đơn giản
class ComplimentApp
def call(request)
[200, {'Content-Type' => 'text/plain'}, ["I like your shoes"]]
end
end
- Rack app bắt buộc phải có method
call
- ở ví dụ này return 1
Array
có 3 phần từ (phù hợp với format của Puma, mỗi App server có những quy định riêng về kiểu trả về, format của kiểu trả về).
- Puma quy định phần tử thứ nhất là HTTP status code
- Phần tử thứ 2 là 1 hash, giá trị của HTTP headers
- Phần tử thứ 3 là 1 object
response_to
method each
, chính là body
của response
Rack endpoint
Endpoint (đích đến) của Rack, tức là Rails Application được định nghĩa ở file config.ru
require_relative 'config/environment'
run Rails.application
Rails.application
return instance của Rails App class, Rails App class lại được định nghĩa ở application.rb
module PLServer
class Application < Rails::Application
end
end
trường hợp này là return instance của PLServer::Application
class. PLServer::Application
kế thừa từ Rails::Application
, một rack App. Rails::Application
implement phương thức #call
(nói ở trên)
def call(env)
req = build_request env
app.call req.env
end
env ở đây không phải biến môi trường ENV, nó chính là request object
Rack Middleware
Là một thành phần trong Rack. Có 2 nhiệm vụ:
- Sửa env object trước khi được pass vào endpoint tiếp theo
- Sửa response object trước được pass vào endpoint tiếp theo
Sau khi request đi qua khoảng 200 middleware objects, nó sẽ vào Router
Routing
router dispatch request vào controller và action tương ứng
ở bước này thì đã có 1 empty response object được tạo ra rồi
controller_class.dispatch(action, request, response)
Controllers
- chạy before_action
- logic trong action
- view rendering, stored in
response.body
,
- after_action
Rời controllers
- chạy after_action
response.to_a
convert response object thành một array mà Rack hiểu được
Rời routing
Routing dơn giản là sẽ pass response của controller vào Middleware, trừ khi response.headers
include X-Cascade: pass
. Khi đó Routing sẽ dispatch response object này sang một App khác chẳng hạn,
Vì dụ NodeJS app
Rời Middleware
Middleware có thể sửa status code, headers, body ở phase này. Ví dụ:
- xóa toàn bộ response body nếu có
HTTP caching headers
- set/edit cookie in response header
Rails as backend, JS framework as frontend
Gỉa sử ta có 2 server, 1 server chạy Rails, serve APIs, một server chạy JS Framwork như là React, VueJS, v.v,
Rails app: api.example.com, Front-end app: front.example.com
Tại frontend server, phải fetch dữ liệu từ backend server thông qua API. Khi đó ta sẽ gặp phải vấn đề Cross-Origin Resource Sharing (CORS)
Để giải quyết vấn đề này, đơn giản nhất là dùng gem:
gem "rack-cors", require: "rack/cors"
Bản chất của gem này là insert một middleware vào đầu tiên trong danh sách middleware stack để modify header của các request từ JS front server.
module MyApp
class Application < Rails::Application
config.middleware.insert_before 0, "Rack::Cors" do
allow do
origins 'front.example.com'
resource '/api/v1',
:headers => :any,
:expose => ['X-User-Authentication-Token', 'X-User-Id'],
:methods => [:get, :post, :options, :patch, :delete]
end
end
end
end
Minh / 22 Apr 2019
Trong OOP có 4 khái niệm là:
- Abstraction (trừu tượng)
- Polymorphism (đa hình)
- Inheritance (kế thừa)
- Encapsulation (Bao đóng)
Cách nhớ là: 4 kí tự đầu tiên tạo thành chữ: A PIE
Bài này nói về Tính kế thừa: Inheritance
Trong OOP nói chung
- Class Con sẽ kế thừa những thuộc tính, phương thức, constants của class Cha, class Ông
- có thể override
super
trong method Con sẽ gọi method cùng tên trong class Cha, không tìm thấy thì sẽ tìm đến Ông, v.v
Trong Rails nói riêng
Model kế thừa từ ApplicationRecord
ApplicationRecord kế thừa từ ActiveRecord::Base
Minh / 22 Apr 2019
Trong OOP có 4 khái niệm là:
- Abstraction (trừu tượng)
- Polymorphism (đa hình)
- Inheritance (kế thừa)
- Encapsulation (Bao đóng)
Cách nhớ là: 4 kí tự đầu tiên tạo thành chữ: A PIE
Bài này nói về Tính bao đóng: Encapsulation
Trong OOP nói chung
- giữ tất cả thuộc tính, giá trị của object nằm trong object
- viết các phương thức setter, getter cho từng thuộc tính, giá trị chỉ khi có nhu cầu sử dụng
Trong Rails nói riêng
Ứng dụng 1 trong Rails
- sử dụng
attr_reader
, attr_writer
, and attr_accessor
để access vào phương thức, giá trị của object
- khi chỉ cần read thì không nên sử dụng
attr_accessor
(có cả quyền read và write)
Ứng dụng 2 trong Rails: Strong params.
private
def dog_params
params.require(:dog).permit(:name, :weight)
end
- Không cho phép các params khác được tham gia vào để init object dog, ví dụ
color
- việc
private
cho method dog_params
có thể coi như một phương thức bao đóng
Minh / 22 Apr 2019
Trong OOP có 4 khái niệm là:
- Abstraction (trừu tượng)
- Polymorphism (đa hình)
- Inheritance (kế thừa)
- Encapsulation (Bao đóng)
Cách nhớ là: 4 kí tự đầu tiên tạo thành chữ: A PIE
Bài này nói về Tính trừu tượng: Abstraction
Trong OOP nói chung
Trừu tượng hóa điểm tương đồng của các đối tượng để tạo Class là Base
Ví dụ, class Ô tô, Xe máy, Xe đạp kế thừa từ Class Phương Tiện
class Chó, Mèo kế thừa từ class Động Vật
Trong Rails nói riêng
class SomeAbstractModel < ApplicationRecord
self.abstract_class = true
# some heritable methods here
end
AbstractModel không có table tương ứng, nên không tạo object được
SomeAbstractClass.create!
# => NotImplementedError: (Vehicle is an abstract class and cannot be instantiated)
Cách dễ hình dung nhất về Abstract Class trong Rails là ActiveRecord::Base
, nó không có bảng,
nó được sử dụng để các Model kế thừa nó, nên các Model có những phương thức nó định nghĩa,
như find
, where
class AbstractModel < ActiveRecord::Base
self.abstract_class = true
end
class Foo < AbstractModel
end
class Bar < AbstractModel
end
# File activerecord/lib/active_record/base.rb, line 610
def find(*args)
options = args.extract_options!
validate_find_options(options)
set_readonly_option!(options)
case args.first
when :first then find_initial(options)
when :last then find_last(options)
when :all then find_every(options)
else find_from_ids(args, options)
end
end
Abstract Class và Module
Xét bài toán sau, có class Car
, class Airplain
v.v, có chung attribute weight
, method convert_weight
Nhưng cũng có attribute khác nhau, Car
thì có bánh, Airplain
thì không có bánh, mà có cánh quạt
Thiết kế như nào?
- Vấn đề của STI: sẽ có cột empty
class Vehicle < ApplicationRecord
with_options presence: true, allow_blank: false do
validates :weight
validates :color
end
def convert_weight(unit)
case unit
when :lbs
weight * 2.20462
when :g
weight * 1000.0
end
end
end
class Car < Vehicle
validates :number_of_wheels, presence: true, allow_blank: false
end
class Airplane < Vehicle
validates :number_of_wings, presence: true, allow_blank: false
end
migration cho bảng vehicles
create_table :vehicles do |t|
# columns required by some children
t.integer :number_of_wheels
t.integer :number_of_wings
# columns required by all children
with_options null: false do
t.string :type # required for inheritence
t.integer :weight
t.string :color
end
end
Như vậy thì thằng Car
thì number_of_wings
null, thằng Airplane
thì number_of_wheels
null. Khi càng có nhiều attribute khác biệt thì càng có nhiều cột null
- Abstract Class xử lý vấn đề đó như thế nào
class Vehicle < ApplicationRecord
self.abstract_class = true
with_options presence: true, allow_blank: false do
validates :weight
validates :color
end
def convert_weight(unit)
case unit
when :lbs
weight * 2.20462
when :g
weight * 1000.0
end
end
end
Khác ví dụ trên thì dữ liệu của Car
, Airplain
sẽ lưu ở bảng cars
, airplains
tương ứng. Không có bảng vehicles
class CreateVehicles < ActiveRecord::Migration[5.2]
def change
create_table :cars do |t|
with_options null: false do
t.integer :weight
t.string :color
t.integer :number_of_wheels
end
end
create_table :airplanes do |t|
with_options null: false do
t.integer :weight
t.string :color
t.integer :number_of_wings
end
end
end
end
Lưu ý 1: Ở abstract model thì đôi khi chỉ khai báo prototype của method, logic cụ thể được định nghĩa ở Class con
Lưu ý 2: Các phương thức ở Abstract class có thể được đóng gói vào Module
Minh / 22 Apr 2019
Trong OOP có 4 khái niệm là:
- Abstraction (trừu tượng)
- Polymorphism (đa hình)
- Inheritance (kế thừa)
- Encapsulation (Bao đóng)
Cách nhớ là: 4 kí tự đầu tiên tạo thành chữ: A PIE
Bài này nói về Tính đa hình: Polymorphism
Trong OOP nói chung
Đa hình nghĩa là khi mà 1 phương thức có những hành vi khác nhau
Trong Rails nói riêng
Các giải thích dễ hiểu như sau:
Có một class là Manager
, một class là nhân viên Employee
Manager
thì đi ô tô. Nhân viên thì đi xe máy. Về bản chất thì đây đều là xe/phương tiện đi lại. Sẽ có những phương thức chung như là: start
, drive
, stop
v.v. Và tất nhiên cách start
của xe máy và oto sẽ khác nhau rồi.
Nên về thiết kế thì mình sẽ làm như sau
# table managers
class Manager
has_many :xes, as: :chu_phuong_tien
end
# table employees
class Employee
has_many :xes, as: :chu_phuong_tien
end
# table xes
class Xe
belongs_to :chu_phuong_tien, polymorphic: :true
def start
# ở đây ta có thể định nghĩa tuỳ theo đây là oto hay xe máy =))
end
def drive; end
def stop; end
end
khi đó bảng xes
thì ta sẽ có các cột:
t.string :name
t.integer :chu_phuong_tien_id
t.string :chu_phuong_tien_type
ta cũng có những phương thức tương ứng:
m = Manager.new
e = Employee.new
m.xes
e.xes
xe = Xe.new(name: "Teslaaaaa", chu_phuong_tien_id: 1, chu_phuong_tien_type: "Manager")
xe.chu_phuong_tien # => Manager with id=1
Minh / 22 Apr 2019
Public
Public method có thể được gọi bên trong hay bên ngoài class
class Animal
def intro_animal
"I am a #{self.class}"
end
end
Animal.new.intro_animal
# => "I am a Animal"
Private
- Private method chỉ có thể được gọi bên trong class
- Khi có sự kế thừa, behaviour không có gì thay đổi
class Animal
def intro_animal
class_name
end
private
def class_name
"I am a #{self.class}"
end
end
n = Animal.new
n.intro_animal #=>I am a Animal
n.class_name #=>error: private method `class_name' called
Protected vs Private
- Protected method chỉ có thể được gọi bên trong class, giống Private
- không gọi được qua self.private_method, nhưng có thể gọi self.protected_method
- Có sự khác biệt khi có sự kế thừa
class Animal
def animal_call
protect_me
end
protected
def protect_me
p "protect_me called from #{self.class}"
end
end
# giống Private
n= Animal.new
n.animal_call #=> protect_me called from Animal
n.protect_me #=>error: protected method `protect_me' called
class Mammal < Animal
def mammal_call
protect_me
end
end
# giống Private
n= Mammal.new
n.mammal_call #=> protect_me called from Mammal
class Amphibian < Animal
def amphi_call
Mammal.new.protect_me #Receiver same as self
self.protect_me #Receiver is self
end
end
# Khác Private, có thể gọi thông qua self, lưu ý: Mammal.new same as self
n= Amphibian.new
n.amphi_call #=> protect_me called from Mammal
#=> protect_me called from Amphibian
class Tree
def tree_call
Mammal.new.protect_me #Receiver is not same as self
end
end
# Vì Tree không kế thừa nên Mammal.new khác self
n= Tree.new
n.tree_call #=>error: protected method `protect_me' called for #<Mammal:0x13410c0>
Send methods
private
, protected
methods có thể gọi thông qua method send
class Animal
def intro_animal
class_name
end
private
def class_name
"I am a #{self.class}"
end
end
n = Animal.new
n.intro_animal #=>I am a Animal
n.class_name #=>error: private method `class_name' called
n.send("class_name") #=> I am a Animal
n.public_send("class_name") #error: private method `class_name' called
Trong Rails
- Ở controller, chỉ các action (index, new, create v.v) nên là public methods, tất cả nên là private
- Ở model,
protected
methods hữu ích khi class B, class C đều kế thừa từ class A. Ở class C bạn muốn gọi method protected
với receiver là class B
Minh / 22 Apr 2019
Định nghĩa
"hello" # String
:hello # Symbol
"hello world!" # String with space and bang!
"hello world!".to_sym # String can convert to Symbol and vice versa
# => :"hello world!"
:"hello world!".class
# => Symbol
# Vậy là Symbol cũng có thể chưa kí tự đặc biệt
Symbol can’t change while mutable String can
a = "hello"
# => "hello"
b = :hello
# => :hello
a.object_id
# => 47213907316480
b.object_id
# => 1150428
a << "w"
# => "hellow"
a.object_id
# => 47213907316480
b << "w"
# NoMethodError: undefined method `<<' for :hello:Symbol
Frozen Strings: immutable String
example = "hello world"
example.upcase!
puts example
example.freeze
example.downcase!
# => "HELLO WORLD"
# => *.rb:7:in `downcase!': can't modify frozen string (TypeError)
Object ID
puts "hello world".object_id
puts "hello world".object_id
puts "hello world".object_id
puts "hello world".object_id
puts "hello world".object_id
# => 3102960
# => 3098410
# => 3093860
# => 3089330
# => 3084800
puts :"hello world".object_id
puts :"hello world".object_id
puts :"hello world".object_id
puts :"hello world".object_id
puts :"hello world".object_id
# => 239518
# => 239518
# => 239518
# => 239518
# => 239518
- Khai báo Symbol nhanh hơn 40% so với khai báo String
- So sánh Symbol vs Symbol nhanh hơn 40% so với so sánh String vs String
Minh / 20 Apr 2019
Định nghĩa
- Viết hoa chữ cái đầu (nhưng thường được viết hoa tất cả)
- Không thể định nghĩa trong method, chỉ bên trong Class, Module
class RubyBlog
URL = "rubyguides.com"
AUTHOR = "Jesus Castello"
def the_method
# ABC = 1 => Lỗi "dynamic constant assignment"
end
p RubyBlog::AUTHOR # "Jesus Castello"
end
Tính bất biến
giá trị của constants có thể thay đổi, nhưng sẽ hiện cảnh báo
tốt nhất là nên freeze
object trước khi assign
freeze
khiến bạn không thể thay đổi giá trị của ô nhớ, hữu ích khi object là String, Array, Hash
ABC = 1
ABC = 2
# 2: warning: already initialized constant ABC
ABC = 2.freeze
ABC = 1
puts ABC
# => 1
Minh = "Minh".freeze
Minh << "dep trai" # RuntimeError: can't modify frozen String
#
Scope
# Ví dụ về kế thừa
class A
FOO = 1
end
class B < A
def foo
puts FOO
end
end
B.constants # [:FOO]
B::FOO # 1
# Ví dụ
module Food
STORE_ADDRESS = "The moon"
class Bacon
def foo; puts STORE_ADDRESS; end
end
end
fb = Food::Bacon.new
fb.foo # "The moon"
Food::STORE_ADDRESS
# => "The moon"
# STORE_ADDRESS không phải constant của Food::Bacon
Food::Bacon::STORE_ADDRESS
# NameError: uninitialized constant Food::Bacon::STORE_ADDRESS
module Mixin
A = 123
end
class Product
include Mixin
puts A
end
# 123
class OtherProduct
extend Mixin
puts A
end
# uninitialized constant OtherProduct::A
module Parent
VALUE = "Parent"
def print_value
VALUE
end
end
class Child
include Parent
VALUE = "Child"
end
# warning: already initialized constant Child::VALUE
# warning: previous definition of VALUE was here
Child::VALUE
# => "Child"
Child.new.print_value
# => "Parent"
class A
FOO = 1
end
class A::B
class C
puts FOO
end
end
# NameError: uninitialized constant A::B::C::FOO
class A
class B
class C
puts FOO
end
end
end
# 1
Anonymous / 20 Apr 2019
#happy420
#happybirthday
Minh / 19 Apr 2019
|
Array |
Hash |
Set |
index |
dùng interger để indexing ví dụ 0,1,2 -1 là last item -2 là item kế item -1
|
dùng object_id của key để indexing |
|
key |
là index: -2,-1,0,1,2 |
key là cái đéo gì cũng được từ int, string, symbol, object, class v.v |
không có key |
access element |
array[index] array[0] |
hash[key] hash[“key_name”] hash[:key_name] |
không thể access được 1 object cụ thể trong set vì không có key |
key unique? |
tất nhiên |
tất nhiên |
không có key |
nếu key không tồn tại |
nil |
nil có thể custom default value ví dụ: a = Hash.new(0) a[:some_key] # => 0 |
không có key |
value unique? |
không |
không |
có, không tồn tại set mà chứa (1, 1) |
lookup |
slow |
fast |
fastest |
|
|
|
|
Minh / 19 Apr 2019
- include, prepend các hàm định nghĩa trong module trở thành instance method
- extend các hàm định nghĩa trong module trở thành class method
module A
def say
puts "A"
end
end
module B
def say
puts "B"
end
end
module C
def say
puts "C"
end
end
module D
def say
puts "D"
end
end
module E
def speak
puts "speak in E"
end
def talk
puts "talk in E"
end
end
class Test
include A # đưa module A vào ngay bên phải class Test trong danh sách ancestors
include B # đưa module B vào ngay bên phải class Test trong danh sách ancestors
prepend C # đưa module C vào đầu tiên trong danh sách ancestors
prepend D # đưa module D vào đầu tiên trong danh sách ancestors
extend E # dduwa module E vào ngay bên phải singleton class Test
def self.talk
puts "talk in Test"
end
end
Test.ancestors # [D, C, Test, B, A, Object, Kernel, BasicObject]
test = Test.new
test.say # D
# Lý do là tìm hàm theo thứ tự từ trái qua phải trong [D, C, Test, B, A, Object, Kernel, BasicObject]
test.speak
# undefined method
Test.speak # speak in E
Test.talk # talk in Test
Test.singleton_class
# => #<Class:Test>
Test.singleton_class.ancestors
# => [#<Class:Test>, E, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]
DHS / 19 Apr 2019
Các loại biến
Loại biến |
ví dụ |
độ phủ sóng |
default |
global variable |
$name |
tất cả mọi nơi |
nil |
class variable |
@@name |
all object, class con |
undefined |
instance variable |
@name |
object self |
nil |
local variable |
name |
method |
undefined |
Định nghĩa instance variable
- Tên biến: bắt đầu bằng @, đi sau là tên ví dụ
@total_income
- Phạm vi: bất kể đâu trong class, bất kì object nào được tạo từ class
- Intance variable không public, không dùng được ngoài object
- Giá trị mặc định nếu chưa được init là
nil
Nơi sử dụng
Minh / 18 Apr 2019
|
class |
module |
có thể tạo object? |
có |
không |
dùng để?? |
để tạo ra object để class khác kế thừa |
gộp các method lại, để tái sử dụng cho class làm namespace cho class |
superclass là gì? |
Object |
không có |
có hàm gì? |
class method instance method |
module method instance method |
kế thừa được không? |
có |
không |
có thể include? |
không |
có, include module trong class |
có thể extend? |
không |
có, extend module trong class |
- class include module thì object sẽ có các methods được định nghĩa trong module, instance method
- class extend module thì methods sẽ đc extend như một class method
cụ thể hơn thì xem thêm ở bài Modules in Ruby: include, extend, prepend
module A
def a_method
puts "a_method"
end
end
module B
def b_method
puts "b_method"
end
end
class Human
include A
extend B
end
Human.new.a_method
# a_method
Human.new.b_method
# NoMethodError: undefined method `b_method' for #<Human:0x00559a416bc4f8>
Human.a_method
# NoMethodError: undefined method `a_method' for Human:Class
Human.b_method
# b_method
DHS / 17 Apr 2019
Setter và Getter là gì
- Setter là method dùng để gán giá trị cho instance variable
- Getter là method dùng để lấy giá trị của instance variable
Setter và Getter tự định nghĩa
class Cat
def initialize(name)
@name = name
end
end
cat = Cat.new("Mimi")
cat.name #=> undefined method `name'
cat.name = "Mymy"
cat.name #=> undefined method `name='
class Cat
def initialize(name)
@name = name
end
def name #getter method
@name
end
def name=(name) #setter method
@name = name
end
end
cat = Cat.new("Mimi")
cat.name #=> "Mimi"
cat.name = "Mymy"
cat.name #=> "Mymy"
Setter và Getter sử dụng accessors
class Cat
attr_reader: :name # creates the getter methods
attr_writer: :name # creates the setter methods
attr_accessor: :name # creates both setter & getter methods
def initialize(name)
@name = name
end
end
cat = Cat.new("Mimi")
cat.name #=> "Mimi"
cat.name = "Mymy"
cat.name #=> "Mymy"
|
attr_reader |
attr_writer |
attr_accessor |
methods được tạo ra |
name |
name= |
name name= |