<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 9.3 列出所有用戶 本節,我們要添加倒數第二個用戶控制器動作,`index`。`index` 動作不是顯示某一個用戶,而是顯示所有用戶。在這個過程中,我們要學習如何在數據庫中生成示例用戶數據,以及如何分頁顯示用戶列表,讓首頁顯示任意數量的用戶。用戶列表、分頁鏈接和“Users”(所有用戶)導航鏈接的構思圖如[圖 9.8](#fig-user-index-mockup) 所示。[[6](#fn-6)][9.4 節](#deleting-users)會添加管理功能,用來刪除用戶。 ![user index mockup bootstrap](https://box.kancloud.cn/2016-05-11_5733305f028fd.png)圖 9.8:用戶列表頁面的構思圖 ## 9.3.1 用戶列表 創建用戶列表之前,我們先要實現一個安全機制。單個用戶的資料頁面對網站的所有訪問者開放,但要限制用戶列表頁面,只讓已登錄的用戶查看,減少未注冊用戶能看到的信息量。[[7](#fn-7)] 為了限制訪問 `index` 動作,我們先編寫一個簡短的測試,確認應用會正確重定向 `index` 動作,如[代碼清單 9.31](#listing-index-action-redirected-test) 所示。 ##### 代碼清單 9.31:測試 `index` 動作的重定向 RED test/controllers/users_controller_test.rb ``` require 'test_helper' class UsersControllerTest < ActionController::TestCase def setup @user = users(:michael) @other_user = users(:archer) end test "should redirect index when not logged in" do get :index assert_redirected_to login_url end . . . end ``` 然后我們要定義 `index` 動作,并把它加入被 `logged_in_user` 事前過濾器保護的動作列表中,如[代碼清單 9.32](#listing-logged-in-user-index) 所示。 ##### 代碼清單 9.32:訪問 `index` 動作要先登錄 GREEN app/controllers/users_controller.rb ``` class UsersController < ApplicationController before_action :logged_in_user, only: [:index, :edit, :update] before_action :correct_user, only: [:edit, :update] def index end def show @user = User.find(params[:id]) end . . . end ``` 若要顯示用戶列表,我們要定義一個變量,存儲網站中的所有用戶,然后在 `index` 動作的視圖中遍歷,顯示各個用戶。你可能還記得玩具應用中相應的動作([2.5 節](chapter2.html#a-toy-app-exercises)),我們可以使用 `User.all` 從數據庫中讀取所有用戶,然后把這些用戶賦值給實例變量 `@users`,以便在視圖中使用,如[代碼清單 9.33](#listing-user-index) 所示。(你可能會覺得一次列出所有用戶不太好,你是對的,我們會在 [9.3.3 節](#pagination)改進。) ##### 代碼清單 9.33:用戶控制器的 `index` 動作 app/controllers/users_controller.rb ``` class UsersController < ApplicationController before_action :logged_in_user, only: [:index, :edit, :update] . . . def index @users = User.all end . . . end ``` 為了顯示用戶列表頁面,我們要創建一個視圖(要自己動手創建視圖文件),遍歷所有用戶,把每個用戶包含在一個 `li` 標簽中。我們要使用 `each` 方法遍歷所有用戶,顯示用戶的 Gravatar 頭像和名字,然后把所有用戶包含在一個無序列表 `ul` 標簽中,如[代碼清單 9.34](#listing-user-index-view) 所示。 ##### 代碼清單 9.34:`index` 視圖 app/views/users/index.html.erb ``` <% provide(:title, 'All users') %> <h1>All users</h1> <ul class="users"> <% @users.each do |user| %> <li> <%= gravatar_for user, size: 50 %> <%= link_to user.name, user %> </li> <% end %> </ul> ``` 在[代碼清單 9.34](#listing-user-index-view) 中,我們用到了 [7.7 節](chapter7.html#sign-up-exercises)練習中[代碼清單 7.31](chapter7.html#listing-gravatar-option) 的成果,向 Gravatar 輔助方法傳入第二個參數,指定頭像的大小。如果你之前沒有做這個練習,在繼續閱讀之前請參照[代碼清單 7.31](chapter7.html#listing-gravatar-option),更新用戶控制器的輔助方法文件。 然后再添加一些 CSS 樣式(確切地說是 SCSS),如[代碼清單 9.35](#listing-user-index-css)。 ##### 代碼清單 9.35:用戶列表頁面的 CSS app/assets/stylesheets/custom.css.scss ``` . . . /* Users index */ .users { list-style: none; margin: 0; li { overflow: auto; padding: 10px 0; border-bottom: 1px solid $gray-lighter; } } ``` 最后,我們還要把頭部導航中用戶列表頁面的鏈接地址換成 `users_path`,這是[表 7.1](chapter7.html#table-restful-users) 中還沒用到的最后一個具名路由,如[代碼清單 9.36](#listing-users-link) 所示。 ##### 代碼清單 9.36:添加用戶列表頁面的鏈接地址 app/views/layouts/_header.html.erb ``` <header class="navbar navbar-fixed-top navbar-inverse"> <div class="container"> <%= link_to "sample app", root_path, id: "logo" %> <nav> <ul class="nav navbar-nav navbar-right"> <li><%= link_to "Home", root_path %></li> <li><%= link_to "Help", help_path %></li> <% if logged_in? %> <li><%= link_to "Users", users_path %></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown"> Account <b class="caret"></b> </a> <ul class="dropdown-menu"> <li><%= link_to "Profile", current_user %></li> <li><%= link_to "Settings", edit_user_path(current_user) %></li> <li class="divider"></li> <li> <%= link_to "Log out", logout_path, method: "delete" %> </li> </ul> </li> <% else %> <li><%= link_to "Log in", login_path %></li> <% end %> </ul> </nav> </div> </header> ``` 至此,用戶列表頁面完成了,所有的測試也都可以通過了: ##### 代碼清單 9.37:**GREEN** ``` $ bundle exec rake test ``` 不過,如[圖 9.9](#fig-user-index-only-one) 所示,頁面中只顯示了一個用戶,有點孤單。下面,我們來改變這種悲慘狀況。 ![user index only one 3rd edition](https://box.kancloud.cn/2016-05-11_5733305f178f7.png)圖 9.9:用戶列表頁面,只顯示了一個用戶 ## 9.3.2 示例用戶 本節,我們要為應用添加更多的用戶。為了讓用戶列表看上去像個“列表”,我們可以在瀏覽器中訪問注冊頁面,一個一個地注冊用戶,不過還有更好的方法,讓 Ruby(和 Rake)為我們創建用戶。 首先,我們要在 `Gemfile` 中加入 `faker` gem,如[代碼清單 9.38](#listing-faker-gemfile) 所示。這個 gem 會使用半真實的名字和電子郵件地址創建示例用戶。(通常,可能只需在開發環境中安裝 `faker` gem,但是對這個演示應用來說,生產環境也要使用 `faker`,參見 [9.5 節](#updating-showing-and-deleting-users-conclusion)。) ##### 代碼清單 9.38:在 `Gemfile` 中加入 `faker` ``` source 'https://rubygems.org' gem 'rails', '4.2.2' gem 'bcrypt', '3.1.7' gem 'faker', '1.4.2' . . . ``` 然后和之前一樣,運行下面的命令安裝: ``` $ bundle install ``` 接下來,我們要添加一個 Rake 任務,向數據庫中添加示例用戶。Rails 使用一個標準文件 `db/seeds.rb` 完成這種操作,如[代碼清單 9.39](#listing-db-seed) 所示。(這段代碼涉及一些高級知識,現在不必太關注細節。) ##### 代碼清單 9.39:向數據庫中添加示例用戶的 Rake 任務 db/seeds.rb ``` User.create!(name: "Example User", email: "example@railstutorial.org", password: "foobar", password_confirmation: "foobar") 99.times do |n| name = Faker::Name.name email = "example-#{n+1}@railstutorial.org" password = "password" User.create!(name: name, email: email, password: password, password_confirmation: password) end ``` 在[代碼清單 9.39](#listing-db-seed) 中,首先使用現有用戶的名字和電子郵件地址創建一個示例用戶,然后又創建了 99 個示例用戶。其中,`create!` 方法和 `create` 方法的作用類似,只不過遇到無效數據時會拋出異常,而不是返回 `false`。這么做出現錯誤時不會靜默,有利于調試。 然后,我們可以執行下述命令,還原數據庫,再使用 `db:seed` 調用這個 Rake 任務:[[8](#fn-8)] ``` $ bundle exec rake db:migrate:reset $ bundle exec rake db:seed ``` 向數據庫中添加數據的操作可能很慢,在某些系統中可能要花上幾分鐘。此外,有些讀者反饋說,Rails 服務器運行的過程中無法執行 `reset` 命令,因此,可能要先停止服務器,然后再執行上述命令。 執行完 `db:seed` Rake 任務后,我們的應用中就有 100 個用戶了,如[圖 9.10](#fig-user-index-all) 所示。(可能要重啟服務器才能看到效果。)我犧牲了一點個人時間,為前幾個用戶上傳了頭像,這樣就不會都顯示默認的 Gravatar 頭像了。 ![user index all 3rd edition](https://box.kancloud.cn/2016-05-11_5733305f32963.png)圖 9.10:用戶列表頁面,顯示了 100 個示例用戶 ## 9.3.3 分頁 現在,最初的那個用戶不再孤單了,但是又出現了新問題:用戶太多,全在一個頁面中顯示。現在的用戶數量是 100 個,算是少的了,在真實的網站中,這個數量可能是以千計的。為了避免在一頁中顯示過多的用戶,我們可以分頁,一頁只顯示 30 個用戶。 在 Rails 中有很多實現分頁的方法,我們要使用其中一個最簡單也最完善的,叫 [will_paginate](http://wiki.github.com/mislav/will_paginate/)。為此,我們要使用 `will_paginate` 和 `bootstrap-will_paginate` 這兩個 gem。其中,`bootstrap-will_paginate` 的作用是設置 will_paginate 使用 Bootstrap 提供的分頁樣式。修改后的 `Gemfile` 如[代碼清單 9.40](#listing-will-paginate-gem) 所示。 ##### 代碼清單 9.40:在 `Gemfile` 中加入 `will_paginate` ``` source 'https://rubygems.org' gem 'rails', '4.2.2' gem 'bcrypt', '3.1.7' gem 'faker', '1.4.2' gem 'will_paginate', '3.0.7' gem 'bootstrap-will_paginate', '0.0.10' . . . ``` 然后執行下面的命令安裝: ``` $ bundle install ``` 安裝后還要重啟 Web 服務器,確保成功加載這兩個新 gem。 為了實現分頁,我們要在 `index` 視圖中加入一些代碼,告訴 Rails 分頁顯示用戶,而且要把 `index` 動作中的 `User.all` 換成知道如何分頁的方法。我們先在視圖中加入特殊的 `will_paginate` 方法,如[代碼清單 9.41](#listing-will-paginate-index-view) 所示。稍后我們會看到為什么要在用戶列表的前后都加入這個方法。 ##### 代碼清單 9.41:在 `index` 視圖中加入分頁 app/views/users/index.html.erb ``` <% provide(:title, 'All users') %> <h1>All users</h1> <%= will_paginate %> <ul class="users"> <% @users.each do |user| %> <li> <%= gravatar_for user, size: 50 %> <%= link_to user.name, user %> </li> <% end %> </ul> <%= will_paginate %> ``` `will_paginate` 方法有點小神奇,在用戶控制器的視圖中,它會自動尋找名為 `@users` 的對象,然后顯示一個分頁導航鏈接。[代碼清單 9.41](#listing-will-paginate-index-view) 中的視圖現在還不能正確顯示分頁,因為 `@users` 的值是通過 `User.all` 方法獲取的([代碼清單 9.33](#listing-user-index)),而 `will_paginate` 需要調用 `paginate` 方法才能分頁: ``` $ rails console >> User.paginate(page: 1) User Load (1.5ms) SELECT "users".* FROM "users" LIMIT 30 OFFSET 0 (1.7ms) SELECT COUNT(*) FROM "users" => #<ActiveRecord::Relation [#<User id: 1,... ``` 注意,`paginate` 方法可以接受一個哈希參數,`:page` 鍵的值指定顯示第幾頁。`User.paginate` 方法根據 `:page` 的值,一次取回一組用戶(默認為 30 個)。所以,第一頁顯示的是第 1-30 個用戶,第二頁顯示的是第 31-60 個,以此類推。如果 `:page` 的值為 `nil`,`paginate` 會顯示第一頁。 我們可以把 `index` 動作中的 `all` 方法換成 `paginate`,如[代碼清單 9.42](#listing-will-paginate-index-action) 所示,這樣就能分頁顯示用戶了。`paginate` 方法所需的 `:page` 參數由 `params[:page]` 指定,`params` 中的這個鍵由 `will_pagenate` 自動生成。 ##### 代碼清單 9.42:在 `index` 動作中分頁取回用戶 app/controllers/users_controller.rb ``` class UsersController < ApplicationController before_action :logged_in_user, only: [:index, :edit, :update] . . . def index @users = User.paginate(page: params[:page]) end . . . end ``` 現在,用戶列表頁面應該可以顯示分頁了,如[圖 9.11](#fig-user-index-pagination) 所示。(在某些系統中,可能需要重啟 Rails 服務器。)因為我們在用戶列表前后都加入了 `will_paginate` 方法,所以這兩個地方都會顯示分頁鏈接。 ![user index pagination 3rd edition](https://box.kancloud.cn/2016-05-11_5733305f4a488.png)圖 9.11:分頁顯示的用戶列表頁面 如果點擊鏈接“2”,或者“Next”,就會顯示第二頁,如[圖 9.12](#fig-user-index-page-two-rails-3) 所示。 ![user index page two 3rd edition](https://box.kancloud.cn/2016-05-11_5733305f6c2f7.png)圖 9.12:用戶列表的第二頁 ## 9.3.4 用戶列表頁面的測試 現在用戶列表頁面可以正常使用了,接下來要為這個頁面編寫一些簡單的測試,其中一個測試前一節實現的分頁。測試的步驟是,先登錄,然后訪問用戶列表頁面,確認第一頁顯示了一些用戶,而且還顯示了分頁鏈接。為此,測試數據庫中要有能足夠數量的用戶,足以分頁才行,即超過 30 個。 我們在[代碼清單 9.20](#listing-fixture-second-user) 中創建了第二個用戶固件,但手動創建 30 多個用戶,工作量有點大。不過,由固件中的 `password_digest` 屬性得知,固件文件支持嵌入式 Ruby,所以我們可以使用[代碼清單 9.43](#listing-users-fixtures-extra-users) 中的代碼,再創建 30 個用戶。([代碼清單 9.43](#listing-users-fixtures-extra-users) 還多創建了幾個用戶,以備后用。) ##### 代碼清單 9.43:在固件中再創建 30 個用戶 test/fixtures/users.yml ``` michael: name: Michael Example email: michael@example.com password_digest: <%= User.digest('password') %> archer: name: Sterling Archer email: duchess@example.gov password_digest: <%= User.digest('password') %> lana: name: Lana Kane email: hands@example.gov password_digest: <%= User.digest('password') %> malory: name: Malory Archer email: boss@example.gov password_digest: <%= User.digest('password') %> <% 30.times do |n| %> user_<%= n %>: name: <%= "User #{n}" %> email: <%= "user-#{n}@example.com" %> password_digest: <%= User.digest('password') %> <% end %> ``` 然后,我們可以編寫用戶列表頁面的測試了。首先,生成所需的測試文件: ``` $ rails generate integration_test users_index invoke test_unit create test/integration/users_index_test.rb ``` 在測試中,我們要檢查是否有一個類為 `pagination` 的標簽,以及第一頁中是否顯示了用戶,如[代碼清單 9.44](#listing-user-index-test) 所示。 ##### 代碼清單 9.44:用戶列表及分頁的測試 GREEN test/integration/users_index_test.rb ``` require 'test_helper' class UsersIndexTest < ActionDispatch::IntegrationTest def setup @user = users(:michael) end test "index including pagination" do log_in_as(@user) get users_path assert_template 'users/index' assert_select 'div.pagination' User.paginate(page: 1).each do |user| assert_select 'a[href=?]', user_path(user), text: user.name end end end ``` 測試組件應該可以通過: ##### 代碼清單 9.45:**GREEN** ``` $ bundle exec rake test ``` ## 9.3.5 使用局部視圖重構 用戶列表頁面現在已經可以顯示分頁了,但是有個地方可以改進,我不得不介紹一下。Rails 提供了一些很巧妙的方法,可以精簡視圖的結構。本節我們要利用這些方法重構一下用戶列表頁面。因為我們已經做了很好的測試,所以可以放心重構,不必擔心會破壞網站的功能。 重構的第一步,把[代碼清單 9.41](#listing-will-paginate-index-view) 中的 `li` 換成 `render` 方法調用,如[代碼清單 9.46](#listing-index-view-first-refactoring) 所示。 ##### 代碼清單 9.46:重構用戶列表視圖的第一步 app/views/users/index.html.erb ``` <% provide(:title, 'All users') %> <h1>All users</h1> <%= will_paginate %> <ul class="users"> <% @users.each do |user| %> <%= render user %> <% end %> </ul> <%= will_paginate %> ``` 在上述代碼中,`render` 的參數不再是指定局部視圖的字符串,而是代表 `User` 類的變量 `user`。[[9](#fn-9)]此時,Rails 會自定尋找一個名為 `_user.html.erb` 的局部視圖。我們要手動創建這個視圖,然后寫入[代碼清單 9.47](#listing-user-partial) 中的內容。 ##### 代碼清單 9.47:顯示單個用戶的局部視圖 app/views/users/_user.html.erb ``` <li> <%= gravatar_for user, size: 50 %> <%= link_to user.name, user %> </li> ``` 這個改進不錯,不過我們還可以做得更好。我們可以直接把 `@users` 變量傳給 `render` 方法,如[代碼清單 9.48](#listing-index-final-refactoring) 所示。 ##### 代碼清單 9.48:完全重構后的用戶列表視圖 GREEN app/views/users/index.html.erb ``` <% provide(:title, 'All users') %> <h1>All users</h1> <%= will_paginate %> <ul class="users"> <%= render @users %> </ul> <%= will_paginate %> ``` Rails 會把 `@users` 當作一個 `User` 對象列表,傳給 `render` 方法后,Rails 會自動遍歷這個列表,然后使用局部視圖 `_user.html.erb` 渲染每個對象。重構后,我們得到了如[代碼清單 9.48](#listing-index-final-refactoring) 這樣簡潔的代碼。 每次重構修改應用代碼后,都要運行測試組件確認仍能通過: ##### 代碼清單 9.49:**GREEN** ``` $ bundle exec rake test ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看