Lista Użytkowników - Profil i Indeks Profilów
Przez: Lukasz Muzyka, Z dnia:
Ten tutorial zakłada, że już ukończyłeś:
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
Profil Użytkownika
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
Komentarze
Dodaj komentarz
Możesz się zalogować by skomentować
Z dnia: Mohamed Saleem napisał:
Z dnia: Brunitob napisał:
There is a ";", you need to remove it. Then its perfect
}