Lista Użytkowników - Profil i Indeks Profilów

Przez:, Z dnia:

Ten tutorial zakłada, że już ukończyłeś:

  1. Adding custom fields to devise

Obecnie pozwalamy naszym użytkownikom na rejestrację, jednakże, użytkownicy nie mogą oddziałowywać na siebie. Jeżeli rozważamy coś socjalnego lub chechy współpracy będziemy musieli w pewnym momencie pozwolić użytkownikom widzieć profile innych użytkowników. W tym tutorialu, będziemy pracować nad tworzeniem listy użytkowników i ich indywidualnych stron.

  • Indeks Użytkowników
  • Profile Użytkowników

Krok 1: Stwórz Indeks Użytkowników

Poprzednio, stworzyliśmy static pages controller.rb. Zawierał on własne akcje jak "home" lub "contact". W przypadku naszych użytkowników powołamy się na bardziej standardowe podejście, zwane REST API. Brzmi strasznie kiedy czytasz po raz pierwszy, ale w rzeczywistości jest to bardzo proste pojęcie. API jest skrótem do Interfejs Programistyczny Aplikacji (Application Programming Interface). REST API to standardowy sposób zapytań o informacje kierowanych do serwera (albo z serwera) przy pomocy URL. Standardowych URL. Więcej informacji na ten temat możecie znaleźć tutaj: Tutorial o tworzeniu postów w aplikacji blogerskiej.

Krok 1.2: Stwórz kontroler

Zaczniemy od stworzenia kontrolera do manipulacji użytkownikami.

bash

$ rails generate controller users

    create  app/controllers/users_controller.rb
    invoke  erb
    exist    app/views/users
    invoke  test_unit
    create    test/controllers/users_controller_test.rb
    invoke  helper
    create    app/helpers/users_helper.rb
    invoke    test_unit
    create      test/helpers/users_helper_test.rb
    invoke  assets
    invoke    coffee
    create      app/assets/javascripts/users.js.coffee
    invoke    scss
    create      app/assets/stylesheets/users.css.scss

Otwórzmy i zobaczmy nowo stworzony kontroler:

app/controllers/users_controller.rb

class UsersController < ApplicationController
end

Krok 1.3: Stwórz akcję "index"

Zaczniemy od stworzenia akcji "index" do wyswietlania wszystkich zarejestrowanych uzytkowników naszej strony. Dodaj zmainy:

app/controllers/users_controller.rb

class UsersController < ApplicationController
  def index
    @users = User.all
  end
end

Krok 1.4: Stwórz plik HTML

Możemy teraz kontynuować i stworzyć szblon HTML dla naszego "index". Stwórz nowy plik wewnątrz app/views/users i nazwij go tak samo jak akcję - index.html.erb, dodaj poniższy kod:

app/views/users/index.html.erb

<ul>
    <% @users.each do |user| %>
        <li><%= user.email %></li>
    <% end %>
</ul>

Krok 1.5: Zmień plik Rutera

Jeżeli chcemy móc otworzyć tę stronę, musimy zmienić plik routes.rb tak, aby aplikacji wiedziała jak zmapować URL z kontrolerem:

config/routes.rb

devise_for :users

resources :users, only: [:index, :show]

#existing code

Odpal aplikację i przejdź do http://localhost:3000/users.

Powinieneś widzieć listę zarejestrowanych użytkowników Twojej aplikacji.

Krok 1.6: Dodaj link

Chcemy także dodać link do indeksu w menu:

app/views/layouts/_menu.html.erb

<nav class="navbar navbar-default" role="navigation">
    <div class="container">

        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-collapse-1">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <%= link_to "Demo App", root_path, class: 'navbar-brand' %>
        </div>

        <div class="collapse navbar-collapse" id="navbar-collapse-1">
            <ul class="nav navbar-nav navbar-right">

                <li><%= link_to 'Members', users_path %></li>

                <% if current_user %>
                <li><%= link_to 'Edit Profile',edit_user_registration_path %></li>
                <li><%= link_to 'Logout', destroy_user_session_path, method: :delete %></li>
                <li class="round-image-50"><%= image_tag(current_user.avatar.url(:thumb)) %></li>
                <% else %>
                <li><%= link_to 'Login', new_user_session_path %></li>
                <% end %>
            </ul>
        </div>
    </div>
</nav>

Krok 2: Stwórz Profil Użytkownika

Jak już stworzyliśmy sposób do wyświetlania wszystkich użytkowników, chcemy zobaczyć ich profile. Stworzymy nową akcję w kontrolerze użytkowników i nazwiemy ją "show":

app/controllers/users_controller.rb

class UsersController < ApplicationController
  # existing code

  def show
    @user = User.find(params[:id])
  end

end

Krok 2.2: Stwórz szablon

Stwórz odpowiadający szablon wewnątrz app/views/users:

app/views/users/show.html.erb

<h1><%= @user.email %></h1>
<ul>
    <li>Name: <%= @user.name %></li>
    <li>Date of birth:<%= @user.date_of_birth %></li>
</ul>

Krok 2.3: Zastąp indeks emaili

Aby łatwo przejść do strony profilu użytkownika powinniśmy przkształcić nasz indeks emaili w listę linków:

app/views/users/index.html.erb

<ul>
    <% @users.each do |user| %>
        <li><%= link_to user.email, user_path(user) %></li>
    <% end %>
</ul>

Krok 3: Refinacja

Do tej pory wszystko działa. Jednak zapewne zauważyłeś, że te profile i indeks wymagają nieco polerowania. 

  • Zamiast emaili chcemy używać nazw.
  • Jeżeli jakaś informacja nie jest obecna, nie chcemy jej wyświetlać.
  • Zamiast daty urodzenia chcemy wyświetlić wiek.

Stawmy im czoła jeden po drugim.

Krok 3.2: Użyj nazw zamiast emaili

Kiedy stworzyliśmy użytkownika z Devise, nie używaliśmy nazw od początku. Dodaliśmy je później. Wciąż nie wymagamy od użytkownika podania jego nazwy. Mogą to zrobić, ale nie jest to konieczne. Dlatego też wpadamy w ryzyko, że użytkownik nie poda nazwy i będziemy mieć puste miejsce. By to złagodzić napiszemy metodę instancji ("instance method") dla class użytkownika. Napiszmy kod i go przedyskutujmy:

app/models/user.rb

class User < ActiveRecord::Base

  #existing code

  def full_name
    if self.name.blank?
      self.email
    else
      self.name
    end
  end

end

Z tą metodą możemy wziąć instancję ("instance") klasy Użytkownika (dokładnie current_user) i uruchomić na niej komendę .full_name. Zwróci ona Nazwę, jeśli nie jest pusta, a jeżeli jest zwróci email. Możemy napisać to w bardziej zwięzły sposób używając "operatorów potrójnych". Z początku może to byc nieco mieszające, więc zanim tego użyjesz upewnij się, że to zrozumiałeś. Ponadto, używanie "self" jest opcjonalne, używam tego dla jasności. Poniższy kod jest tylko przykładem.

app/models/user.rb

def full_name
    name.blank? ? email : name
end

Krok 3.3: Wyświetlanie tylko nie-pustych rekordów

W profilu użytkownika zamierzamy wyświetlić zarówno nazwę jak i datę urodzenia. Ale co jeśli użytkownik nie podał tych informacji? Mysimy znaleźć sposób na ukrycie tych rekordów, w przeciwnym razie, nasza strona nie będzie dobrze się prezentować. Technicznie możemy napisać takie coś:

app/views/users/show.html.erb

<h1><%= @user.email %></h1>
<ul>
    <% unless @user.name.blank? %>
        <li>Name: <%= @user.name %></li>
    <% end %>

    <% unless @user.date_of_birth.blank? %>
        <li>Date of birth:<%= @user.date_of_birth %></li>
    <% end %>
</ul>

Na szczęście możemy to napisać w bardziej zwięzły sposób używając content_tag:

app/views/users/show.html.erb

<h1><%= @user.email %></h1>
<ul>
    <%= content_tag(:li, ("Name: " + @user.name)) unless @user.name.blank? %>
    <%= content_tag(:li, ("Date of birth: " + @user.date_of_birth)) unless @user.date_of_birth.blank? %>
</ul>

Robimy tak, ponieważ nie chcemy wyświtlać całego tagu "li" kiedy treść jest pusta.

Krok 3.4: Wyświetlanie wieku zamiast daty urodzenia

Tutaj użyjemy trochę "Magii Rails".

app/views/users/show.html.erb

<h1><%= @user.email %></h1>
<ul>
    <%= content_tag(:li, ("Name: " + @user.name)) unless @user.name.blank? %>
    <%= content_tag(:li, ("Age: " + distance_of_time_in_words(Time.now, @user.date_of_birth) + " old")) unless @user.date_of_birth.blank? %>
</ul>

Zauważ jak używamy "distance_of_time_in_words(one_date, other_date)".

Dodanie tego do naszego szablonu HTML jest dosyć trudne. Zazwyczaj staje się to bardziej złożone.

Krok 4: Ulepsz wygląd

Wygląd chcę zostawić Tobie, ale żeby uruchomić Twój proces rozwoju pokażę Ci jak to może wyglądać z podstawami "responsive design". By zobaczyć jak to działa, spróbuj zmienić rozmiar okna.

app/views/users/index.html.erb

<div class="container">
    <div class="users row">
        <% @users.each do |user| %>
        <div class="panel panel-default">
            <%= link_to user_path(user) do %>
            <div class="panel-body">
                <%= image_tag(user.avatar.url(:medium)) %>
                <p><%= user.full_name %></p>
            </div>
            <% end %>
        </div>
        <% end %>
    </div>
</div>

app/views/users/show.html.erb

<div class="row profile">
    <div class="col-sm-4 col-md-3">
        <%= image_tag(@user.avatar.url(:medium), class: 'avatar') %>
        <h1><%= @user.full_name %></h1>
        <ul>
            <%= content_tag(:li, ("Name: " + @user.name)) unless @user.name.blank? %>
            <%= content_tag(:li, ("Age: " + distance_of_time_in_words(Time.now, @user.date_of_birth) + " old")) unless @user.date_of_birth.blank? %>
        </ul>
    </div>
    <div class="feed">
        <h3>Social Feed Coming</h3>
        <p>Put a couple of lines of text here and see how it scrolls</p>
    </div>
</div>

app/assets/stylesheets/custom.css.scss

// Columns

.users.row {
    -moz-column-width: 15em;
    -webkit-column-width: 15em;
    -moz-column-gap: 0;
    -webkit-column-gap: 0;
}

@media (min-width: 992px) {
    .users.row {
        -moz-column-width: 13.5em;
        -webkit-column-width: 13.5em;
    }
}


// users index

.feed {
    width: 100%;
    text-align: center;
}

.panel {
    display: inline-block;
    padding:  0;
    margin:  0 0 10px 0;
    width:98%;
    img { width: 100%; }
}

    // users show

.profile {
    text-align: center;
    .avatar { max-width: 100%; }
    ul {
        list-style: none;
        padding: 0;
    }
}

.users .panel-body {
    padding: 0;
    p {
        margin: 10px;
        overflow-x: scroll;
    }
   &:hover {
        background-color: #fcfcfc;
        box-shadow: 0 0 3px #b7b7b7;
    }
}


@media (min-width: 768px) {
    .feed {
        text-align: center;
        position: absolute;
        right: 0;
        top:53px;
        bottom:0;
        border-left: 1px dotted #e4e4e4;
        width: 63%;
        overflow-y: scroll;
        padding-top: 50px;
    }
    .profile {text-align: left}
}

To powinno wyglądać mniej więcej tak:

Indeks użytkowników

 

Index of users

Profil Użytkownika

 

User's profile

Krok 4.2: Dodaj jQuery i napraw CSS

Musimy tutaj pamiętać o jednej rzeczy, ponieważ dla naszego "feed" używamy position:absolute;, będzie on kolidował z naszymi wiadomościami flash, które pojawiają się nad menu. Możemy to łatwo naprawić używając jQuery. Dodajmy trochę kodu do wiadomości flash:

app/views/layouts/_flash_messages.html.erb

<% flash.each do |key, value| %>
    <div class="alert alert-<%= key %> alert-dismissable">
        <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
        <%= value %>
    </div>
<% end %>

<script>
    $('.alert').fadeOut(4000);
</script>

I naprawmy CSS:

app/assets/stylesheets/custom.css

$navbar-default-border: #e5e5e5;
$navbar-margin-bottom: 50px;

@import "bootstrap";

.field_with_errors { @extend .has-error; }
.alert-notice { @extend .alert-info; }
.alert-alert { @extend .alert-danger; }

.alert {
   top: 50px;
   left:0;
   right: 0;
   position:absolute;
}

// existing code

Musisz się zalogować by móc oznaczyć tutorial jako ukończony żeby śledzić swój postęp



Komentarze

  • Z dnia: Mohamed Saleem napisał:

    This was one amazing tutorial for me. I have been searching something like this for a long time. Thanks you very much..
  • Z dnia: Brunitob napisał:

    There is a ";", you need to remove it. Then its perfect

    .users .panel-body {
    padding: 0;
    p {
        margin: 10px;
        overflow-x: scroll;
    }
    &;:hover {
        background-color: #fcfcfc;
        box-shadow: 0 0 3px #b7b7b7;
    }
    

    }

  • Z dnia: Brunitob napisał:

    Before hover.

  • Z dnia: Muzyka Bartek napisał:

    Thanks! Already fixed.

Dodaj komentarz

Możesz się zalogować by skomentować