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 email 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

Q & A

Rails: Introduction (Week 1)

By CYB

Rails: Introduction (Week 1)

Rails: Introduction (Week 1) @ Rakuten Taiwan weekly meetup

  • 1,287