Rails: Introduction (Week 1)
@ Rakuten Taiwan weekly meetup
Agenda
-
Short Intro
-
Setup
-
Scaffold Application
-
Understanding ActiveRecord
Short Intro
- Open Source Project
- Web Framework for Ruby
- A MVC Framework
- Philosophy
- DRY (Don't Repeat Yourself)
- CoC (Convention over Configuration)
MVC of Rails
Rails Controller
Rails View
HTTP Request
Browser
Rails Model
Database
Rails Structure
-
ActiveRecord = Model
-
ActionView = View
-
ActionController = Controller
-
ActionDispatch = Routing
Setup
# First, Install ruby
$ brew install ruby
$ ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-linux]
# Then, use `rubyGems` to install `rails`
$ gem install rails --no-ri --no-rdoc
$ rails -v
Rails 5.0.0.1
# However, if you want to install an old version?
$ gem install rails -v 4.2.4 --no-ri --no-rdoc
Setup (Cont.)
# Use `rails` cli to scaffold your project
$ mkdir <project-name>
$ rails new <project-name> --skip-test-unit
# However, if you don't want to use newest version of rails,
# you can give version, in `_x.x.x_` format, as parameter in cli
$ rails _4.2.4_ new <project-name> --skip-test-unit
Setup (Cont.)
File/Directory | Purpose |
---|---|
app/ | Core application code, including models, views, controllers, and helpers |
bin/ | Binary Executable Files |
config/ | Application configurations |
db/ | Database files |
doc/ | Documentation for application |
lib/ | Library modules |
log/ | Application log files |
public/ | Data accessible to the public |
test/ | Application tests |
Setup (Cont.)
File/Directory | Purpose |
---|---|
tmp/ | Temporary files |
vendor/ | Third-party code |
Rakefile | Utility tasks available via rake |
Gemfile | Gem requirements for this app |
Gemfile.lock | A list of gems used to ensure that all copies of the app use the same gem versions |
config.ru | Configuration file for Rack middleware |
Setup (Cont.)
# cd to your project and use this command to install packages in `Gemfile`
$ cd <project-name>
$ bundle install
# Then, use this command to up your rails server
$ rails server # a.k.a rails s
Scaffold Application
# Use generate scaffold to generate Models, Views, and Controllers
$ rails g scaffold person name:string bio:text birthday:date
Enter localhost:3000
Migration
-
Able to manage `db` w/ VCS
-
Flexible for app
-
Cross-database
Scaffold Application (Cont.)
Scaffold Application (Cont.)
Migration
class CreatePeople < ActiveRecord::Migration
def change
create_table :people do |t|
t.string :name
t.text :bio
t.date :birthday
t.timestamps null: false
end
end
end
Scaffold Application (Cont.)
Migration
class AddNicknameToPeople < ActiveRecord::Migration
def change
add_column :people, :nickname, :string
end
end
Scaffold Application (Cont.)
Layout: Partial Template w/ erb
Example: app/views/people/index.html.erb
Scaffold Application (Cont.)
Interact w/ Rails Application via `rails console`
Scaffold Application (Cont.)
config/routes.rb
RESTful Routes
Scaffold Application (Cont.)
Validation
class Person < ActiveRecord::Base
validates :name, length: { maximum: 20 }
end
Scaffold Application (Cont.)
respond_to
Basic ActiveRecord
Table | Class |
---|---|
CRUD to Table | CRUD to Class |
Row | Object |
Column | Object attribute |
Naming in Plural | Naming in Singular |
Basic ActiveRecord (Cont.)
- ORM (Object-relational mapping)
- Active Record Pattern from Martin Fowler in "Patterns of Enterprise Application Architecture"
- Schema Name Convention
- PK (Primary Key) : Default with an integer id, auto-generated via db:migrate
- FK (Foreign Key) : Corresponding Table singular name + _id, e.g. user_id
Basic ActiveRecord (Cont.)
CRUD: Create
# `create`: create and save data into database
todo = Todo.create( description: 'Study Ruby on Rails', done: false )
# `new`: assign an instance to a variable and need to use `save` to have transaction with database
todo = Todo.new
todo.description = 'Weekly sharing @ Rakuten'
todo.done = false
todo.save
localhost:3000/todos
Basic ActiveRecord (Cont.)
CRUD: Read
# `all`: return all todos in database
todos = Todo.all
# `first`: return first row in database
todo = Todo.first
# `find_by`: return first todo which is done yet
todo = Todo.find_by(done: false)
# `where`: return all todos which are done yet and ordered by `created_at` in desc
todo = Todo.where(done: false).order('created_at DESC')
Basic ActiveRecord (Cont.)
CRUD: Read
Basic ActiveRecord (Cont.)
CRUD: Update
# Get one row, modify it and use `save` method to update database
todo = Todo.find_by(description: 'Study Ror')
todo.description = 'Study RoR'
todo.save
# Get one row, use `update` method to update database directly
todo = Todo.find_by(description: 'Study Ror')
todo.update(description: 'Study RoR')
First way
Second way
Basic ActiveRecord (Cont.)
CRUD: Delete
# Get one row, and use `destroy` method to delete it from database
todo = Todo.find_by(description: 'Study RoR')
todo.destroy
ActiveRecord Association
Q: If there are multiple models, how can we communicate b/w models?
class Customer < ActiveRecord::Base
end
class Order < ActiveRecord::Base
end
ActiveRecord Association
Q: If there are multiple models, how can we communicate b/w models?
A: Use Primary Key (id) and
Foreign Key ({table_name}_id) to communicate b/w them
class Customer < ActiveRecord::Base
has_many :orders
end
class Order < ActiveRecord::Base
belongs_to :customer
end
ActiveRecord Association (Cont.)
One-to-Many
Customer
Order
Order
Order
id | name |
---|---|
1 | Allen |
2 | Nick |
3 | Haku |
id | item | customer_id |
---|---|---|
1 | Rakuten Stickers | 2 |
2 | Apple Stickers | 1 |
3 | GitHub Stickers | 3 |
Customers
Orders
ActiveRecord Association (Cont.)
One-to-Many
class Customer < ActiveRecord::Base
has_many :orders # Plural
end
class Order < ActiveRecord::Base
belongs_to :customer # Singular
end
ActiveRecord Association (Cont.)
One-to-One
Q: When should we use 1-to-1 association?Why don't we just combine those tables into one table?
ActiveRecord Association (Cont.)
One-to-One
Q: When should we use 1-to-1 association?Why don't we just combine those tables into one table?
A: Each table has different meaning. On the other hand, this kind of design is always used to reduce amount of search. Let's take a look at example at next page
ActiveRecord Association (Cont.)
One-to-One
Customer
Account
id | name |
---|---|
1 | Allen |
2 | Nick |
3 | Haku |
id | name | user_id | |
---|---|---|---|
1 | Allen | Allen@example.com | 1 |
2 | Nick | Nick@example.com | 2 |
3 | Haku | Haku@example.com | 3 |
Cusomers
Accounts
ActiveRecord Association (Cont.)
One-to-One
class Customer < ActiveRecord::Base
has_one :account
end
class Account < ActiveRecord::Base
belongs_to :customer
end
ActiveRecord Association (Cont.)
Many-to-Many
id | name |
---|---|
1 | Allen |
2 | Nick |
3 | Haku |
id | group_name |
---|---|
1 | Tech Sharing |
2 | Buy Stickers |
customer_id | group_id |
---|---|
1 | 1 |
1 | 2 |
2 | 2 |
3 | 1 |
3 | 2 |
$ rails g model customer_groupship customer_id:integer group_id:integer
Customers
CustomerGroupShips
Groups
ActiveRecord Association (Cont.)
Many-to-Many
class Customer < ActiveRecord::Base
has_many :customer_groupships
has_many :groups, :through => :customer_groupships
end
class CustomerGroupship < ActiveRecord::Base
belongs_to :customer
belongs_to :group
end
class Group < ActiveRecord::Base
has_many :customer_groupships
has_many :groups, :through => :customer_groupships
end
ActiveRecord Association (Cont.)
All methods for association
-
belongs_to
-
has_one
-
has_one :through
-
has_many
-
has_many :through
Next Week
-
Understanding ActionView
-
Understanding ActionController
-
Difference b/w 4.x and 5.0
References
- Rails Guide (中文)
- Rails Guide (English)
- Ruby on Rails 實戰聖經
- Ruby on Rails チュートリアル
- 小学生でもわかるRuby on Rails入門
- RailsにおけるMVC(モデル/ビュー/コントローラ)
- Rails 筆記 - activerecord 實作 (一) - transaction
- Ruby on Rails plural (controller) and singular (model) convention - explanation
- Ruby on Rails Tutorial Learn Web Development with Rails
Q & A
Rails: Introduction (Week 1)
By CYB
Rails: Introduction (Week 1)
Rails: Introduction (Week 1) @ Rakuten Taiwan weekly meetup
- 1,287