10/10/2018, 13:18

Ruby on Rails - Mỗi ngày một chuyện [Tutorital]

Lời nhắn từ quản trị:
Đây là bài hướng dẫn có lẽ là đầu tiên về Ruby on Rails. Vì thế các bài hướng dẫn của tác giả được chúng tôi tách riêng ra để các bạn tiện theo dõi.

Chủ đề gốc: "Ruby on Rails - Mỗi ngày một chuyện"

Note: Dành riêng cho các bài viết hướng dẫn, vui lòng gửi các bài khác tại chủ đề gốc
#++++++++++++++++++++++++++++++++++++++++++#

Trước tiên giới thiệu một chút về bản thân mình nhé: Mình mới ra trường hơn 1 năm thôi, và đã sử dụng RoR khoảng hơn 6 tháng một chút. Cũng như hầu hết các bạn mới bắt đầu, mình gặp vô khối chuyện linh tinh từ nhỏ đến lớn với RoR.

Mình lập thread này là để chia sẻ những kinh nghiệm của mình, và cũng mong các bạn có kinh nghiệm đóng góp các kinh nghiệm của các bạn trong việc sử dụng RoR cho việc lập trình web.

Mình học RoR theo cách không chính quy, tức là học theo nhu cầu, công việc cần tới đâu mình học tới đó, nên các kinh nghiệm của mình hơi linh tinh không theo sách vở gì cả, hơn nữa mình cũng chưa phải là expert hay pro gì (nếu chỉ sử dụng RoR hơn 6 tháng mà thành expert được thì tốt quá ) nên có gì các bạn cứ góp ý thẳng thắn.

Nói thêm là hiện nay mình sử dụng Linux, nhiều ví dụ trong các bài viết sau sẽ dùng từ website của team mình là www.yup.vn, đồng thời do yêu cầu công việc phải sử dụng tiếng Anh nên có thể mình sẽ chêm tiếng Anh khá nhiều vào bài viết, mong các bạn thông cảm.

Các bài viết sẽ theo thứ tự thời gian từ lúc mình là 1 newbie 100% cho tới hiện nay, vì vậy các bạn có kinh nghiệm rồi sẽ thấy các bài đầu tiên hơi thừa thãi



++Chuẩn bị++
Để setup RoR trong máy của bạn, cách dễ dàng nhất vẫn là trực tiêp theo hướng dẫn của trang chủ RoR tại đây http://www.rubyonrails.org/down nếu bạn sử dụng windows hay mac.

Nếu bạn dùng Linux, bạn sẽ cần install các package: ruby ruby-devel ruby-libs ruby-irb ruby-rdoc
Code:
Ví dụ: yum install ruby ruby-devel ruby-libs ruby-irb ruby-rdoc
hoặc: apt-get install ruby ruby-devel ruby-libs ruby-irb ruby-rdoc
tùy vào phiên bản linux bạn sử dụng.

Tiếp đến các bạn cần có ruby gem để kiểm soát các gem thư viện của ruby.

Với windows:
Code:
download rubygems tại đây: http://rubyforge.org/frs/?group_id=126
Giải nén, vào thư mục vừa giải nén ra và chạy lệnh: ruby setup.rb
Với Linux:bạn có thể tìm RPM của rubygems tương ứng với version của mình, ví dụ với fedora và centos bạn có thể sử dụng file sau
Code:
ftp://download.fedora.redhat.com/pub/fedora/linux/updates/7/SRPMS/rubygems-0.9.4-1.fc7.src.rpm
Kế tiếp là một số gem tối thiểu cần thiết cho web development
Code:
gem install rake -v 0.7.3 --include-dependencies

gem install rails -v 1.2.6 --include-dependencies

gem install mongrel -v 1.1.1 --include-dependencies
Hiện nay Rails đã ra tới version 2.0, tuy nhiên version này còn mới nên chưa bảo đảm tính ổn định nên mình vẫn xài 1.2.6

Về IDE cho việc phát triển, hiện tại mình đang sử dụng NetBeans với ruby extension, vì NetBeans có tích hợp cả SVN, tuy nhiên bạn vẫn có thể sử dụng một số IDE khác như Aptana với ruby extension (cho cả windows và linux) hay Radrails (cho windows)

Vậy là xong, bạn đã sẵn sàng cho việc phát triển web với RoR



++Bước đầu++
Bạn có thể dùng IDE để tạo project, hoặc tạo trực tiếp từ command line (khuyến khích dùng command line, vì sau này còn nhiều đất dụng võ ). Tại folder bạn muốn tạo project, chạy
Code:
rails <project_name>
Và rails sẽ tạo ra sẵn một khung sườn project cho bạn, bao gồm rất nhiều folder và một số file nữa.

Các folder mình nghĩ cần chú ý là:
-/app/models: chứa các object class của bạn
-/app/views: chứa các file giao diện rhtml hay rjs cho project của bạn
-/app/helpers: chứa các function hỗ trợ cho view
-/app/controllers: chứa các class quản lý object, và thực hiện các chức năng của system của bạn
-/db: chứa các file giúp bạn khởi tạo database. Không như nhiều framework khác, Rails sẽ quản lý phần lớn database cho bạn, tất cả những gì bạn cần là nói cho Rails biết phải quản lý như thế nào
-/lib: chứa các module mà sau này bạn sẽ viết thêm. Lợi thế của các module này là có thể được gọi từ bất cứ đâu, không giống như helper chỉ có thể được gọi từ view, và controller chỉ có thể được gọi từ controller
-/public: chứa các file ảnh, CSS và javascripts nếu bạn cần
-/vendor: chứa các plugin cho rails nếu bạn cần sử dụng, chúng sẽ được install vào đây

Nếu bạn đã biết về MVC thì có lẽ các khái niệm trên không xa lạ lắm với bạn


RoR thường được nhắc tới với khái niệm "Convention over Configuration", tức là thay vì phải thiết lập môi trường hay những gì đại loại như vậy, tất cả những gì bạn cần là gọi cho đúng tên

Ví dụ: bạn có một class gọi là User (từ nay mình sẽ gọi là model, theo RoR) thì file model của class này sẽ được RoR "nghĩ" là có tên là /models/user.rb (tất nhiên bạn vẫn có thể đặt tên khác nếu thích), và controller của model này sẽ mặc đinh được hiểu là /controllers/user_controller.rb (tất nhiên, bạn vẫn có thể đặt tên khác nếu thích) và helper của model này sẽ là /helpers/user_helper.rb, các view của model sẽ được đặt trong thư mục /views/users, và điều tuyệt nhất của Rails là: table dưới database chứa các dữ liệu về user sẽ được "hiểu" là table 'users', bạn không cần phải thiết lập bất cứ binding nào như với VB hay .NET

Tất nhiên đi đôi với cái lợi đấy có cái hại là nếu bạn gọi sai tên thì tất cả đều không chạy

Các model sẽ được định nghĩa như sau:
Code:
#user.rb
class User < ActiveRecord::Base

end
Kí hiệu '< ActiveRecord::Base' có nghĩa là model này sẽ inherit lại ActiveRecode::Base, đây là class cơ bản nhất của RoR, chứa rất nhiều các function cơ bản cho phép bạn xử lý database cũng như relationship giữa các model khác nhau, và còn vô khối thứ khác mà mình cũng không biết hết

Relationship của các model thường sẽ được định nghĩa như sau:
Code:
#user.rb
class User < ActiveRecord::Base
   #1-many relationship
   has_many :pets

   #1-1 relationship
   has_one :room

   #many-1 relationship
   belongs_to :family

   #many-many relationship
   has_many_and_belongs_to :groups
end
Mình nghĩ không cần giải thích gì thêm, ngoài chuyện bạn có thấy RoR sử dụng ngôn ngữ gần giống với tiếng Anh thông dụng không ?

Và vì Rails đã quản lý hầu hết database cho bạn, tất cả những gì bạn cần là thiết lập các table cho đúng.

Ví dụ, trong table 'pets' chúng ta sẽ phải có 1 column tên là 'user_id' (theo đúng convention của RoR) thì RoR sẽ hiểu 'user_id' chính là foreign key của table 'users' trong table 'pets'. Từ đó, chúng ta có thể làm như sau trong code
Code:
....
   #my_pet is a Pet
   #me is a User
   my_pet.user = me
   my_pet.save
....
Khi đó RoR sẽ tự tìm và update column 'user_id' tương ứng với record 'my_pet' bằng id của record 'me'

Vì RoR hoạt động trên cơ chế như vậy, cho nên có một số chữ bạn không được phép sử dụng cho tên của class, controller hay function, như liệt kê tại link sau
http://wiki.rubyonrails.com/rails/pages/ReservedWords

Xin phép tạm dừng tại đây, mai viết tiếp, chủ đề có lẽ sẽ là validate model, model function và class function
ndgiang84 viết 15:23 ngày 10/10/2018
-----------------------------------------------
thailehuy viết 15:34 ngày 10/10/2018
À cái đó là bạn sử dụng Webrick server đi kèm với Rails, ngoài ra, trong bài đầu mình có chỉ dẫn cài Mongrel server tốt hơn Webrick chút Bạn có thể chạy
Code:
mongrel_rails start
từ trong folder gốc chứa project của bạn để start server, sau đó vào localhost:3000 để xem tác phẩm của mình

Việc này thì yên tâm, từ từ sẽ nói tới trong phần view và controller.

Mấy ngày cuối tuần bận quá nên không post được, hôm nay xin phép tiếp tục với model và validate.

Có 2 cách cơ bản để tạo một model trong RoR.
-Cách 1: vào folder /app/models/ trong thư mục chứa project của bạn, tạo file <tên model>.rb Tuy nhiên nên nhớ là mỗi model của RoR bắt buộc phải gắn với một table tương ứng dưới database, nên bạn nên bảo đảm là tên model của bạn gọi đúng table. RoR quản lý quan hệ giữa model và database như sau: tên table dưới database = tên class của model viết thường (downcase) và ở số nhiều (trong tiếng Anh). Ví dụ: class 'User' sẽ tương ứng với table 'users' trong database.

-Cách 2: vào folder /db/migrate/ trong thư mục chứa project của bạn, tạo một file create_<tên model>.rb. File này thì thật ra bạn đặt tên thế nào cũng được, tuy nhiên nên đặt sao cho dễ nhớ. Trong file này bạn sẽ xác lập tên model và các thuộc tính của model. Khi được thực thi, file này sẽ được biên dịch ra thành một file SQL và chạy trên database tương ứng.

File này có cấu trúc như sau:
Code:
#file description goes here
class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
       t.column :username, :string, :limit => 30, :null => false
       t.column :email, :string, :limit => 50, :null => false
       t.column :title, :string, :limit => 15
       t.column :age, :integer
       t.column :citizen_id, :string, :limit => 9
       t.column :activation_code, :string, :limit => 100 
       t.column :activated_at, :datetime 
    end

     add_index :users, :username
     add_index :users, :email
     add_index :users, :title
  end
  
  def self.down
    drop_table :users
  end
end
Các class migration dùng để tạo model và database cần phải được inherit lại từ class 'ActiveRecord::Migration'.

Function 'self.up' được gọi khi tạo table, và bạn có thể dễ dàng nhận thấy các column trong table được thêm vào với các kiểu cũng như các định nghĩa của SQL.

Chú ý ký hiệu ':<tên thuộc tính>', vì đây là quy định bắt buộc của RoR khi gọi các thuộc tính của model trong nhiều trường hợp.

Function 'self.down' được gọi khi xóa model

Các function 'add_index' được sử dụng cho việc index data, phục vụ cho việc tìm kiếm sau này

Sau khi đã hoàn chỉnh file migrate của bạn, bạn có thể chạy lệnh sau từ command line tại thư mục chứa project của bạn:
Code:
rake db:migrate
Lệnh này sẽ tự động tìm và thực thi tất cả các file chứa trong thư mục /db/migrate/ của bạn và tạo các table tương ứng. Chú ý rằng khi chạy lệnh này thì các table sẽ được tạo lại mới hoàn toàn, bạn sẽ mất toàn bộ dữ liệu từ table cũ nếu có tồn tại sẵn.

Dù bạn sử dụng cách nào thì bạn cũng sẽ cần tạo một file model trong thư mục /app/models/ của bạn. Tiếp tục ví dụ trên thì chúng ta cần một file 'user.rb' cho model User. Chú ý là theo convention của RoR thì tên file model nên là tên class model viết thường và ở số nhiều (tương tự tên table )
Code:
#user.rb
class User < ActiveRecord::Base
end
Đây là tất cả những gì bạn cần với model User. Phải, bạn đang thấy rằng trong model này chúng ta không cần khai báo bất cứ một thuộc tính gì. Tất cả thuộc tính bạn cần sẽ được đọc từ table tương ứng dưới database.

Việc này có lợi là rất dễ dàng khai báo các model, nhưng cũng có hại là nếu bạn tạo table sai thì


Validate:
Nếu model của bạn chỉ chứa dữ liệu kiểm soát được thì không có gì đặc biệt để nói. Tuy nhiên nếu model của bạn cần dữ liệu lấy từ bên ngoài vào (ví dụ như để các thành viên khác gõ vào) thì bạn cần phải bảo đảm dữ liệu đó được đưa vào theo luật của bạn.

Ví dụ:
Code:
#user.rb
class User < ActiveRecord::Base
   validates_uniqueness_of :username,
                           :message => "Already registered username"
                           
   validates_presence_of :username,
                         :message => "Username is required"
                         
   validates_length_of :username,
                       :in => 6..12,
                       :too_short => "Username must have at least 6 characters",
                       :too_long => "Username must have maximum 12 characters",
                       :if => Proc.new{|user| !user.username.blank?}

    validates_format_of :email,
                       :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
                       :message => "Invalid email",
                       :if => Proc.new{|user| !user.email.blank?}

    validates_numericality_of :citizen_id,
                              :only_integer => true,
                              :allow_nil => false,
                              :if => Proc.new{|user| !user.citizen_id.blank?}
end
Đây là tất cả các function validate cơ bản của RoR cũng cấp sẵn cho bạn. Giống như tên của các function này, chúng có tác dụng như sau:
-validates_uniqueness_of : kiểm tra xem field này có bị trùng lặp trong table hay không
-validates_presences_of : kiểm tra xem có dữ liệu trong field hay không
-validates_length_of : kiểm tra độ dài của chuỗi dữ liệu trong field
-validates_format_of : kiểm tra format của chuỗi trong field, sử dụng regular expression (xin lỗi, cái này ai chỉ mình tiếng Việt gọi ra sao nhé )
-validates_numericality_of : bắt buộc dữ liệu phải là kiểu số.

Ngoài ra bạn còn chú ý thấy các dòng ':if => Proc.new{|user| !user.citizen_id.blank?}'. Đây là các dòng điều kiện để kiểm tra, vì dụ dòng trước là điều kiện khi tạo mới user, chỉ kiểm tra khi field 'citizen_id' không để trống (blank?)

"Nhưng nếu tớ thích validate những kiểu khác thì sao ?". Đây chắc chắn là câu hỏi mà nhiều bạn đang nghĩ

Nếu bạn cần validate những thứ mà RoR không có sẵn, bạn có thể dễ dàng tự viết function validate của riêng mình:
Code:
#user.rb
class User < ActiveRecord::Base
   .......
   #== Method for validation ==#
   def validate            
      if age < 18
          errors.add(:age, "You are too young to be here")
      end     
   end
   .......
end
Như đã từng nói, RoR cũng cấp cho bạn tất cả những gì bạn cần, việc bạn phải làm là gọi tên cho đúng. Và 'validate' là một trong những thứ đấy.

Hàm 'validate', nếu có tồn tại trong model của bạn, sẽ luôn luôn được gọi trước khi model của bạn được lưu vào database. Điều này bảo đảm bạn sẽ không lưu các dữ liệu sai (tất nhiên, trừ khi chúng ta viết code sai ).

'errors' là một global array, cho phép bạn lưu tất cả các lỗi trên các field, cũng với các thông báo lỗi tương ứng với field đó (cái này gọi là hash thì phải)

Việc truy xuất và sử dụng 'errors' mình sẽ nói rõ hơn khi vào phần views, vì dù sao, thông báo lỗi thì phải cho người ta đọc chứ

Xin phép tạm dừng tại đây, ngày mai viết tiếp, có lẽ chủ để sẽ là model function và class function.
thailehuy viết 15:29 ngày 10/10/2018
Phù, lại một tuần bận rộn.

Hôm này xin phép viết tiếp về class function và object function của model.

Lấy ví dụ là đơn giản nhất

Code:
#user.rb
class User < ActiveRecord::Base
   .......
   #== object function ==#
   def is_grown_up?            
      return age >= 18
   end
   .......
   #== class function ==#
   def self.find_all_grown_up            
      find(:all, :conditions => "age >= 18")
   end
   .......
  protected
   #== class function ==#
   def validate
      
   end
   .......
end
Thông thường tất cả các model đều chứa một số dạng function như trên. 'is_grown_up?' là một object function, bắt buộc được gọi qua lệnh 'user.is_grown_up?'. Điểm đặc biệt của RoR là bạn có thể sử dụng dấu '?' trong tên function như mọi ký tự bình thường khác.

'self.find_all_grown_up' là một class instance function, 'self' định nghĩa hàm này phải được gọi thông qua instance của class chứ không phải là object, ví dụ 'User.find_all_grown_up'. Lợi thế của việc này là bạn có thể gọi hàm từ bất cứ đâu mà không cần khởi tạo object.

Tất cả các function đặt sau 'protected' chỉ có thể được gọi từ trong cùng class, không thể gọi từ bên ngoài.

Controller và View
Trong RoR, controller và view luôn gắn chặt với nhau qua một quy luật cơ bản nhất: mọi function call xuất phát từ view vào controller đều phải thể hiện trở lại view. Tức là mọi click của bạn trên GUI đều phải thay đổi một cái gì đó trên GUI

Hãy ghi nhớ quy luật đó trước khi chúng ta tiếp tục.

Về cơ bản, 1 controller trong RoR 'nên' quản lý một model. Tuy nhiên điều này không bắt buộc, controller có thể quản lý nhiều model hoặc chẳng quản lý model nào cả.

Đối với view, một folder trong /app/views luôn 'thuộc về' một controller nào đó. Vì dụ controller 'users_controller' mà chúng ta có sẽ đi kèm với view trong folder /app/views/users

Theo convention mặc định của RoR, nếu bạn không tự xác định khác đi, thì mỗi function trong controller (nếu được gọi từ GUI) sẽ tự động được hiểu là sẽ thể hiện một view cùng tên trong folder tương ứng.

Ví dụ nếu chúng ta có function 'list_all_users' trong 'users_controller' thì mặc định view của function này sẽ là /app/views/users/list_all_user.rhtml

Vì có mối quan hệ như vậy nên view sẽ có quyền truy xuất 1 số biến từ controller. Ví dụ như khi bạn muốn tìm một user, rồi thể hiện tên của user đó lên view thì cấu trúc sẽ là:
Code:
#controller
class UsersController < ApplicationController
     def find_user
          @user = User.find_by_id(params[:user_id])
     end
end
Rồi từ /app/views/users/find_user.rhtml chúng ta có thể gọi
Code:
........
<%= @user.name%>
........
'ApplicationController' là controller gốc của tất cả controller, mọi function từ đây đều có thể được các controller khác truy xuất.

Bạn có thể thấy mình đang sử dụng một instance class function của User để tìm ra user cần thiết. 'params[:user_id]' là một HTTP parameter được truyền từ GUI. Ký hiệu '@' xác nhận là biến '@user' có thể được truy xuất từ GUI

Ký hiệu '<% .... %>' tương tự như của PHP xác định vị trí bạn nhúng code ruby vào trang rhtml.

Nếu bạn không thích một function phải sử dụng một trang view cùng tên, bạn có thể dùng những hàm như 'render' hay 'redirect_to' để thay đổi. Về bản chất, các trang view được gọi qua 'render' vẫn có thể truy xuất các biến từ function trên (nếu có xác định '@', tất nhiên), còn 'redirect_to' thì không thể, vì 'redirect_to' có nghĩa là bạn đã gọi một request mới tương tự như request từ GUI

Ví dụ:
Code:
#controller
class UsersController < ApplicationController
     def find_user
          @user = User.find_by_id(params[:user_id])
          render :action => :show_user
     end
end
Hoặc
Code:
#controller
class UsersController < ApplicationController
     def find_user
          @user = User.find_by_id(params[:user_id])
          redirect_to :action => :show_user
     end
end
Bữa nay bận nên tạm viết bi nhiêu đây thôi, bài kế tiếp chúng ta sẽ xây dựng một web app đơn giản
hoattm1 viết 15:31 ngày 10/10/2018
Hơi ngoài lề chút, hiện Fsoft đang tuyển gấp technical leader mảng Ruby on Rails. Bạn nào quan tâm thì contact qua email Hoattm1@fsoft.com.vn. Thank and regards.
unglevan viết 15:19 ngày 10/10/2018
@thailehuy:
cậu post tiếp mấy bài về RUBY ON RAILS đi. Đang hay thì đứt dây đàn.
Mr.Chu viết 15:32 ngày 10/10/2018
Rails giờ còn được dùng nhiều không các bác ?
ngoc_viet08 viết 15:30 ngày 10/10/2018
ít xài lắm . nhưng bác pro thì sẽ có lương cao cho bác . nhưng ko phải tôi tuyển dụng
freshgraduate09 viết 15:21 ngày 10/10/2018
cái nào ít xài mà mình thành thạo thì trở thành "hàng độc". Đã là hàng độc thì sẽ trở nên đắt giá. Tuy nhiên rủi ro cũng ko ít. Giả sử trong số ít những chỗ dùng RoR , ko có chỗ nào tuyển mình thì mình chả có đất dụng võ.
satthudatinh011 viết 15:20 ngày 10/10/2018
sao ko viết tiếp nữa vậy
đang hay
Bài liên quan
0