Опубликован: 27.01.2016 | Доступ: свободный | Студентов: 914 / 58 | Длительность: 23:07:00
Лекция 9:

Обновление, демонстрация и удаление пользователей

Отображение всех пользователей

В этом разделе мы добавим предпоследнее действие пользователя, действие index, которое предназначено для отображения всех пользователей вместо одного единственного. По дороге мы узнаем о заполнении базы данных образцами ползователей и пагинации вывода пользователей с тем, чтобы страница со списком пользователей могла масштабироваться для отображения потенциально большого количества пользователей. Набросок результата — пользователи, пагинационные ссылки и навигационная ссылка "Users" — представлена на рис. 9.7.6Фотография ребенка из http://www.flickr.com/photos/glasgows/338937124/ В Разделе 9.4 мы добавим административный интерфейс к списку пользователей для того чтобы (предположительно проблемные) могли быть удалены.

Набросок списка пользователей с пагинацией и навигационной ссылкой “Users”.

Рис. 9.7. Набросок списка пользователей с пагинацией и навигационной ссылкой “Users”.

Список пользователей

Хотя мы сохраним страницы show отдельных пользователей видимыми для всех посетителей сайта, для страницы user index будет реализовано ограничение, отображающее ее только для зарегистрированных пользователей, также будет реализовано ограничение того, сколько зарегистрированных пользователей будет отображаться на каждой странице списка. Мы начнем с тестирования того, что действие index защищено, посетив users_path (Таблица 7.1, лекция 7) и проверив что мы перенаправлены на страницу входа. Как и с остальными тестами авторизации, мы поместим этот пример в интеграционные тест авторизации, как это показано в Листинге 9.20.

require 'spec_helper'

describe "Authentication" do
  .
  .
  .
  describe "authorization" do

    describe "for non-signed-in users" do
      .
      .
      .
      describe "in the Users controller" do
        .
        .
        .
        describe "visiting the user index" do
          before { visit users_path }
          it { should have_title('Sign in') }
        end
      end
      .
      .
      .
    end
  end
end
Листинг 9.20. Тестирование того, что действие index защищено. spec/requests/authentication_pages_spec.rb

Соответствующий код приложения просто добавляет index в список действий защищенных предфильтром signed_in_user, как это показано в Листинге 9.21.

class UsersController < ApplicationController
  before_action :signed_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
Листинг 9.21. Требование входа пользователя для действия index. app/controllers/users_controller.rb

Следующий набор тестов убеждается что, для вошедших пользователей, страница списка пользователей имеет правильные заголовок браузера/контент и список всех пользователей сайта. Методика заключается в создании трех фабричных пользователей (вошедшим будет первый из них) и проверке того что страница со списком пользователей имеет тег элемента списка (li) для имени каждого из них. Обратите внимание, что мы позаботились о том, чтобы дать пользователям разные имена, так что каждый элемент в списке пользователей имеет уникальную запись, как это показано в Листинге 9.22.

require 'spec_helper'

describe "User pages" do

  subject { page }

  describe "index" do
    before do
      sign_in FactoryGirl.create(:user)
      FactoryGirl.create(:user, name: "Bob", email: "bob@example.com")
      FactoryGirl.create(:user, name: "Ben", email: "ben@example.com")
      visit users_path
    end

    it { should have_title('All users') }
    it { should have_content('All users') }

    it "should list each user" do
      User.all.each do |user|
        expect(page).to have_selector('li', text: user.name)
      end
    end
  end
  .
  .
  .
end
Листинг 9.22. Тесты для страницы со списком пользователей. spec/requests/user_pages_spec.rb

Как вы можете вспомнить из соответствующего действия в 'demo app' (Листинг 2.4), код приложения использует User.all для вытягивания всех пользователей из базы данных, присваивая их переменной экземпляра @users для использования в представлении, как это показано в Листинге 9.23. (Если отображение всех пользователей за раз кажется вам плохой идеей, вы правы и мы избавимся от этого недостатка в Разделе 9.3.3.)

class UsersController < ApplicationController
  before_action :signed_in_user, only: [:index, :edit, :update]
  .
  .
  .
  def index
    @users = User.all
  end
  .
  .
  .
end
Листинг 9.23. Действие index контроллера Users. app/controllers/users_controller.rb

Для того, чтобы на самом деле создать страницу, нам необходимо создать представление, которое перебирает всех пользователей и обертывает каждого из них в тег li. Мы сделаем это с помощью метода each, отображающего Gravatar и имя каждого пользователя, в то время как сам он будет завернут в тег ненумерованного списка (ul) (Листинг 9.24). Код в Листинге 9.24 использует результат Листинга 7.30 из Раздела 7.6, который позволяет нам передать опцию, определяющую размер отличный от дефолтного, в хелпер Gravatar. Если вы не выполнили это упражнение, обновите ваш файл хелпера Users с содержимым Листинга 7.30 прежде чем продолжать.

<% provide(:title, 'All users') %>
<h1>All users</h1>

<ul class="users">
  <% @users.each do |user| %>
    <li>
      <%= gravatar_for user, size: 52 %>
      <%= link_to user.name, user %>
    </li>
  <% end %>
</ul>
Листинг 9.24. Представление для страницы со списком пользователей. app/views/users/index.html.erb

Давайте также добавим немного CSS (или, скорее, SCSS) для придания стиля (Листинг 9.25).

.
.
.

/* Users index */

.users {
  list-style: none;
  margin: 0;
  li {
    overflow: auto;
    padding: 10px 0;
    border-top: 1px solid $grayLighter;
    &:last-child {
      border-bottom: 1px solid $grayLighter;
    }
  }
}
Листинг 9.25. CSS для страницы со списком пользователей. app/assets/stylesheets/custom.css.scss
.
.
.

/* Users index */

.users {
  list-style: none;
  margin: 0;
  li {
    overflow: auto;
    padding: 10px 0;
    border-top: 1px solid $grayLighter;
    &:last-child {
      border-bottom: 1px solid $grayLighter;
    }
  }
}
Листинг 9.25. CSS для страницы со списком пользователей. app/assets/stylesheets/custom.css.scss

Наконец, мы добавим URL в ссылку на список пользователей в навигационном меню шапки сайта с помощью users_path, тем самым применив последний из неиспользованных именованных маршрутов Таблицы 7.1 лекции 7. Тест (Листинг 9.26) и код приложения (Листинг 9.27) довольно просты.

require 'spec_helper'

describe "Authentication" do
    .
    .
    .
    describe "with valid information" do
      let(:user) { FactoryGirl.create(:user) }
      before { sign_in user }

      it { should have_title(user.name) }
      it { should have_link('Users',       href: users_path) }
      it { should have_link('Profile',     href: user_path(user)) }
      it { should have_link('Settings',    href: edit_user_path(user)) }
      it { should have_link('Sign out',    href: signout_path) }
      it { should_not have_link('Sign in', href: signin_path) }
      .
      .
      .
    end
  end
end
Листинг 9.26. Тест для URL ссылки “Users”. spec/requests/authentication_pages_spec.rb
<header class="navbar navbar-fixed-top navbar-inverse">
  <div class="navbar-inner">
    <div class="container">
      <%= link_to "sample app", root_path, id: "logo" %>
      <nav>
        <ul class="nav pull-right">
          <li><%= link_to "Home", root_path %></li>
          <li><%= link_to "Help", help_path %></li>
          <% if signed_in? %>
            <li><%= link_to "Users", users_path %></li>
            <li id="fat-menu" 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 "Sign out", signout_path, method: "delete" %>
                </li>
              </ul>
            </li>
          <% else %>
            <li><%= link_to "Sign in", signin_path %></li>
          <% end %>
        </ul>
      </nav>
    </div>
  </div>
</header>
Листинг 9.27. Добавление URL к ссылке на список пользователей. app/views/layouts/_header.html.erb

С этим кодом список пользователей стал полностью функциональным, и все тесты должны проходить:

$ bundle exec rspec spec/

Но с другой стороны, как это видно на рис. 9.8, он выглядит несколько безлюдно. Давайте исправим эту печальную ситуацию.

Страница списка пользователей /users с одним пользователем.

Рис. 9.8. Страница списка пользователей /users с одним пользователем.
Вадим Обозин
Вадим Обозин

Здравствуйте, записался на курс. При этом ставил галочку на "обучаться с тьютором". На email пришло письмо, о том, что записался на самостоятельное изучение курса. Как выбрать тьютора?