AWDR 阅读笔记 – 4.Code – Task C

Agile Web Development with Rails 5.1 阅读笔记系列第 4 篇,目录、通用布局和缓存,参考本书该部分(CH8 – Task C)。

Creating the Catalog Listing

创建书籍目录索引。该部分并不需要 Scaffold,只需要建立 Controller,并且只需要 indeces 方法。

建立 Controller

$ bin/rails generate Controller Store index

配置 Routes

这里将 store#index 方法配置为 index,名称为 “store_index”。

# ...
# get 'store/index'
root 'store#index', as: 'store_index'
# ...

排序数据

调用 order 依据 title 字段对数据进行升序排列。

app/controllers/store_controller.rb

# ...
@products = Product.order(:title)
# ...

编写 view

app/views/store/index.html.erb

<% if notice %>
  <aside id="notice"><%= notice %></aside>
<% end %>

<h1> Your Pragmatic Catalog</h1>

<ul class="catalog">
  <% @products.each do |product| %>
    <li>
      <%= image_tag product.image_url %>
      <h2><%= product.title %></h2>
      <p>
        <%= sanitize product.description %>
      </p>
      
</li> <% end %> </ul>

调整 CSS

.store {
  max-width: 80em;
  ul.catalog {
    border-top: solid 0.250em;
    list-style: none;
    padding: 0;
    margin: 0;
    li {
      padding: 1em;
      margin: 0;
      border-bottom: solid thin #ddd;

      // This makes sure our <li> has enough height
      // to hold the entire image, since it's floated
      &::after {
        clear: both;
        content: " ";
        display: block;
      }
      img {
        float: left;
        padding: 1em;
        margin-right: 1em;
        margin-bottom: 1em;
        box-shadow: 0.176em 0.176em 0.354em 0px rgba(0,0,0,0.75);
      }
      .price {
        font-size: 1.414em;
      }
    }
  }
}

Adding a Page Layout

配置统一布局

主要是 header、footer 等。

app/views/layouts/application.html.erb

<header class="main">
  <%= image_tag 'logo.svg', alt: 'The Progmatic Bookshelf' %>
  <h1><%= @page_title %></h1>
</header>

<section class="content">
  <nav class="side_nav">
    <ul>
      <li><a href="/">Home</a></li>
      <li><a href="/questions">Questions</a></li>
      <li><a href="/news">News</a></li>
      <li><a href="/contact">Contact</a></li>
    </ul>
  </nav>

  <main class="<%= controller.controller_name %>">
    <%= yield %>
  </main>
</section>

调整 CSS

同时,为 layout 提供响应式布局。

body {
  margin: 0;
  padding: 0;
}
header.main {
  text-align: center; // center on mobile
  @media (min-width: 30em) {
    text-align: left; // left align on desktop
  }
  background: #282;
  margin: 0;
  h1 {
    display: none;
  }
}
.content {
  margin: 0;
  padding: 0;

  display: flex;
  display: -webkit-flex;
  flex-direction: column; // mobile is horizontally laid out
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;

  @media (min-width: 30em) {
    flex-direction: row;  // desktop is vertically laid out
    -webkit-box-orient: horizontal;
  }

  nav {
    padding-bottom: 1em;
    background: #141;
    text-align: center;  // mobile has centered nav
    @media (min-width: 30em) {
      text-align: left; // desktop nav is left-aligned
      padding: 1em;     // and needs more padding
    }
    ul {
      list-style: none;
      margin: 0;
      padding: 0;
      @media (min-width: 30em) {
        padding-right: 1em; // give desktop some extra space
      }
      li {
        margin: 0;
        padding: 0.5em;
        text-transform: uppercase;
        letter-spacing: 0.354em;
        a {
          color: #bfb;
          text-decoration: none;
        }
        a:hover {
          background: none;
          color: white;
        }
      }
    }
  }
  main {
    padding: 0.5em;
  }
}

Using a Helper to Format the Price

格式化价格

为了提高代码可读性,降低编写的冗余度,提高代码复用,而采用 herlper 方法。

格式化价格可采用 number_to_currency product.price,其等价于 sprintf “$%0.02f", product.price

局部测试

到此为之,可以编写测试书籍目录页的代码,测试覆盖以下几个点:

  1. nav – minimum num;
  2. catalog – list num;
  3. h2 – books’ title;
  4. .price – formated currency。

assert_select 是一个测试 DOM 的非常有用的方法,可以使用 CSS 选择器语法选取元素,然后根据不同的参数判定目标断言是否成立。

test/controllers/store_controller_test.rb

require 'test_helper'

class StoreControllerTest < ActionDispatch::IntegrationTest
  test "should get index" do
    get store_index_url
    assert_response :success
    assert_select 'nav.side_nav a', minimum: 4
    assert_select 'main ul.catalog li', 3
    assert_select 'h2', 'Programming Ruby 1.9'
    assert_select '.price', /$[,d]+.dd/
  end

end

其中的测试数据依然使用的是 fixtures 中定义的数据。

测试!

$ bin/rails test:controllers

Caching of Partial Results

启用 DEV Cache

对于高负载请求,诸如 10000+/s,如果用户每次请求都区连接 DB,会浪费许多资源,Rails 自带 Cache,在开发服务器模式下,通过以下命令启用 Cache。

$ bin/rails dev:cache

指定要 Caching 的内容

这里 cache:

  1. products;
  2. product。

cache 可以嵌套任意多层。

app/views/store/index.html.erb

<% cache @products do %>
  <% @products.each do |product| %>
    <% cache product do %>
      <!-- ... -->
    <% end %>
  <% end %>
<% end %>

查看 Cache Log

在 dev config 中置 enable_fragment_cache_logging 为 true 可启用 Cache Log。

config/environments/development.rb

if Rails.root.join('tmp', 'caching-dev.txt').exist?
  config.action_controller.enable_fragment_cache_logging = true
  config.action_controller.perform_caching = true
  # ...
else

Other Useful CMD

Enable DEV Cache

$ bin/rails dev:cache

参考:

  1. Agile Web Development with Rails 5.1 . Sam Ruby. David Bryant Copeland. with Dave Thomas. 2017 The Pragmatic Programmers, LLC.
  2. 完整源码见:https://media.pragprog.com/titles/rails51/code/rails51/depot_d/*
  3. https://guides.rubyonrails.org/caching_with_rails.html
  4. https://signalvnoise.com/posts/3113-how-key-based-cache-expiration-works

作者: V

Web Dev

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google photo

您的留言將使用 Google 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s