SLIDE 1 Ruby%on%Rails%
Ruby%on%Rails%%,% 1
SLIDE 2 //tonytonyjan
- tonytonyjan.net
- Ruby-on-Rails-
- TJDict-Chrome-
- Rails-Girls-Taipei-1~5-
Ruby%on%Rails%%,% 2
SLIDE 3
- Ruby&(Rails)
- C&(Qt)
- Java&(Swing)
- Network&Programming
- Informa?on&Retrieval
Ruby%on%Rails%%,% 3
SLIDE 4
- RubyConf*Brazil*2015*
- Confoo*Canada*2015*
- Ruby*Kaigi*Japan*2014*
- Yahoo*Hack*Taiwan*2013*
Ruby%on%Rails%%,% 4
SLIDE 5 !RoR!
task '' => 'Rails' task 'Rails' => %w[Ruby CLI RDBMS Git] task '' => ''
Ruby%on%Rails%%,% 5
SLIDE 6
Ruby%on%Rails%%,% 6
SLIDE 7 !gem
Ruby%on%Rails%%,% 7
SLIDE 8
User%Story
Ruby%on%Rails%%,% 8
SLIDE 9 User%Story%*%
Ruby%on%Rails%%,% 9
SLIDE 10 User%Story%*%
Ruby%on%Rails%%,% 10
SLIDE 11
- Spree
- ror_ecommerce
- Piggybak
- mount4carrierwave4
Ruby%on%Rails%%,% 11
SLIDE 14
- "#>"/products
- "#>"/products/:id
- "#>"/cart
- "#>"/orders/new
- "#>"/orders/:id
- "#>"/admin/*
Ruby%on%Rails%%,% 14
SLIDE 15
- git clone https://github.com/tonytonyjan/my_cart
cd my_cart rails s
Ruby%on%Rails%%,% 15
SLIDE 16
Prefix Verb URI Pattern Controller#Action root GET / products#index product GET /products/:id(.:format) products#show cart GET /cart(.:format) carts#show
Ruby%on%Rails%%,% 16
SLIDE 17 # config/routes.rb root 'products#index' resources :products, only: :show resource :cart, only: :show
Ruby%on%Rails%%,% 17
SLIDE 18 ERD
Ruby%on%Rails%%,% 18
SLIDE 19 ERD
Ruby%on%Rails%%,% 19
SLIDE 20
2. 3.
Ruby%on%Rails%%,% 20
SLIDE 21 Ruby%on%Rails%%,% 21
SLIDE 23 Ruby%on%Rails%%,% 23
SLIDE 25 Ruby%on%Rails%%,% 25
SLIDE 26
- Agile'Web'Development'with'Rails'
- ror_ecommerce'
- SpreePiggybak''Cart'en>ty'Order'
Ruby%on%Rails%%,% 26
SLIDE 27
- rails g model product name description:text price:decimal stock:integer
rails g model order name address status payment_method rails g model cart rails g model line_item \
- rder:references cart:references product:references \
unit_price:decimal quantity:integer
Ruby%on%Rails%%,% 27
SLIDE 28
class Cart has_many :line_items end # app/models/product.rb class Product has_many :line_items end # app/models/order.rb class Order has_many :line_items has_many :products, through: :line_items end
Ruby%on%Rails%%,% 28
SLIDE 29
- # db/migrate/VERSION_create_line_items.rb
t.decimal :unit_price, null: false t.integer :quantity, null: false, default: 1 # db/migrate/VERSION_create_products.rb t.string :name, null: false t.text :description, null: false t.decimal :price, null: false, default: 0 t.integer :stock, null: false # db/migrate/VERSION_create_carts.rb t.string :status, null: false, default: ''
Ruby%on%Rails%%,% 29
SLIDE 30 rake dev:setup
rails g task dev fakeup
namespace :dev do desc "Generate fake data" task fakeup: ['db:schema:load', :environment] do 20.times do |i| Product.create( name: "product no.#{i}", description: "description no.#{i}", price: (rand(10) + 1) * 50, stock: rand(91) + 10 ) end cart = Cart.create Product.all.sample(5).each do |product| cart.line_items.create product: product, unit_price: product.price, quantity: rand(4) + 1 end end end
Ruby%on%Rails%%,% 30
SLIDE 31
- Cart#total
- Cart#empty?
- Cart#clear
- Order#total
- LineItem#subtotal
Ruby%on%Rails%%,% 31
SLIDE 32 !controller
Prefix Verb URI Pattern Controller#Action root GET / products#index product GET /products/:id(.:format) products#show cart GET /cart(.:format) carts#show rails g controller products index show rails g controller carts show
Ruby%on%Rails%%,% 32
SLIDE 33 current_cart
class ApplicationController < ActionController::Base protect_from_forgery with: :exception before_action :set_current_cart, if: ->{ Rails.env.development? } helper_method :current_cart def current_cart @current_cart ||= Cart.find_or_create_by(id: session[:cart_id]) session[:cart_id] = @current_cart.id @current_cart end private def set_current_cart session[:cart_id] = 1 end end
Ruby%on%Rails%%,% 33
SLIDE 34
Ruby%on%Rails%%,% 34
SLIDE 36
- @cart.add_product @product
@product.add_to_cart @cart
36
SLIDE 37 Rails&
Ruby%on%Rails%%,% 37
SLIDE 38 Clean&Architecture&by&Uncle&Bob
Ruby%on%Rails%%,% 38
SLIDE 39
Ruby%on%Rails%%,% 39
SLIDE 40
resources :line_items, only: %i[create update destroy]
# app/controllers/line_items_controller.rb class LineItemsController < ApplicationController def create @line_item = current_cart.line_items.new line_item_params if @line_item.save redirect_to cart_path, notice: '' else @product = @line_item.product render 'products/show' end end private def line_item_params params.require(:line_item).permit(:quantity, :product_id) end end
Ruby%on%Rails%%,% 40
SLIDE 41
- # app/models/line_item.rb
validate :check_stock before_save :set_unit_price def check_stock errors.add(:quantity, 'out of stock') if quantity > product.stock end def set_unit_price self.unit_price = product.price end
Ruby%on%Rails%%,% 41
SLIDE 42
- # app/controllers/products_controller.rb
def show @product = Product.find params[:id] @line_item = current_cart.line_items.find_or_initialize_by(product: @product) end
<!-- app/views/products/show.html.erb --> <h1><%= @product.name %></h1> <p><%= @product.description %></p> <p><%= @product.price %></p> <p><%= @product.stock %></p> <%= form_for @line_item do |f| %> <%= f.number_field :quantity %> <%= f.hidden_field :product_id %> <%= f.submit '' %> <% end %>
Ruby%on%Rails%%,% 42
SLIDE 43
- LineItemsController#destroy
- LineItemsController#update
Ruby%on%Rails%%,% 43
SLIDE 45
accepts_nested_attributes_for :line_items validates_associated :line_items
- @cart.line_items_attributes = {
0 => {quantity: 10, id: 123}, 1 => {quantity: 10, id: 123} }
Ruby%on%Rails%%,% 45
SLIDE 46
cart = Cart.first cart.line_items_attributes = {0 => {quantity: 10, product_id: __}} # create cart.line_items_attributes = {0 => {id: __, quantity: 10}} # update cart.save
Ruby%on%Rails%%,% 46
SLIDE 47
resource :cart, only: %i[show update]
# app/controllers/carts_controller.rb class CartsController < ApplicationController def update if current_cart.update cart_params redirect_to cart_path, notice: '' else render :show end end private def cart_params params.require(:cart).permit(line_items_attributes: [:id, :quantity]) end end
Ruby%on%Rails%%,% 47
SLIDE 48 <!-- app/views/carts/show.html.erb --> <%= f.fields_for :line_items do |ff| %> <% line_item = ff.object %> <tr> <td><%= link_to line_item.product, line_item.product %></td> <td><%= ff.number_field :quantity %></td> <td></td> </tr> <% end %>
- <input type="number" name="cart[line_items_attributes][1][quantity]"/>
<input type="hidden" name="cart[line_items_attributes][1][id]"/>
Ruby%on%Rails%%,% 48
SLIDE 50 RubyConf)Taiwan)2014) !Rails! slides/video
Ruby%on%Rails%%,% 50
SLIDE 51 Ruby%on%Rails%%,% 51
SLIDE 52 Ruby%on%Rails%%,% 52
SLIDE 53 # app/models/account.rb class Account < ActiveRecord::Base ... end # app/models/admin/account.rb class Admin::Account < Account ... def transfer_money(account) ... end ... end
- "Account"Admin::Account"
- "Admin"
- Admin::Account""controller"
Ruby%on%Rails%%,% 53
SLIDE 54
- link_to('foo', @post) # href="/posts/:id"
form_for(@post) # action="/posts" or "/posts/:id"
- link_to('foo', [:admin, @post]) # href="/admin/posts/:id"
link_to('foo', admin_post_path(@post)) # href="/admin/posts/:id" form_for(@post, url: admin_posts_path) # action="/admin/posts" form_for(@post, url: admin_post_path(@post)) # action="/admin/posts/:id"
Ruby%on%Rails%%,% 54
SLIDE 55
link_to('foo', @post) # href="/admin/posts/:id" form_for(@post) # action="/admin/posts/:id" or "/admin/posts"
Ruby%on%Rails%%,% 55
SLIDE 56
- !Post!model
- 1. #config/routes.rb
- 2. #app/models/admin/post.rb
- 3. app/controllers/admin/posts_controller.rb
- 4. app/views/admin/posts/{index,new,edit}.html.erb
Ruby%on%Rails%%,% 56
SLIDE 57
scaffold
Ruby%on%Rails%%,% 57
SLIDE 58 !scaffold!
- rails g scaffold Admin::Product name description:text --parent=Product
rails g scaffold Admin::Order name address status --parent=Order
└── templates └── erb └── scaffold ├── _form.html.erb ├── edit.html.erb ├── index.html.erb ├── new.html.erb └── show.html.erb
Ruby%on%Rails%%,% 58
SLIDE 59
- "lib/templates/erb/scaffold/show.html.erb
"table"
- "bundle show railtie/lib/rails/generators/erb/
scaffold/templates/show.html.erb
Ruby%on%Rails%%,% 59