Bygg Instagram av Ruby on Rails (del 2)

Ladda upp foto för post och ladda upp Avatar för användare

Tidigare inlägg:

Del 1: medium.com/luanotes/build-instagram-by-ruby-on-rails-part-1

Vad lär du dig efter att ha läst artikeln?

  • CRUD i aktiv post
  • Association in Active Record
  • Validering i aktiv post
  • Aktiv lagringsfunktion i Rails 5.2
  • Pagination med Kaminari pärla.

Innehållsförteckning:

  • Skapa postmodellen.
  • Förening mellan användar- och postmodeller.
  • Använda aktiv lagring för att bifoga en bild i ett inlägg.
  • Skapa ett nytt inlägg och lägg till validering till inlägget.
  • Visa inlägg på hemsidan och användarprofilsidan.
  • Använda Kaminari-pärla för att paginera inlägg.
  • Ladda upp Avatar till användaren.

Skapa postmodellen

Modeller i Rails använder ett singelnamn, och deras motsvarande databastabeller använder ett flertalnamn. För att skapa Post-modell använder vi generator av Rails och skriver kommando i din terminal:

rails genererar modell inlägg Beskrivning: sträng user_id: heltal

Detta kommando genererar ett gäng filer:

Kör via Spring-förladdaren i process 5011 åberopa active_record skapa db / migrera / 20180922091640_create_posts.rb skapa app / models / post.rb åberopa test_unit skapa test / models / post_test.rb skapa test / fixtures / posts.yml

Nu måste vi överväga 2 filer är app / models / post.rb och db / migrate / 20180922091640_create_posts.rb

Öppna db / migrate / 20180922091640_create_posts.rb i redigeraren:

klass CreatePosts 
      t.stämplar end end end

Denna fil är en migrering kommer att skapa inläggstabell med 2 kolumner: beskrivning (typsträng) och user_id (typ heltal).

Kör migreringen för att köra skapa inläggstabell:

rails db: migrera

och se resultatet:

== 20180922091640 CreatePosts: migrera ===================================== - create_table (: posts) ) -> 0.0404s == 20180922091640 CreatePosts: migrated (0.0405s) ==============================

Mer information om migrering, se Active Record Migrations.

Open Post-modell: app / models / post.rb

klass Inlägg 

Detta är inläggsmodell som mappats till en inläggstabell i vår databas.

Lägg till en koppling mellan användare och postmodeller

I vår designdatabas har varje användare många inlägg i relationer, så vi behöver associeringar mellan User och Post-modeller. Det kommer att göra vanliga operationer enklare och enklare i din kod.

Active Record-stödfunktioner för att förklara föreningar enkelt. Utan föreningar:

klass Användare 
klass Inlägg 

Efter att ha förklarat en förening:

klass Användare 
klass Inlägg 

En has_many association indikerar en en-till-många-koppling till en annan modell.

Och beroende:: förstöra alternativet indikerar att alla tillhörande inlägg kommer att förstöras när användaren förstörs.

Presentera aktiv lagring

Aktiv lagring är en fantastisk funktion i Rails 5.2. Den är utformad för att ladda upp filer till en molnlagringstjänst som Amazon S3, Google Cloud Storage eller Microsoft Azure Storage och koppla dessa filer till Active Record-objekt.

Active Storage kommer med en lokal diskbaserad tjänst för utveckling och testning.

Konfigurera aktiv lagring:

Kör kommando:

rails active_storage: installera

Det kommer att skapa en migreringsfil så här: db / migrate / 20180924134051_create_active_storage_tables.active_storage.rb

Och kör sedan rails db: migrera för att utföra migreringen.

$ rails db: migrera
== 20180924134051 CreateActiveStorageTables: migrering ============ - create_table (: active_storage_blobs) -> 0,0576s - create_table (: active_storage_attachments) -> 0.0106s == 20180924134051 CreateActiveStorageTablessables :ated ==

Migreringen skapar två tabeller är: active_storage_blobs och active_storage_attachments som Active Storage använder för att lagra filer.

Konfigurera tjänster där lagra filer:

Active Storage deklarerar tjänster i config / storage.yml. Öppna den här filen, du kan se standardkonfigurering som nedan:

test: service: Diskrot: <% = Rails.root.join ("tmp / lagring")%>
local: service: Disk root: <% = Rails.root.join ("lagring")%>

Denna konfiguration som betyder att vår ansökan förklarar två tjänster som heter test och lokala. Båda dessa tjänster använder disketjänst.

Du kan lägga till fler andra tjänster. Till exempel kan vi lägga till ny tjänst med namnet amazon till config / storage.yml:

amazon: service: S3 access_key_id: your_access_key_id secret_access_key: your_secret_access_key region: us-east-1 hink: your_own_bucket

Varje miljö använder ofta en annan tjänst.

I utvecklingsmiljön kan vi använda Disk-tjänsten genom att lägga till konfigureringskoden till config / Communities / Development.rb:

# Lagra uppladdade filer på det lokala filsystemet config.active_storage.service =: local

För att använda Amazon S3-tjänsten i produktionen kan du lägga till följande kod i config / Communities / Production.rb:

# Lagra uppladdade filer på Amazon S3 config.active_storage.service =: amazon

Glöm inte att starta om servern när du uppdaterar konfigurationen i varje miljö.

Använda aktiv lagring för att lagra Image in Post

Bifoga bild till inlägg

Vi använder has_one_attached makro för att skapa en en-till-en-relation mellan inlägg och bild. Varje inlägg kan ha en bild bifogad.

klass Inlägg 
  has_one_attached: bild slut

Skapa ett nytt inlägg

Att posta bilder till vår applikation är en huvudfunktion. Varje inlägg kommer att innehålla en bild, beskrivning och användare som skapar inlägg.

Flödet till ett nytt inlägg inkluderar:

  • Skapa postkontroller
  • Lägg till skapa åtgärder i postkontrollern
  • Lägg till ett formulär för att skapa inlägg

Skapa postkontroller:

rails genererar controller Inlägg >> skapa app / controllers / posts_controller.rb åberopa erb skapa app / vyer / inlägg åberopa test_unit skapa test / controllers / posts_controller_test.rb åberopa hjälper skapa app / helpers / posts_helper.rb åberopa test_unit åkalla tillgångar åberopa kaffe skapa app skapa app /assets/javascripts/posts.coffee åberopa scss skapa app / tillgångar / stilark / posts.scss

Lägg till skapa åtgärd:

Vi kommer att lägga till en skapa-åtgärd till Post-controller

def skapa Post.create (post_params)
  omdirigera_ till root_path slut
privat
def post_params params.require (: post) .permit (: beskrivning,: image,: user_id) slut

Den här åtgärden kommer att skapa ett nytt inlägg från params och ladda om sidan (omdirigera till hemsidan).

Lägg till ett formulär för att skapa ett nytt inlägg på hemsidan

HTML-kod för form:

<% = form_for Post.new do | f | %> <% = f.text_field: beskrivning%> <% = f.file_field: image%> <% = f.text_field: user_id, värde: current_user.id, klass: 'd-none'%> <% = f.sänd in 'Skapa inlägg', klass: 'btn btn-primär'%> <% slut%>

Vi använder File_field-hjälpmetoden för att ladda upp bild.

<% = f.file_field: image%>

user_id är user create post, det betyder att det är current_user och vi döljer det här fältet i formen av 'd-none' CSS-klass.

<% = f.text_field: user_id, värde: current_user.id, klass: 'd-none'%>

Lägg till nya rutter och skapa åtgärder för Post:

resurser: inlägg, bara: [: nytt,: skapa]

CSS-kod:

.form-upload {border: 1px solid #dbdbdb; höjd: auto; marginal: auto 160px; stoppning: 30px; gränsradie: 3px;
input [type = 'text'] {bredd: 100%; }}
Form Skapa ett nytt inlägg

Lägg till validering i inlägget

För närvarande har vi ett litet fel när skicka formulär skapa inlägg när inte lägg till någon bild. Det skapar ett nytt inlägg utan bild och visar felen på hemsidan:

Det går inte att lösa bilden till URL: to_model delegerad till bilaga, men bilagan är noll

Ovanstående fel som betyder att bildfästning av inlägg är noll. Så nu kommer vi att validera inlägg innan vi skapar för att se till att varje inlägg måste ha en bild.

Eftersom Active Storage ännu inte har stöd för validering för bifoga filer måste vi använda en anpassad metod för att validera bild i Post.

Lägg till validering till postmodellen:

klass inlägg 
  validera: image_presence
def image_presence Error.add (: bild, "kan inte vara tom") såvida inte image.attached? slutändan

Vi använder image_presence för att validera inlägg. Metoden kommer att lägga till ett fel med meddelandet kan inte vara tomt när du skapar ett nytt inlägg utan bild (om inte image.attached?) Och sedan kommer inlägget att vara ogiltigt och inlägget kan INTE skapa.

När valideringsmetoder körs?

Innan Spara ett Active Record-objekt kör Rails våra valideringar. Om dessa valideringar ger några fel sparar Rails inte objektet.

Prova det i din konsol:

post = Post.new (beskrivning: "abc", user_id: User.last.id) => #
post.save # => falsk
post.valid? # => falsk
post.errors.messages # => {: image => ["kan inte vara tomt"]}
post.image.attached? # => falsk

Nu har våra inlägg alltid bilder efter validering i Post-objekt.

Visa inlägg på hemsidan

När vi har lagt till nya inlägg framgångsrikt kommer vi i det här steget att visa dem på hemsidan. Vi visar alla inlägg och ordning efter skapat_at-fältet.

Post.all.order (skapad_at:: desc)

I HomeController lägger du till inläggsvariabel som innehåller alla beställda inlägg för att indexera åtgärder.

klass HomeController 

I view: app / views / home / index.html.erb, visar vi inlägg:

<% @ posts.each do | post | %> <% slut%>

Ett inläggssektion innehåller avataranvändares, användarnamn, bild och beskrivning. Vi använder tillfälligt en standardbild för avataranvändarna. Och visa bild av inlägget av:

<% = image_tag post.image, class: 'main-image'%>

HTML-kod för avsnitt:

<% = post.user.usnamn%> <% = image_tag post.image, class: 'main-image'%> <% = post.beskrivning%>

CSS-stil:

.posts {marginal: 50px 180px 10px;
.post {border: 1px solid #efefef; marginal: 60px 0; gränsradie: 3px; .användare {border-bottom: 1px solid #efefef; display: flex; .avatar {bredd: 30px; marginal: 8px;
img {bredd: 100%; kant: 1px solid #efefef; gränsradie: 50%; }} .namn {padding-top: 13px; färg: # 262626; teckenstorlek: 14px; font-vikt: 600; }}
.main-image {bredd: 100%; border-bottom: 1px solid # f4f4f4; } .beskrivning {polstring: 20px; }}}

Inlägget ser ut som:

Ett inlägg på hemsidan

Visa inlägg på sidan Användarprofil

I det här steget visar vi inlägg från användaren på deras profilsida. Jag ska ersätta tillfälliga bilder med bilder som användare har lagt ut.

Eftersom användare och inlägg har has_many associering, betyder det att en användare har många inlägg, så vi kan enkelt hämta inlägg av användare av current_user.posts

I show action of UsersController, lägg till en inlägg instansvariabel samma på hemsidan, det är inlägg för den aktuella användaren vilken ordning efter skapat_at-fältet.

def show @posts = current_user.posts.order (create_at:: desc) slut

Uppdatera HTML-kod i avsnittet användarbilder:

<% @ posts.each do | post |%> <% = image_tag post.image%> <% slut%>

Uppdatera antalet inlägg för aktuell användare:

... <% = @ posts.count%> inlägg

Ja, se fantastiskt ut !!!

Lägg till pagination för inlägg

Vi kan enkelt implementera pagination i Rails med kaminari-pärla.

Kaminari är en Scope & Engine-baserad, ren, kraftfull, anpassningsbar och sofistikerad paginator för moderna webbappsramar och ORM.

Kaminari pärla lätt att använda: vi buntar bara pärlan, då är dina modeller redo att bli paginerade. Ingen konfiguration krävs. Behöver inte definiera något i dina modeller eller hjälpare.

Installation

För att installera kaminari i vår applikation, lägg den här raden i din Gemfile:

pärla 'kaminari'

Kör sedan bunt:

paket installera

Hur man använder Pagination för inlägg

I hemkontrollen:

Koden ser ut så här:

@posts = Post.order (create_at:: desc) .sida (params [: page]). per (5)

Sidomfånget: Att hämta den (n): e sidan till inlägg.

Exempel: Post.sida (3) som betyder att den hämtar den 3: e sidan i Posten.

Obs: Paginering börjar på sida 1, inte på sida 0, sida (0) ger samma resultat som sida (1).

Perfältet: För att visa antalet inlägg per sida är standard per_sida 25.

Exempel: Post.sida (3) .per (5) det betyder 5

I vyer:

Ring den paginathjälpen:

<% = paginera @users%>

Detta kommer att göra flera? Page = N paginationslänkar omgiven av en HTML5 märka. Detta skulle producera flera sidlänkar såsom:

«Första‹ Föregående ... 2 3 4 5 6 7 8 9 10 ... Nästa ›Sista»

Lägg till paginathjälper för att visa: home / index.html.erb

<% @ posts.each do | post | %> ... <% end%> <% = paginera @posts%>

Gå till hemsidan och ladda om sidan igen, se vad som händer (glöm inte att lägga till mer än 5 inlägg, eftersom vi konfigurerar per_sida är 5).

Bläddra till botten av sidan så ser vi sidlänkarna:

Paginationslänkar

Du kan se sidlänkarna: 1 2 3 4 Nästa ›Sista», UI är inte vacker. Vi lägger till några CSS nedan för att göra det bättre:

.hemsida {[...]
.pagination {span {padding-höger: 10px; }}}

Lägg till en Avatar till användaren

Använda aktiv lagring för att lägga till en avatar för användare

I modell

Eftersom varje användare har en avatar, så definiera användarmodellen så här:

klass Användare 
  has_one_attached: avatar
slutet

I Visa (Form redigera användare)

<% = f.märke: avatar, klass: 'col-sm-3 col-form-label'%> <% = f.file_field: avatar, klass: 'form-control'%>

I kontrollenhet:

Lägg till avatar till starka params

def user_params params.require (: user) .permit (: användarnamn,: namn,: webbplats,: bio,: e-post,: telefon,: kön,: avatar) slut

Nu kan vi gå till sidan Redigera användare för att ladda upp en avatar för användaren.

Visa användarens Avatar:

Byt ut allt där du använder en tillfällig bild av användarens avatar:

  • På sidan Användarprofil (användare / show.html.erb)
<% om current_user.avatar.attached? %> <% = image_tag current_user.avatar%> <% end%>
  • På sidan för formulärredigering (användare / edit.html.erb)
<% = form_med modell: aktuell_användare, lokal: sann, html: {klass: "form-horisontell form-redigera-användare"} do | f | %> <% om current_user.avatar.attached? %> <% = image_tag current_user.avatar, klass: 'avatar'%> <% end%> ... <% slut%>
  • På hemsidan (home / index.html.erb)

Avataranvändare av varje inlägg:

<% om post.user.avatar.attached? %> <% = image_tag post.user.avatar%> <% slut%> ...

Ring user.avatar.attached? för att avgöra om en användare har en avatar.

Visa andra Användarprofil genom att klicka på sin Avatar.

Uppdatera show-åtgärden i UsersController:

Ändra aktuell_användare av en användare som frågar efter id

klass UsersController 
  def show @user = User.find (params [: id]) @posts = @ user.posts.order (create_at:: desc) slut

På hemsidan (home / index.html.erb):

Lägg till länkar för avatar och användarnamn för användaren som går till användarprofilsidan.

<% om post.user.avatar.attached? %> <% = link_to user_path (post.user) do%> <% = image_tag post.user.avatar%> <% end%> <% end%> <% = link_to post.user.username, user_path (post.user), klass: 'användarnamn'%>

Nu på hemsidan kan vi klicka för att avatar eller användarnamn för användaren för att se detaljer om deras profil.

Slutsats

I den här artikeln hjälper jag dig att lära dig detaljer om modell (Active Record) som: skapa en ny modell, valideringar, associering. Introduktion om Active Storage-funktionen och hur man använder den för att ladda upp bilden. Slutligen, hur man använder Kaminari pärla i pagination.

Fullständig kod på Github: https://github.com/thanhluanuit/instuigram

Relaterade inlägg:

  • Del 1: medium.com/luanotes/build-instagram-by-ruby-on-rails-part-1
  • Del 3: medium.com/luanotes/build-instagram-by-ruby-on-rails-part-3

referenser:

  • Aktiv post: guides.rubyonrails.org/active_record_basics.html
  • Aktiv lagring: guides.rubyonrails.org/active_storage_overview.html
  • Kaminari: https://github.com/kaminari/kaminari