Aplicatie Ruby On Rails

Aplicație Ruby on Rails

INTRODUCERE

Aplicația are ca scop administrarea de evenimente, conferințe sau întâlniri ce pornesc de la un scară medie spre foarte mare. Când vorbesc de scară, mă refer la un număr foarte mare de participanți, la numărul de ateliere, magazine, activități, dar nu numai, mă refer inclusiv la perioada în care se desfășoară evenimentul. Evenimentele pe care aplicația le cuprinde tind să fie foarte complexe, cu numeroase activități care necesită o evidență manuală dificil de ținut. Organizatorii pun la dispoziția participanților, sub formă de pliante, broșuri, programul activităților, o hartă a complexului, diferite informații precum parola de acces la WiFi, lista cu invitați speciali și multe alte documente specifice fiecărui eveniment, informații pe suport manual care necesită spațiu, timp și costuri.

O altă dificultate în organizarea de astfel de evenimente este administrarea lor, anunțarea anumitor activitați în timpul evenimentului, informații importante precum bunuri pierdute, probleme tehnice, amânări, etc.

Aplicația ajută la simplificarea acestor probleme, oferă organizatorului o interfață ușor de folosit și intuitivă, ce are la dispoziție utilitățile de bază pentru a crea structura unui astfel de eveniment. Se poate construi un program, o agendă, lista cu invitații, se pot trimite invitații și anunțuri către participanți, etc. Aplicația permite și adăugarea de activități, având fiecare descrierea ei, data, durata, lista cu reprezentanți.

Scopul aplicației nu este numai de a veni în ajutorul organizatorului, dar și de a ajuta participanții, astfel ei pot renunța la pliante, broșuri, liste, având acces la toate informațiile chiar de pe telefonul mobil, smartphone. Participanții pot accesa pagina web a evenimentului, se pot înregistra cu adresa de email pe care au primit invitația și pot vizualiza toate informațiile necesare. Își pot crea o agendă personalizată și pot comunica între ei printr-un sistem de chat sau mesagerie internă. Aplicația permite până și personalizarea unui profil cu date precum nume, email, website personal, telefon, conturi de socializare, biografie, compania, etc.

În dezvoltarea aplicației am optat pentru platforma Ruby on Rails întrucât oferă utilitățile necesare pentru o dezvoltare rapidă, este ușor de folosit și configurat și are la bază arhitectura MVC.

Primul capitol definește aplicațiile web. Prezintă funcționalitatea, limbajele și tehnologiile de bază utilizate în dezvoltarea lor. De asemenea, descrie modul în care informația este stocată într-o bază de date și sistemul prin care este accesată.

Al doilea capitol cuprinde dezvoltarea aplicațiilor în platforma Ruby on Rails. Este definit limbajul Ruby folosit la crearea platformei și prezintă componentele de bază ale arhitecturii MVC. Se detailează structura fizică a unei astfel de aplicații și se prezintă tehnici de testare.

Capitolul trei prezintă structura specifică aplicației ce are la bază ideea de administrare de evenimente. În cadrul acestuia sunt explicate amănunțit toate componentele: structura bazei de date, clasele asociate fiecărui tabel, controllere și view-uri.

Ultimul capitol parcurge fiecare pas pe care utilizatorul îl poate urma pentru a beneficia de toate facilitățile aplicației. Ghidul prezintă căile de urmat pentru fiecare tip de utilizator în parte: organizator sau participant.

1. APLICAȚII WEB

1.1 Ce sunt aplicațiile web?

Aplicațiile web sunt programe stocate pe un server ce sunt transmise prin internet si executate într-un browser, permițând utilizatorilor să interacționeze cu serverul pentru a accesa sau trimite informații.

Browserul este aplicația software ce permite utilizatorilor să acceseze conținutul aflat pe

Internet cum ar fi: imagini, poze, video, pagini web etc. Prezența acestuia în majoritatea sistemelor de operare fac ca aplicațiile web să fie populare și simplu de folosit. Browserele folosesc un limbaj comun pentru a procesa si reprezenta informatia primita de la server. Limbajul pe care browserul îl folosește este de fapt o combinație de mai multe tipuri de limbaje, cum ar fi: HTML(markup), CSS(stylesheet), JavaScript (programare).

Un prim avantaj al aplicațiilor web față de aplicatiile software este lipsa necesității utilizatorului de a le actualiza constant la ultima versiune. Actualizarea se realizează de fiecare dată când browserul încarcă aplicația. Un al-2-lea avantaj, chiar foarte important, este faptul că utilizatorul nu trebuie să instaleze un program specific fiecărei aplicații în parte, totul rulând în browser. Alt avantaj este disponibilitatea lor în orice perioadă din zi.

1.2 Cum funcționează aplicațiile web?

Transmiterea și funcționalitatea aplicațiilor web au la baza protocolul HTTP (Hypertext Transfer Protocol). HTTP este un protocol de tip text care funcționează ca un protocol de tip cerere-raspuns și se folosește de modelul client-server pentru a comunica. În cazul aplicațiilor web, clientul care face cererea către server este browserul, acesta apoi așteaptă ca serverul să îi răspundă.

Răspunsul furnizat de server numit și serviciu este chiar aplicația web, mai exact fișierele text HTML, CSS, JavaScript de care browserul are nevoie pentru a executa aplicația.

În protocolul HTTP informațiile cererilor vechi se pierd, fiind un protocol fără reținere a stării. Pentru a reține informații referitoare la o anumită stare se pot însă utiliza cookie-urile atașate

headerului cererii HTTP.

Protocolul HTTP furnizează mai multe metode prin care se pot face cereri:

GET: este cea mai folosită metodă, fiind utilizată atunci când serverului i se cere o resursă;

HEAD: se comportă exact ca metoda GET, dar serverul returnează doar antetul resursei, ceea ce permite clientului să inspecteze antetul resursei, fără a fi nevoit să obțină și corpul resursei;

PUT: metoda este folosită pentru a depune documente pe server, fiind inversul metodei GET;

POST: a fost proiectată pentru a trimite date de intrare către server;

DELETE: este opusul metodei PUT;

TRACE: este o metodă folosită de obicei pentru diagnosticare, putând oferi mai multe informații despre traseul urmat de legătura HTTP, fiecare server proxy adăugându-și semnătura în antetul via al cererii;

OPTIONS: este folosită pentru identificarea capacităților serverului Web înainte de a face o cerere către acesta;

CONNECT: este o metodă folosită în general de serverele intermediare.

Aplicațiile simple sunt structurate pe un singur nivel, care se află pe calculatorul utilizatorului, în cazul aplicațiilor web numărul de nivele folosite pentru a le structura este nelimitat.

Cea mai comuna structura este cea care folosește 3 nivele: prezentare, aplicație si stocare. După cum se înțelege și din denumire nivelul prezentare este browserul în sine, acesta proceseaza informația și o afișează. Al-2-lea nivel este alcătuit din motorul/tehnologia care generează dinamic conținutul (PHP, ASP, Node.js, Ruby on Rails, etc.), acesta se află de obicei pe un server aflat la distanța, însă poate fi și local. Al-3-lea nivel este alcătuit din baza de date, locul unde este stocată informația.

Pentru acest tip de structură, funcționalitatea este destul de simplă: browserul trimite o cerere către nivelul 2, acesta procesează cererea și execută operațiile necesare asupra bazei de date, apoi trimite răspunsul inapoi browserului. În concluzie aplicațiile web sunt de fapt porți ce oferă accesul către informații stocate într-o bază de date.

1.3 Tehnologii web

1.3. 1. HTML (HyperText Markup Language)

HTML este un limbaj de marcare folosit în crearea paginilor web. Scopul acestuia este de a putea construi și reda vizual documente text care includ o multitudine de stiluri, decorațiuni și elemente grafice.

Limbajul oferă mijloace cu care se pot crea documente ce conțin structuri semantice precum paragrafe, titluri, liste și nu numai. Acesta mai oferă posibilitatea de a include imagini, fișiere video si audio, fișiere de tip script, ce pot modifica comportamentul paginilor web, oferind o experiență unică utilizatorului. De asemenea, elementele de design nu lipsesc, cu ajutorul limbajului CSS documentelor HTML li se pot definii structuri și diferite aspecte grafice.

HTML oferă mijloace de a personaliza documente începând de la cele mai mici decorațiuni pe care un text le poate avea până la scripturi, formulare interactive, liste, tabele, etc. Alte informații pe care un document HTML le poate conține sunt numite metadate, ele includ date despre titlu, autor, descriere, informații structurale și cuvinte cheie.

Un limbaj de marcare este un set de etichete, marcatoare numite și taguri cu rolul de a aduce informații ce țin de structură sau prezentarea textului. Fiecare tag în parte are proprietăți unice ce ajută la construirea structurii documentului html. Tagurile sunt de fapt cuvinte cheie care au înainte și după ele simbolurile ,,<” și ,,>” (<head></head>), acestea comunică browserului cum să formateze și să afișeze conținutul. Când browserul citește documentul html, nu afișează tagurile, ci le procesează, iar conținutului aflat între acestea îi sunt aplicate caracteristicile specifice tagului respectiv. De exemplu <strong>Hello World!</strong> este afișat de către browser astfel: Hello World!, tagul în care textul de mai sus este înfășurat are proprietatea de a îngroșa conținutul din interior.

Orice document html trebuie să respecte o structură anume pentru a fi valid, mai exact acesta trebuie să conțină tagurile esențiale pentru ca browserul să îl poată ințelege.

Tagurile esențiale sunt:

<html></html>

Definește începutul și sfârșitul documentului html. Restul tagurilor trebuie să se afle în interiorul acestuia.

<head></head>

Acesta conține informații despre documentul html și nu este vizibil în reprezentarea vizuală. Conține detalii precum: titlu, autor, descriere, pagini de stil, scripturi, metataguri.

<title></title>

Definește titlul documentului, apare în interiorul tagului <head>. Este afișat în bara de titlu a browserului.

<body></body>

Este tagul ce conține toate informațiile vizibile ale documentului. Toate linkurile, imaginile, textul, tabele, liste, etc. trebuie să se afle în acest tag.

Exemplu de document html:

<!DOCTYPE html>

<html>

<head>

<title>Document</title>

</head>

<body>

<p>Hello World!</p>

</body>

</html>

Orice fișier html trebuie să înceapă cu instrucțiunea: <!DOCTYPE html> care spune browserului ce versiune de html să folosească. Se observă în continuare că totul este cuprins de tagul html, cum în interiorul tagului head se află title, iar imediat după inchiderea tagului head începe tagul body.

1.3. 2. CSS (Cascading Style Sheets)

CSS este un limbaj pentru stilizarea și formatarea elementelor unui limbaj de marcare cum este HTML. Acesta conține instrucțiuni care acoperă o arie largă de elemente grafice, aplicabile tagurilor HTLM. Stilurile se pot adăuga elementlelor HTML prin intermediul fișierelor externe, cu ajutorul tagului <style></style> ce se află în tagul head sau prin atributul style atașat fiecarui element html în parte.

Limbajul CSS a fost contruit pentru a separa conținutul unui document de elementele grafice cum ar fi: fonturi, culori, aranjări în pagină. Această separare îmbunătățește accesiblitatea la conținutul documentului, mărește flexibilitatea și controlul cu care sunt manipulate reprezentările vizuale și permite distribuirea acelorași reguli de stil mai multor pagini HTML prin intermediul fișierelor externe. Un alt avantaj al separării conținutului de stil este faptul că aceeași pagină poate fi reprezentată în diferite stiluri pentru diferite moduri de afișare, de exmplu: screen(ecran de calculator), print(pentru imprimante), handheld(pentru dispozitive mobile), projection(pentru proiectari, slideuri), etc.

Pentru a putea accesa tagurile HTML programatorul se folosește de selectori CSS. Selectorii CSS sunt tipare cu care se pot identifica taguri HTML pentru a putea fi formatate și stilizate, și sunt de mai multe tipuri: universal, de tip, descendenti, de atribut, de clasa, de ID etc.

Un selector simplu poate să fie un selector de tip sau un selector universal urmat de 0 sau mai mulți selectori de atribut, ID sau clasă. Selectorul de tip lanț este alcătuit din mai mulți selectori legați între ei cu ajutorul combinatorilor (spațiu, ,,>” sau ,,+”).

Exemple de selectori:

universal (*) – se referă la toate elementele;

de tip (h1, p, div, etc.) – este de fapt chiar cuvantul cheie al tagului din limbajul de marcare folosit;

descendent (div p) – se referă la element ,,p” descendent al lui ,,div”;

de atribut (input[name=“email”]) – cuprinde toate elementele de tip ,,input” ce conțin atributul ,,name’’ și are valoarea ,,email’’;

de clasă (div.email) – selectează toate elementele al căror cuvânt cheie este ,,div” și au atributul ,,class’’ cu valoarea ,,email”;

de ID (#email) – sunt selectori unici, se aplică primului element găsit care are atributul ,,id’’ cu valoarea ,,email’’. În fișierul HTML nu trebuie să se găsească mai mult de un element cu atributul ,,id” si aceeași valoare pentru el.

Posibilitatea de a crea stiluri individuale pentru diferite moduri de afișare și diversitatea selectorilor CSS a dus la apariția conceptului de Responsive Web Design. Această abordare se referă la capacitatea unui website, unei aplicații web de a se adapta la diferite rezoluții și dispozitive. Conceptul a apărut ca urmare a varietății foarte mari a dispozitivelor mobile (telefoane mobile, tablete, etc), acestea având o multitudine de rezoluții pornind de la 320px pana la 2560px sau chiar mai mari, pe care programatorii nu aveau cum să le cuprinda în totalitate. Înainte de apariția acestui concept majoritatea aplicațiilor web aveau la bază structuri cu griduri fixe care nu puteau să se adapteze în funcție de tipul dispozitivului, dimensiunea ecranului sau a rezoluției, astfel a aparut un sistem flexibil de griduri care se bazează pe calculul proporțiilor și se asigură că toate elementele din structura sunt redimensionate unul față de celălalt. Nu se mai măsoară dimensiunile în pixeli, ci în unități relative și procente. Imaginile nu mai există într-o singură dimensiune, ele se găsesc pe server în seturi de câte 2-3 sau chiar 4 dimensiuni, din care va fi încărcată mai apoi imaginea potrivită, în funcție de dimensiunea ecranului pe care este afișată aplicația.

Acest concept vine însă și cu dezavantaje, timpul necesar dezvoltării unei aplicații crește semnificativ, deoarece complexitatea structurii duce la mărirea dificultății. Un alt dezavantaj îl prezintă problemele de compatibilitate între browsere, însă de aici pornește apariția frameworkurilor CSS care înglobează o varietate de utilități pentru a micșorarea timpului de lucru și reducerea dificultății.

Frameworkul este un mediu software care furnizează o funcționalitate generică și care poate fi modificat selectiv oferind astfel utilități specifice unei aplicații.

Frameworkurile CSS aduc imediat noțiunea de sistem de grid flexibil, vin cu stiluri predefinite, elemente grafice, meniuri gata funcționale pentru orice tip de dispozitiv, butoane, liste, tabele și multe altele. Ele reduc pe cât de mult posibil problema compatibilității între browsere și măresc productivitatea. Unele dintre cele mai avansate vin și cu funcții JavaScript predefinite.

Exemple de frameworkuri CSS: Bootstrap, Foundation, Gumby, etc.

1.3. 3. JavaScript

JavaScript este un limbaj de programare orientat pe obiect, interpretabil și folosit în special pentru introducerea unor funcționalități în aplicațiile web. Fiind un limbaj interpretabil, acesta este executat de browser. Permite implementarea de scripturi care să ruleze pe mașina clientului. Este un limbaj care poate comunica asincron cu serverul, alterând astfel documentul HTML. Acesta ajută la construirea de pagini dinamice în cadrul unei aplicații web, poate manipula structura aplicației web, poate schimba stilul, adauga sau sterge atribute elementelor HTML, poate insera sau elimina etichetele HTML din cadrul documentului.

Ca și în cazul CSS-ului, a apărut nevoia de a construi biblioteci care să ajute programatorii să crească productivitatea și să micșoreze timpul necesar implementării diferitelor funcționalități. Una dintre astfel de biblioteci este jQuery.

jQuery, poate cea mai folosită biblioteca de JavaScript, face ca parcurgerea unui document HTML și manipularea, crearea de animații si trigeri să fie foarte ușor de folosit. Aceasta vine cu un set de funcții predefinite care funcționeaza pe majoritatea browserelor fără a exista probleme de compatibilitate.

1.3. 4. JSON (JavaScript Object Notation)

JSON sau JavaScript Object Notation este un format de reprezentare și interschimb de date între aplicații informatice. Este un format text, inteligibil pentru oameni, utilizat pentru reprezentarea obiectelor și a altor structuri de date și este folosit în special pentru a transmite date structurate prin rețea, procesul purtând numele de serializare.

Acesta a fost creat ca o alternativă a limbajului XML cu scopul de a fi mai simplu. Simplitate lui vine de la faptul că este un subset al limbajului JavaScript. De fapt structura lui este aceeași cu structura de inițializare a unui obiect JavaScript.

Tipurile de date pe care formatul JSON le suportă sunt:

Number, numere de tip întreg, cu sau fara zecimale;

String, o secvență de 0 sau mai multe caractere Unicode;

Boolean, valori de adevăr, true sau false;

Array, o listă ordonată de 0 sau mai multe elemente;

Object, o colecție de perechi neordonate de forma cheie – valoare;

Null, o valoare goală.

Exemplu de JSON:

{

"firstName": "John",

"lastName": "Smith",

"age": 25,

"address": {

"streetAddress": "21 2nd Street",

"city": "New York",

},

"phoneNumbers": [

{

"type": "home",

"number": "212 555-1234"

}

],

}

1.3. 5. AJAX (asynchronous JavaScript and XML)

AJAX este o tehnică de programare ce se folosește în partea de front-end pentru crearea de aplicații web interactive. Prin AJAX aplicațiile web pot trimite sau cere informații asincron fară a interveni în asupra interfeței grafice. Folosind AJAX nu mai este necesară reîncarcarea paginii pentru a actualiza informația sau pentru a trimite date către server.

AJAX nu este o singură tehnologie, ci un grup de tehnologii, în care sunt incluse HTML, CSS, JavaScript. Pentru a actualiza interfața cu noile informații venite de la server printr-o cerere făcută asincron folosim JavaScript pentru a manipula elementele HTML sau atributul style ale acestora.

Cererile AJAX sunt construite folosind obiectul XMLHttpRequest din JavaScript.

Scripturile ce fac cereri AJAX se află în partea de client a aplicației web.

Exemplu de scrip ce face o cerere AJAX:

// Initializarea obiectului XMLHttpRequest

var xhr = new XMLHttpRequest();

xhr.open('get', 'send-ajax-data.php');

xhr.onreadystatechange = function () {

if (xhr.readyState === 4) { 4 – cererea a fost făcută

if (xhr.status === 200) { 200 – s-a executat cu succes

alert(xhr.responseText); // afișare text returnat

} else {

alert('Error: ' + xhr.status); // afișare eroare

}

}

};

// Se trimite cererea

xhr.send(null);

1.4 REST (Representational State Transfer)

REST este un model arhitectural pentru crearea serviciilor web care descrie o arhitectură orientata pe resurse. A fost construita pe ideea că cea mai bună metodă de a distribui informație între două sau mai multe părți este de a face informația disponibilă la cerere.

REST se folosește de alte standarde care stau la baza WEBului cum ar fi:

HTTP (Hypertext Transfer Protocol);

URI (Uniform Resource Identifier);

XML (Extensible Markup Language).

Într-o arhitectură de tip REST se deosebesc două trăsături importante:

datele asupra căreia clientul îi spune serverului să opereze se află în URI;

operația pe care serverul o face asupra datelor este descrisă de metoda HTTP.

Din punct de vedere tehnic, arhitectura de tip REST se descrie prin câteva noțiuni de bază : resursă, URI, reprezentare, interfață uniformă.

Noțiunea de resursă este un element ce stă la baza arhitecturii de tip REST, astfel tot ce poate fi referit ca un obiect este o resursă. Resurse pot fi: un produs pe un site, o imagine, un document de tip .txt, o listă de persoane, etc.

URI vine de la acronimul Uniform Resource Identifier, reprezintă un identificator alfanumeric, univoc și unic în lume. Acesta face parte din definiția unei resurse, el reprezintă numele si adresa resursei. Dacă o anumită informație nu are un URI atunci aceasta nu este o resursă și nu se află pe web. Deși URI –urile sunt unice în lume nu înseamnă că o resursă are un singur URI, aceasta poate avea mai multe, dar un URI nu poate avea mai multe resurse.

Exemple de URI:

http://www.exemplu.com/products/20

http://www.exemplu.com/search/wallaper

http://www.exemplu.com/wiki/URI

http://www.exemplu.com/profile/9299lad

http://www.exemplu.com/photo/mountain

Protocolul HTTP furnizează patru metode de bază ce reprezintă operațiile care se pot aplica unei resurse:

HTTP GET – operația de bază ce face cererea resursei respective;

HTTP POST – operația pentru creare unei resurse;

HTTP PUT – operația pentru modificarea unei resurse;

HTTP DELETE – operația pentru ștergerea unei resurse.

O altă caracteristică importantă a arhitecturii REST este faptul că resursele sunt separate de reprezentare, astfel încât conținutul lor să poată fi accesat în diferite formaturi, spre exemplu: HTLM, XML, JSON, PDF, JPEG, text și altele.

După cum spune și acronimul Representational State Transfer, arhitectura REST nu menține stările, astfel fiecare operație asupra unei resurse transferă clientul într-o altă stare.

Niciun fel de informație nu este păstrată pe server între cereri. Fiecare cerere trebuie să conțină toate informațiile necesare pentru a executa cu succes operația. Starea sesiunii este păstrată în client, iar pentru a o menține pe o perioadă mai lungă de timp, aceasta poate fi stocată într-o bază de date. Arhitectura are la baza modelul client-server pe care protocolul HTTP îl promovează, astfel serverul și clientul sunt complet separate. Serverul nu conține informații despre interfață și starea clientului, iar clientul nu are nevoie de informații legate de baza de date sau alte moduri de stocarea informației. Separarea clientului de server aduce scalabilitate mărită arhitecturii REST.

Exemple de servicii de tip REST: google.com, amazon.com, twitter.com, etc.

1.5 Baze de date

Baza de date este un ansamblu structurat de date coerente, fără redundanţă inutilă, astfel încât acestea pot fi prelucrate eficient de mai mulţi utilizatori într-un mod concurent. Baza de date este o colecţie de date pe persistente, care sunt folosite de către sistemele de aplicaţii. Datele din baza de date persistă deoarece, după ce au fost acceptate de către sistemul de gestiune pentru introducerea în baza de date, ele pot fi şterse din bază numai printr-o cerere explicită adresată sistemului de gestiune. O bază de date este accesată și interogată prin intermediul unui sistem de gestiune.

Un sistem de gestiune a bazelor de date (SGBD) este o aplicație software care interacționeaza cu utilizatorul, alte aplicații și baza de date. Acesta permite definirea, consultarea, actualizarea și administrarea datelor unei baze de date.

În cadrul unei baze de date putem vorbi de patru niveluri de abstractizare şi de percepţie a datelor: intern, conceptual, logic şi extern. Datele există doar la nivel fizic, iar celelalte trei niveluri reprezintă virtualizări ale acestora.

• Nivelul fizic (intern) este descris de schema fizică a datelor (bit, octet, adresă);

• Nivelul conceptual este descris de schema conceptuală a datelor (articol, înregistrare, zonă) şi reprezintă viziunea programatorilor de sistem asupra datelor;

• Nivelul logic este descris de una din schemele logice posibile ale datelor şi reprezintă viziunea programatorului de aplicaţie asupra datelor;

• Nivelul virtual (extern) reprezintă viziunea utilizatorului final asupra datelor.

Bazele de date sunt folosite pentru a stoca informații precum date bancare, inventar, liste cu angajați, rezervări etc. Informațiile sunt stocate in fișiere pe disc sub diferite forme.

O bază de date poate fi de mai multe tipuri, însă cel mai des întâlnit este modelul relațional. Modelul determină structura logică, cum informațiile vor fi stocate și organizate. Acest tip de baza de date stochează informația în tabele. Fiecare tabel având structura proprie, specifică informației dorite.

Modelul relațional se folosește de noțiunea de normalizare, scopul este de a asigura faptul că fiecare element în parte (informatia) este stocată într-un singur loc astfel încât să se poată păstra o bază de date cât mai consistentă.

Majoritatea bazelor de date relaționale folosesc limbajul SQL pentru a administra datele conținute de acestea.

SQL este împărțit în mai multe elemente: clauze, expresii, predicate, interogări și instrucțiuni. Clauzele sunt componente ale instrucțiunilor și interogărilor. Expresiile produc valori scalare sau tabele. Predicatele sunt condiții evaluate. Interogările găsesc informațiile specifice unor criterii impuse. Instrucțiunile sunt comenzi SQL care afectează tranzacții, structura datelor, conexiuni etc.

Exemplu de interogare SQL:

SELECT [ALL | DISTINCT] coloana1 [,coloana2]

[INTO fișier]

FROM tabel1 [,tabel2]

[WHERE condiție] [ AND|OR condiție…]

[GROUP BY listă-coloane]

[HAVING condiții]

[ORDER BY listă-coloane [ASC | DESC] ]

Clauzele sunt: INTO, WHERE, GROUP BY, HAVING, ORDER BY.

Pentru manipularea datelor, SQL oferă diferite instrucțiuni, acest grup de instrucțiuni se numește limbaj pentru manipularea datelor (DML) și el este de fapt un subset al limbajului SQL.

Instrucțiunile DML sunt:

INSERT inserează un articol într-un tabel;

UPDATE actualizează un articol sau un set de articole;

DELETE șterge un articol sau un set de articole.

Un alt subset al limbajului SQL, este limbajul pentru definirea datelor, acesta conține instrucțiuni de creare, modificare și ștergere a informațiilor sau a structurilor din cadrul bazei de date.

Instrucțiunile DDL sunt:

CREATE TABLE, crează un tabel;

ALTER TABLE, modifică structura unui tabel (redenumire, adăugarea, modificare, ștergere de câmpuri sau indexi și multe altele);

TRUNCATE TABLE, șterge toate intrările, articolele dintr-un tabel;

DROP TABLE, șterge tabelul.

În anumite situații se dorește executarea succesivă a mai multor instrucțiuni SQL, însă din cauza diferitelor probleme (întreruperea conexiunii, defectarea serverului, erori de sistem etc.) ce pot apărea pe parcursul execuției nu ne putem baza pe faptul că toate instrucțiunile au fost executate cu succes și nici nu dorim să păstram doar o parte din informația generată de acestea. Din acest motiv există tranzacțiile.

Tranzacțiile ne ajută să controlăm în ce condiții se desfășoară o succesiune de instrucțiuni pentru manipulare a datelor. Orice tranzacție are un început marcat de comanda ,,BEGIN TRANSACTION’’(începe o noua tranzacție) și un sfârșit marcat de comenzile ,,COMMIT” (acceptă toate tranzacțiile și le face permanente) sau ,,ROLLBACK’’ (refuză toate tranzacțiile). De asemenea, SQL oferă posibilitatea de a salva o tranzacție în starea ei actuală prin comanda ,,SAVE TRANSACTION’’.

Alt subset al limbajului SQL, numit limbajul de control al datelor (DCL), permite personalizarea drepturilor de acces ale utilizatorilor ce accesează baza de date. DCL este un subset cu o importanță destul de mare în administrarea unei baze de date, filtrând accesul la aceasta putem menține confidențialitatea datelor mult mai bine, scăzând altfel riscul unei breșe de securitate.

Confidențialitate datelor, mai ales în cazul unor informații personale ale clienților, este foarte importantă.

Instrucțiunile specifice limbajului DCL sunt:

GRANT, acordă drepturi unui utilizator sau un grup de utilizatori;

REVOKE, elimină drepturi.

2. APLICAȚII WEB ÎN RUBY ON RAILS

2.1 Ruby

Ruby este un limbaj de programare simplu, dinamic, bazat pe simplitate și productivitate. Are o sintaxă simplă ce vine natural și ușor de memorat. Este un limbaj orientat pe obiecte cu o arie de utilități destul de largă. A fost descris ca un limbaj ,,multi-paradigm’’, deoarece suportă mai multe paradigme ale programării cum ar fi: funcțională (pentru că are funcții anonime și acestea întorc predefinit ultima valoarea a ultimei evaluări), orientată pe obiecte (conține clase, există conceptul de moștenire, etc.) și imperativă (se pot defini funcții, variabile în afara claselor).

În Ruby orice element este un obiect plecând de la valori întregi, booleene până la clase și module. Metodele sunt funcții ce fac parte dintr-o clasă și care se aplică doar obiectelor de tipul acelei clase.

Flexibilitatea limbajului reiese din capacitatea de a modifica orice parte a acestuia. Se pot elimina sau redefini funcționalități ale acestuia, dar și adaugarea unora noi.

Ruby este folosit în scripting cum ar fi procesare de texte, executare de sarcini, interacțiunea cu o bază de date și multe altele, însă el este folosit și în creare de aplicații foarte complexe cum sunt aplicațiile web. Unul dintre cele mai complexe și de succes sisteme software implementate în Ruby este frameworkul Ruby on Rails bazat pe arhitectura MVC.

2.2 Arhitectura MVC (model-view-controller)

MVC împarte aplicația în trei componente interconectate, pentru a separa partea din spate (back end) de cea din față (fron tend). Back end reprezintă partea aplicației care se află și se execută pe server, aceasta e și cel care se ocupă cu interogarea bazelor de date, validarea informațiilor venite de la client, etc. Front end este interfața dintre utilizator și back end. Acesta se află și rulează pe mașina clientului, mai exact în browser.

Componentele arhitecturii MVC sunt:

model, reține informația și specificațiile ei;

view, îi corespunde reprezentarea grafică a informației pe care modelul o conține;

controller, controlează accesul la aplicație.

2.2. 1. Model

Modelul este logica aplicației și cel care comunică direct cu baza de date. Acesta menține starea în care se află aplicația la un moment dat, astfel, când aceasta se schimbă, modelul trebuie să anunțe toate view-urile asociate lui pentru a se actualiza. El nu se ocupă de modul în care este prezentată utilizatorului starea aplicației și nici de cum interacționează acesta cu ea. Un model nu conține doar date, contine și funcții care să opereze pe aceste date, fiind și cel responsabil cu validarea datelor. Este o componentă indispensabilă în arhitectura MVC, deoarece nu depinde de celelalte doua (view și controller), însă ele depind în totalitate de el.

2.2. 2. View

View-ul interacționează direct cu utilizatorul. El este reprezentarea grafică a stării în care se află modelul. În framework-urile web ele sunt mai mult niște template-uri (tipare) ce definesc cum sunt afișate datele de ieșire în format HTML. Acestea conțin și căi prin care pot executa acțiuni asupra aplicației (butoane, formulare, linkuri, etc.). Lipsa view-urilor duce la imposibilitatea utilizatorului de a interacționa cu aplicația.

Rails oferă posiblitatea de a structura în diverse moduri template-urile. Putem separa conținutul HTML în fișiere separate în funcție de scop. De exemplu dacă dorim să ca același formular să apară în 2 locuri diferite, de preferat ar fi să nu scriem același lucru de 2 ori. Pentru a face acest lucru mutăm formularul într-un fișier separat și îl includem oriunde avem nevoie. Aceste fișiere se numesc parțiale (partials) și deobicei se scriu cu semnul underscore(_) în față.

Exemplu pentru includerea unui parțial numit _form.html.erb:

<%= render ”form” %>

2.2. 3. Controller

Controllerul este conceptualizat ca o clasă ce poate îndeplini mai multe funcții, numite acțiuni. Fiecare funcție primește un set de date de intrare, ce reprezintă parametri sau informații. Acesta trimite comenzi la model pentru a modifica informația, dar poate controla și un view pentru a altera modul cum informația este prezentată utilizatorului. El conține toată logica de execuție a aplicației. Reprezintă atât punctul de intrare în aplicație, cât și cel de ieșire și se folosește de celelalte componente (model și view) pentru a-și îndeplini sarcina dată. Controllerul acceptă date de intrare și în urma unor prelucrări făcute de acesta împreună cu ajutorul modelelor furnizează date de ieșire.

Schema conceptuală a arhitecturii MVC:

Se observă din schemă cum controllerul este cel care face legătura între model și view. Acesta manipulează și modifică modelul cu informații venite de la view, dar nu înainte de a fi verificate de el însuși.

Liniile punctate arată legături indirecte.

Într-o aplicație web, având ca structură de bază o arhitectură MVC, view-ul este de fapt codul HTML, CSS și Javascript generat de aplicație, iar controllerul este cel ce primește cererile HTTP de tip GET, POST, PUT sau DELETE. Controllerul este și cel care se asigură că formatul în care vine informația de la view este același cu cel pe care modelul îl agrează și invers. Diferența între formaturi se datorează conversiilor ce pot fi aplicate asupra datelor de către controller pentru a facilita traficul de informație între componente. De exemplu, informația interogată de către un model vine într-un format de tip obiect, însă utilizatorului nu îi putem afișa în acest mod, view-ul conține cod HTML, deci constrollerul trebuie să facă o conversie.

Schema de funcționare a unei aplicații modelate după arhitectura MVC:

Utilizatorul interacționează cu interfața, apasând un buton, completând un formular, atașând o imagine și prin multe alte moduri.

Controllerul primește acțiunea realizată de utilizator și face conversia ei la un format pe care modelul îl înțelege.

Modelul își modifică starea la o alta care conține noua informație.

View-ul interoghează modelul (prin intermediul controllerului, nu direct) pentru a genera o interfață corespunzatoare noii stări a modelului.

2.3 Ruby on Rails

Ruby on Rails (sau doar Rails) este un framework web implementat în Ruby, cu scopul de a facilita construirea de aplicații web într-un mod accelerat cât și de a crește productivitatea. Rails folosește ca arhitectură modelul MVC (model-view-controller). El furnizează structuri predefinite pentru baza de date, încurajează folosirea formatelor standard ca JSON sau XML pentru transferul datelor și HTML, CSS, Javascript pentru afișarea interfețelor către utilizator.

Conține diferite unelte pentru a accelera dezvoltarea cum ar fi scaffoldingul care poate genera automat modelele și vizualizările necesare pentru a construi o pagină web simplă. O altă unealtă este WEBrick, un server web minimalist ce oferă funcționalitățile necesare pentru a rula orice aplicație Ruby on Rails, acesta este folosit în special în modul de dezvoltare sau testare.

Rake este un alt utilitar pe care Rails îl furnizează, acesta ajută la automatizarea anumitor task-uri necesare dezvoltării unei aplicații. El se ocupă de setarea, ștergerea și modificarea bazei de date, de compilarea anumitor fișiere, de urcarea aplicației pe un server de producție și multe altele.

Rails promovează două mari principii din programarea si anume Don’t Repeat Yourself (DRY) și Convention Over Configuration.

Principiul DRY de a „nu te repeta” se aplică de foarte mult timp, în diverse moduri, specifice fiecărui limbaj. La bază, principiul DRY propune ca orice blocuri comune, similare, repetitive, să fie reprezentate printr-o singură entitate, printr-un „model”. Orice modificare a „modelului” se va propaga automat tuturor blocurilor aferente. Prin folosirea corespunzătoare a principiului se elimină:

Codul duplicat;

Munca manuală și repetitivă la editare;

Metoda copy-paste pentru replicarea unor funcționalități;

Convention Over Configuration se referă la faptul că dezvoltatorul are la dispoziție un arsenal de opțiuni implicite, pe care le poate particulariza la nevoie, fără a fi nevoit să le definească în totalitate de la început. Scopul principiul este de a reduce numărul de decizii pe care programatorul trebuie să le ia de-a lungul dezvoltării unei aplicații și fără a pierde din flexibilitate. De exemplu, dacă există un model numit ,,User” tabelul corespunzător în baza de date este ,,users’’ iar controller-ul asociat modelului ,,User’’ este numit ,,UsersController’’ și fisierul în care se găsește este ,,user_controller.rb’’. Prin această convenție, dezvoltatorul nu trebuie să mai specifice asocierile dintre model, controller, tabelul din baza de date și view , ele fiind implicit definite.

2.3. 1. Structura unei aplicații Ruby on Rails

Structura arhitecturală a lui Rails este separată în mai multe pachete, anume ActiveRecord (un sistem de legare tip relație-obiect pentru accesul la baza de date), ActiveResource (facilitează servicii web), ActionPack, ActiveSupport și ActionMailer (se ocupă de conectarea la un server de mail și transmiterea de e-mail-uri).

Ca și majoritatea framework-urilor ce au la bază arhitectura MVC, Rails asociază un model cu o tabelă din baza de date și un fișier Ruby. Spre exemplu pentru un model numit Utilizator, se definește un fișier ,,utilizator.rb” și se asociază cu tabela ,,utilizatori” din baza de date.

Controllerul răspunde la cereri din exterior și determină ce fișiere de tip view să afișeze. Având la bază și arhitectura de tip REST, controllerul are predefinite acțiunile specifice lui REST, GET, POST, PUT, DELETE, însă se pot aduga multe altele. Pentru ca un controller să poată răspunde la anumite acțiuni pe care utlizatorul le cere, acele acțiuni trebuie să existe în fișierul de rute. Fișierul de rute controlează accesul la acțiunile ce sunt cerute aplicației. Acesta are predefinite rutele specifice lui REST.

Cea mai importantă parte a structurii de directoare a unei aplicații Rails arată așa:

/app, în aces director se găsește cea mai mare parte a codului specific aplicației, se găsesc fișiere pentru model, view, controller, mailer, css, javascript etc.;

/assets, conține fișierele statice, în special pentru partea de front end;

/controllers, toate controller-ele existente în aplicație;

/helpers, conține clase ajutatoare pentru model, view sau controller;

/mailers, conține clase specifice trimiterii de emailuri;

/models, conține clasa fiecărui model;

/views, cuprinde toate template-urile aplicației;

/config, aici sunt ținute toate fișierele de configurare pentru fiecare mediu de lucru, ce tip de bază de date se folosește, fișierul de rute, fișiere de inițializare, etc.;

/db, schema bazei de date (schema.rb), migrațiile (/migrate);

/log, conține fișiere de loguri;

/public, toate fișierele statice sau fișiere care nu au restricții de accesare;

Gemfile, fișierul ce conține toate pachetele necesare aplicației pentru a rula corect, pachetele se numesc ,,gem-uri’’;

2.3. 2. RubyGems

RubyGems este un manager de pachete pentru Ruby ce furnizează programe, biblioteci, module pentru Ruby. Acesta este indispensabil pentru dezvoltarea aplicațiilor în Rails.

Există o varietate foarte mare de pachete ce sunt puse la dispoziție prin RubyGems. Chiar și instalarea framework-ului Ruby on Rails depinde de acesta. Comanda pentru instalare este gem install rails. Cu RubyGems se pot instala biblioteci javascript, framework-uri CSS, module cu diverse utlități pentru Ruby on Rails, biblioteci ruby și multe altele, etc.

Câteva din cele mai utilizate gemuri sunt: devise (folosit pentru instalarea rapida a unui modul de autentificare), biblioteci precum jQuery, Boostrap, PostgreSQL (pg), figaro și multe altele.

2.3. 3. Unit testing și Test driven development

Testarea unitara sau unit testing este un proces de dezvoltare software în care cele mai mici părți dintr-o aplicație, numite și unități sau unit, sunt testate cu scopul de a verfica dacă sunt gata de a fi folosite. Noțiunea de unit ține să aibă înțelesuri în funcție de paradigma de programare, astfel în programarea procedurală un unit poate să fie un modul întreg sau chiar și funcții sau proceduri, în programarea orientată pe obiecte acesta reprezintă de obicei o clasă sau metode ale acelei clase.

Scopul testării este de a izola părți de cod, funcții, module și de a verifica dacă acestea își îndeplinesc corect sarcina, astfel sunt detectate încă de la început probleme ce pot apărea în viitor. Odata cu dezvoltarea aplicației la un nivel din ce în ce mai complex, căutarea și descoperirea erorilor devine mult mai complicată. Bineînțeles că testele nu pot acoperi în totalitatea erorile ce pot apărea pe parcurs, în special erorile ce țin de logică, însă ele minimalizează pe cât de mult posibil apariția lor, astfel ușurează și poate chiar accelerează modul de lucru.

Un alt beneficiu al scrierii testelor este faptul că dezvoltatorul poate revenii asupra unei funcționalități pentru a o îmbunătăți, a o actualiza sau pentru a o rescrie cu scopul de a opitmiza (refactor). După ce este executată una sau mai multe din operațiile de mai sus rezultatul final al unității trebuie să fie același, iar aici intervine testul ce verifică corectitudinea modificărilor.

Deoarece testele verifică ce face fiecare unit în parte și știu cum ar trebui să se comporte, ele furnizează într-o anumită măsura și un fel de documentație pentru aplicația respectivă. Dezvoltatorul poate să citească testele și astfel să își facă o idee despre ce funcționalități furnizează o aplicație.

O tehnică derivată din testarea unitară este test driven development.

Test driven development este o tehnică de dezvoltare software, având la bază testarea unitară, care promovează ideea de a scrie teste înainte de a crea funcționalitatea dorită. Prin test de fapt se descrie funcționalitatea unității respective. Inițial testul eșuează nefiind implementată unitatea. Pentru a putea scrie un test, dezvoltatorul trebuie să înțeleagă bine și clar scopul unității, specificațiile și necesitățile. Acesta ar fi primul pas al procesului.

Al doilea pas este executarea tuturor testelor pentru a verifica dacă nu cumva noul test este trecut cu succes.

Al treilea pas este implementarea funcționalității minime pentru a face testul să fie trecut cu succes. Codul scris nu trebuie să fie perfect, el va fi optimizat în urmatorii pași.

În al patrulea pas dezvoltatorul rulează toate testele pentru a verifica dacă cumva noul test nu degradează într-un fel restul funcționalităților.

Într-un ultim pas codul scris anterior pentru a face testul să treacă poate fi rescris, optimizat sau îmbunătățit cu noi funcționalități. De aici procesul se repetă pâna la finalizarea aplicației.

Pentru a scrie teste există diferite programe și utilități. Rails aduce odata cu instalarea posibilitatea de a crea și executa teste, fără nevoia instalării altor pachete.

3. STRUCTURA APLICAȚIEI

3.1 Modele și baza de date

Logica aplicației are la bază o mulțime de modele, fiecare având un tabel corespondent în baza de date. Structura bazei conține următoarele tabele: events, sessions, presentations, invitations, attendees, administrations, users, sponsors. Fiecare tabel în parte conține câmpurile de id, created_at, updated_at, sunt câmpurile pe care Rails le creează implicit pentru a exista un index unic, o dată la care o informație a fost adaugată și un câmp pentru a știi când s-a executat o modificare asupra ei.

Tabelul events reprezintă principala legătură cu restul tabelelor, prin el se fac cele mai multe conexiuni între diferite secțiuni ale aplicației. Conține câmpurile necesare pentru a descrie pe scurt un eveniment, conferință și mai exact un câmp title pentru a putea specifica un nume, două câmpuri pentru descriere, short_description, long_description, unde short_description ar trebui să prezinte activitatea de bază pe care evenimentul o susține, iar long_description o descriere mai în detaliu.

Alte câmpuri ar fi logo de tip text pentru a putea adăuga URI-ul unui document în format de tip imagine, start_date și end_date sunt de tip date, conțin datele calendaristice în care evenimentul are loc, location adresa din cadrul unui oraș, city de tip string și country de tip string.

Tabelul sessions reprezintă ideea de activitate din cadrul unui eveniment. Este compus din urmatoarele câmpuri:

name de tip string, numele activității;

description de tip text, descrierea activității;

date de tip date, data la care are loc;

start_time de tip datetime, ora la care începe;

end_time de tip datetime, ora la care se sfârșește;

location_id de tip integer, idul locației din cadrul complexului în care se ține evenimentul;

event_id de tip integer, câmpul care asociază o activitate cu un eveniment.

Tabelul attendees conține informațiile fiecărui participant sau invitat în parte. Are câmpurile specifice unui profil succint:

name de tip string, numele;

email de tip string, emailul;

phone de tip string, numărul de telefon;

company de tip string, compania de la care face parte;

job_title de tip string, postul acestuia în companie;

picture de tip text, URI cu poză;

bio de tip text, scurtă biografie;

website de tip string, website personal;

facebook de tip string, profil Facebook;

linkedin de tip string, profil LinkedIn;

twitter de tip string, profil Twitter.

Tabelul presentations stabilește legătura many-to-many între tabelele sessions și attendees. Tipul acesta de legătură apare deoarece profilele participanților și a invitaților speciali sunt ținute în același loc, singura diferență între ei este rolul lor la acel eveniment. Astfel un participant poate participa la mai multe activități ce sunt susținute de invitați speciali. Desigur, pentru a face distincție între rolurile celor două categorii, tabelul presentations conține pe langă câmpurile generale unui astfel de tip de asociere și un câmp special:

attendee_id de tip integer, idul unui profil de participant;

session_id de tip integer, idul unei activități;

role de tip integer, rolul persoanei în cadrul acelei activități, cu valorile 1 – participant, 2 – susținător.

Multe astfel de relații de tip many-to-many mai apar în cadrul aplicației și o alta ar fi cea ce formează tabelul invitation.

Tabelul invitation stabilește legătura dintre un eveniment și participanți. De asemenea conține și el un câmp specific, mai exact codul de confirmare a invitației:

attendee_id de tip integer, id-ul unui profil de participant;

event_id de tip integer, id-ul unui eveniment;

confirmation_token de tip string, codul sau tokenul ce confirma participarea la eveniment;

confirmed_at de tip date, data la care a fost făcută confirmarea de către participant;

confirmation_sent_at de tip date, data la care a fost trimisă confirmarea.

Tabelul users este cel ce conține lista cu toți utilizatorii aplicației. Cei ce se găsesc în acest tabel au abilitatea de a crea și administra evenimente. Ei sunt de fapt organizatorii.

name de tip string, numele organizatorului;

email de tip string, emailul organizatorului;

encrypted_password de tip string, parola criptată;

confirmation_token de tip string, codul sau tokenul de confirmare primit la creara contului;

confirmed_at de tip date, data la care a fost făcută confirmarea de către participant;

confirmation_sent_at de tip date, data la care a fost trimisă confirmarea.

Aplicația permite unui organizator să construiască mai multe evenimente și să ofere permisiunile necesare altora pentru a putea modifica acel eveniment. Pentru a fi posibil acest lucru, fiind o relație many-to-many, este nevoie de un tabel de legătură.

Tabelul administrations, creează această legătura între events și users:

user_id de tip integer, id-ul organizatorului din tabelul users;

event_id de tip integer, id-ul unui eveniment din tabelul events.

Tabelul partners este alcătuit din informații legate de sponsori, parteneri ce au ajutat la organizarea evenimentului prin diferite căi. Acesta este foarte asemănător cu attendees, în el informațiile sunt tot specifice unui profil, doar că profilul nu este al unei persoane, ci al unei companii, iar legătura dintre cele două tabele nu este de tip many-to-many, ci de tip one-to-many:

name de tip string, numele companiei;

about de tip text, date despre companie, o scurtă descriere;

logo_url de tip text, un URI către fișiere de tip imagine;

level de tip integer, nivelul de implicare în organizarea evenimentului;

location_id de tip integer, în caz că există un loc unde partenerul își prezintă anumite produse;

phone de tip string, număr de telefon a unei persoane de contact;

email de tip string, email de contact;

website de tip string, websitul companiei;

event_id de tip integer, câmpul ce face legătura cu un eveniment, o intrare în tabelul events.

Motivul pentru care nu am făcut legătura many-to-many, ci one-to-many este de a simplifica puțin procesul, fiind complicat de a găsi un identificator unic specific fiecărei companii. Numele companiei, emailul sau alte câmpuri pe care tabelul le conține nu garantează siguranța că nu mai există o companie cu același date.

Cum mentionam și în capitolul 2, în aplicațiile dezvoltate pe o arhitectura MVC fiecare tabel din baza de date are un model corespondent. În cazul lui Ruby on Rails acel corespondent este o clasă și conform principiului pe care îl promovează, Convention Over Configuration, există o clasă ce are ca denumire, numele tabelului la singural, adica tabelul events este corespondentul clasei Event ce se află localizată în fisierul ,,event.rb’’ din directorul ,,models’’ al aplicației.

Clasa Event are scopul de a crea obiecte ce înglobează toate caracteristicile unui eveniment. Tot în interiorul ei sunt făcute și legăturile cu celelalte clase: Attendee, Invitation, User, Administration, Session, Presentation, Partner.

class Event < ActiveRecord::Base

has_many :invitations

has_many :attendees, through: :invitations

has_many :administrations

has_many :users, through: :administrations

accepts_nested_attributes_for :attendees, reject_if: proc { |attributes| attributes[:email].blank? }, allow_destroy: true

accepts_nested_attributes_for :invitations, reject_if: proc { |attributes| attributes[:event_id].blank? || attributes[:attendee_id].blank? }, allow_destroy: true

has_many :sessions

has_many :presentations, through: :sessions

has_many :speakers, through: :presentations, source: :attendee

accepts_nested_attributes_for :sessions, allow_destroy: true

has_many :partners

end

Funcția has_many creează asociere între modele, acceptă ca parametru numele clasei cu care se dorește asocierea, însă acesta trebuie sa fie la plural cu litere mici ca și numele tabelului

(has_many :invitations). Aceste legături sunt benefice în cazul validatoarelor, în construirea de instrucțiuni SQL complexe și cresc productivitatea dezvoltatorului. Un exempu concret ar fi nevoia de a afla toate activitățile din cadrul unui eveniment cu scopul de a le afișa sub forma de listă participanților. În cadrul unei aplicații simple, ce nu folosește un framework, programatorul trebuie să scrie instrucțiunea SQL:

SELECT * FROM sessions LEFT JOIN events ON sessions.event_id = events.id WHERE events.id = 5;

În Rails acest lucru se poate face mult mai simplu, prin funcția has_many:

Event.find_by_id(5).sessions

Aceste legături pe care le construim ne scapă de instrucțiunile simple SQL și de faptul că de multe ori trebuie să le scriem, aproape în totalitate, la fel.

Un al doilea parametru al funcției has_many apare când se dorește crearea unei relații de tip many-to-many, atunci intervine opțiunea through ce ia valoarea tabelului de legătură.

(has_many :attendees, through: :invitations).

Se observă cum se construiește relația many-to-many între Event și Attendee:

has_many :invitations

has_many :attendees, through: :invitations

Mai întâi se face asocierea cu tabelul de legătură, invitations, apoi se face asocierea cu tabelul attendees prin tabelul invitations, utilizând through.

Funcția accepts_nested_attributes_for spune clasei că odată cu crearea unui obiect din clasa Event putem accepta și câmpuri pentru o tabelă cu care există o asociere. În cazul de mai sus, când dorim crearea unui nou eveniment, dorim să putem adăuga și o listă de invitați.

accepts_nested_attributes_for :attendees

O opțiune foarte folositoare a aceste funcții este de a putea aplica filtre pe care aplicația să le verifice înainte de a salva datele în baza de date. Parametrul reject_if acceptă o funcție care trece prin toate informațiile și le filtreaza după un anumit criteriu. De exemplu, clasa Event se asigură că înainte de introducerea unui eveniment în baza de date ce este însoțit de o listă cu invitați, să nu existe elemente ce au câmpul de email gol.

accepts_nested_attributes_for :attendees, reject_if: proc { |attributes| attributes[:email].blank? }

Parametrul allow_destroy permite eliminarea unor intrări la executarea unei acțiuni de tip update.

Pentru ca legătura să lucreze în ambele sensuri și să fie corectă trebuie adăugată și în cealaltă clasă specificată de funcția has_many. Pentru exemplul de mai sus acestea ar fi Invitation și Attendee.

class Attendee < ActiveRecord::Base

has_many :invitations

has_many :events, through: :invitations

end

class Invitation < ActiveRecord::Base

belongs_to :attendee

belongs_to :event

end

Invitation, fiind clasa de legătura dintre cele două tabele, ea aparține ambelor părți, între Invitation și Event sau Invitation și Attendee este o relație one-to-many. De fapt o relație many-to-many se sparge în doua relații one-to-many. Ne folosim de metoda belongs_to pentru a defini această relație de aparținere.

Rails oferă posibilitatea de a face legături și între trei sau mai multe tabele. Un exemplu concret se află chiar în aplicație.

has_many :sessions

has_many :presentations, through: :sessions

has_many :speakers, through: :presentations, source: :attendee

Aici se face legătura clasei Event cu Attendee, dar prin clasele Session și Presentation. Deoarece mai există o legătura cu Attendee nu mai putem folosi aceeași valoare pentru primul parametru încă o dată și înlocuim has_many :attendees cu has_many :speakers, source: :attendee, creând de fapt un alias pentru attendees numit speakers. Prin această legătură putem afla toți participanții unui event care și-au adăugat în agenda proprie din cadrul aplicației una sau mai multe activități.

Clasa Presentation reprezintă legătura dintre o activitate (Session) și un participant (Attendee). Reamintesc că ea face distincția dintre un participant și un susținător al acelei activități prin câmpul type_of. Conține validatorul ce asigură unicitatea și anunță utilizatorul că nu poate insera aceeași informație de mai multe ori. Unicitatea fiecărui obiect este formată din mai multe câmpuri: attendee_id, session_id și type_of (cu valorile 1 sau 2). Dacă type_of are valoarea 1 atunci este vorba de un susținător al acelei activități, iar dacă are valoarea 2 atunci este vorba de un participant ce și-a adăugat în agendă.

class Presentation < ActiveRecord::Base

belongs_to :session

belongs_to :attendee

validates_uniqueness_of :attendee_id, :scope => [:session_id, :type_of]

end

Clasa Invitation reprezintă legătura dintre un eveniment (Event) și un participant (Attendee). Un eveniment poate avea mai mulți participanți, iar fiecare participant poate merge la mai multe evenimenet, astfel relația dintre cele două entități este una de tip many-to-many. Am construit cele doua relații de tip one-to-many folosindu-mă de metoda belongs_to.

belongs_to :attendee

belongs_to :event

La fel ca în cazul clasei Presentation fiecare obiect trebuie să fie unic și am adăugat un validator de unicitate pe coloanele event_id și attendee_id.

validates_uniqueness_of :event_id, :scope => :attendee_id

Participarea la un eveniment se face pe bază de invitație, astfel în cadru unui obiect trebuie să existe și un cod unic, alfanumeric ce reprezintă invitația. Codul trebuie să se genereze automat înainte de a salva obiectul în baza de date. Pentru a face acest lucru ne folosim de before_save ce primește ca parametru o altă metodă, metoda care se executa imediat, înainte de a se face inserarea. În cazul aplicatiei am construit o metodă ce generează un cod unic pentru fiecare obiect în parte. Metoda se folosește de clasa predefinită SecureRandom din Rails pentru a genera un cod unic și sigur.

class Invitation < ActiveRecord::Base

before_save :generate_confirmation_token

after_create :send_invite_confirmation

private

def generate_confirmation_token

self.confirmation_token = SecureRandom.urlsafe_base64()

end

def send_invite_confirmation

@attendee = Attendee.find_by_id self.attendee_id

ApplicationMailer.invite_confirmation(@attendee, self).deliver_now

self.update_column :confirmation_sent_at, Time.zone.now

end

end

Bineînțeles că trebuie să trimitem codul și invitaților (Attendee) pentru a putea confirma participarea lor. Pentru asta m-am folosit de metoda after_create ce îmi permite să execut o acțiune imediat după inserarea informației în baza de date. Am creat o funcție send_invite_confirmation pentru a trimite prin email invitația. În funcție mă folosesc de clasa ApplicationMailer unde am definit o metodă pentru acest tip de mail.

class ApplicationMailer < ActionMailer::Base

def invite_confirmation(attendee, invitation)

@attendee = attendee

@invitation = invitation

mail to: @attendee.email, subject: "This is your invitation to our event."

end

end

În cadrul clasei ApplicationMailer se definesc metode pentru fiecare tip de email pe care aplicația îl poate trimite. Fiecărei metode îi corespunde un șablon (template) aflat în folderul ,,app/views/application_mailer’’ cu denumirea ,,<nume metodă>.text.erb’’.

Exemplu: ,,invite_confirmation.text.erb”.

Metoda invite_confirmation primește ca parametrii obiectul specific invitatului (attendee) și invitația (invitation) ce conține codul de confirmare.

În emailul trimis se găsește de fapt un URI către pagina evenimentului, ce odată accesat confirmă participarea, modificând câmpul confirmed_at al invitației cu data curentă. Odată confirmată, URI devine invalid.

Clasa User este într-o relație many-to-many cu Event asociată prin modelul Administration. Aceasta conține elemente specifice modului de autentificare, modul este de fapt un gem foarte complex ce oferă toate utilitățile necesare pentru a construi un sistem de autentificare complet și sigur.

class User < ActiveRecord::Base

devise :database_authenticatable, :registerable, :recoverable,

:confirmable, :rememberable

has_many :administrations

has_many :events, through: :administrations

end

Pachetul ,,devise’’ cuprinde mai multe funcționalități necesare unui modul de autentificare complet. Acesta oferă posiblități de autentificare, înregistrare, recuperare parolă, confirmare email, blocare cont, reținere sesiune și altele.

În aplicație m-am folosit de autentificare, înregistrare, recuperare parolă, confirmare email și reținere sesiune.

Devise oferă posibilitatea de a adauga modulul de autentificare mai multor modele. În cadrul aplicației mele apare această necesitate, mai exact în interiorul clasei Attendee. Pentru a oferi unui participant posibilitatea de a-și forma un program personal și de a beneficia de anumite avantaje ale aplicației, precum comunicarea cu alți invitați printr-un sistem de mesagerie privat sau completarea datelor unui profil, am fost nevoit să adaug și aici anumite funcționalități pe care devise le oferă (autentificare și confirmare).

Clasa Conversation se află într-o relație many-to-one cu Attendee și într-o relație one-to-many cu Message. O conversație implică doi interlocutori, în cazul meu doi participanți.

Din acest motiv un obiect de tip Conversation conține două câmpuri, un câmp pentru emițător și unul pentru receptor. Ambele câmpuri fac trimitere la clasa Attendee, iar combinația emițător, receptor trebuie să fie unică.

class Conversation < ActiveRecord::Base

belongs_to :sender, :foreign_key => :sender_id, class_name: 'Attendee'

belongs_to :recipient, :foreign_key => :recipient_id, class_name: 'Attendee'

has_many :messages, dependent: :destroy

validates_uniqueness_of :sender_id, :scope => :recipient_id

end

De asemenea, o conversație implică mai multe mesaje, de unde și relația cu modelul Message.

Modelul Message reprezintă structura unui mesaj dintre doi interlocutori. Un mesaj conține: un text, o cheie prin care se face legătura cu o conversație și legătura cu utilizatorul care a trimis mesajul. O conversație este alcătuită din mai multe mesaje, iar fiecare mesaj în parte are un deținător. Această structură este în totalitate necesară pentru a avea un sistem de chat corect funcțional. Bineînțeles că pentru a îl îmbunătăți se pot adauga câmpuri precum ora și data la care a fost creat, însă de acest lucru se ocupă Rails implicit la crearea tabelelor pentru baza de date.

Deoarece cele trei componente sunt necesare în totalitate, trebuie să asigurăm existența lor într-un anume fel. Pentru acest lucru m-am folosit tot de o funcție pe care Rails o oferă și anume:

validates_presence_of care verifică ca nu cumva atributele unui obiect să fie goale.

class Message < ActiveRecord::Base

belongs_to :conversation

belongs_to :attendee

validates_presence_of :body, :conversation_id, :attendee_id

end

3.2 Controllere

Cum spuneam în primul capitol, controllerele sunt cele care conțin logica de execuție a aplicației. La ele ajung cererile făcute de către client.

Fiecărui model îi corespunde cel mult un controller. Prezența acestuia nu e întotdeauna necesară, deoarece e posibil să nu intervenim asupra acelui model direct sau dacă intervenim o putem face și din alt controller. Scopul ideii de corespondență dintre cele două componente este mai multe estetic și pentru a avea o aplicație cât mai bine structurată. Pot exista și controllere de sine stătătoare, fără nevoia unei comunicări cu un model și indirect cu o bază de date. Aceste tipuri de controllere sunt folosite în general pentru servirea paginilor web statice care includ acțiuni către alte controllere. Un astfel de exemplu se găsește implementat în aplicația mea.

Am fost nevoit să mă folosesc de un astfel de controller pentru a crea pagini statice, precum

pagina de index (home) care nu face decât să afișeze diferite butoane ce conduc către alte pagini.

class StaticController < ApplicationController

def home

end

end

Metoda din controller asociată paginii de index (home) nu trebuie să conțină nimic. Simpla declarare și adăugare în fișierul cu rute a instrucțiunii necesare este de ajuns pentru a oferi funcționalitate.

La fel ca și in cazul modelelor, controllerele sunt clase ce conțin diverse metode, validatoare etc. Aici se găsesc metodele specifice acțiunilor de bază ale arhitecturii REST.

Cel mai complex controller din cadrul aplicației este EventsController, prin acesta se adaugă, se modifică sau se șterg evenimente și toate legăturile cu restul modelelor.

Metodele de bază sunt:

index, funcționalitatea de bază este de a reda o listă cu obiecte, răspunde la o cerere de tip GET;

show, primește ca parametru idul unui obiect și afișează informațiile pe care acesta le conține, răspunde la o cerere de tip GET;

new, creează un obiect gol, răspunde la o cerere de tip GET;

create, inserează conținutul obiectului în baza de date, răspunde la o cerere de tip POST;

edit, interoghează baza de date și returnează un formular pentru editarea unui obiect, răspunde la o cerere de tip GET;

update, modifică conținutul unui obiect, răspunde la o cerere de tip PUT;

destroy, primește ca parametru idul unui obiect și îl elimina din baza de date, răspunde la o cerere de tip DELETE.

Accesul la aceste metode nu trebuie să fie întotdeauna permis oricui. Rails pune la dispozție funcții ce se execută înaintea oricărei acțiuni din cadrul unui controller. De exemplu, doresc ca adăugarea unui eveniment nou să fie posibilă doar dacă utilizatorul este autentificat.

Funcția care ne permite acest lucru se numește before_action. Aceasta poate să limiteze accesul la fiecare metodă în parte, specificând în parametrul only o listă cu metode.

before_action :check_user_permissions, if: :user_signed_in?, only: [:show, :edit, :update, :new, :create, :destroy]

În exemplul de mai sus, înainte de executarea oricarei dintre metodele show, edit, update, new, destroy sau create, se execută funcția check_user_permissions, însă doar dacă utilizatorul autentificat are drepturi de administrator. Metoda user_signed_in? verifică dacă este autentificat un administrator.

Metoda create din interiorul lui EventsController are rolul de a verifica și a insera noile informații furnizate de utilizator în cadrul unui eveniment. Deoarece un eveniment acceptă atribute și pentru celelalte clase cu care este asociat, în metoda create se fac și verificările specifice acelor atribute. Aceasta se ocupă de eliminarea câmpurilor goale, a dublurilor sau dacă acele informatii exista deja.

Pentru a crea o funcționalitate nouă a trebuit să adaug metoda speakers.

def speakers

@speakers = @event.speakers.uniq

End

Aceasta returnează lista de invitați speciali ce susțin diferite activitați în cadrul unui eveniment dat. Funcția uniq elimină dublurile, în caz că sunt găsite.

În InvitationsController se găsesc metodele necesare pentru adaugarea, ștergerea, listarea de invitații în cadrul unui eveniment. O metodă specifică este cea de confirm prin care împreună cu codul invitației primit prin email se face confirmarea participării. confirm primește ca parametru codul unic, apoi îl caută în baza de date și dacă este găsit trece statusul invitației ca și confirmat. Modificarea statusului se face prin adăugarea în câmpul confirmed_at a datei curente. În caz că nu se găsește nicio intrare în baza de date se returnează un mesaj de eroare. O dublă confirmare nu este posibilă deoarece în condițiile de căutare, pe lânga codul unic se află și clauza ca valoarea câmpului confirmed_at să fie nulă.

Attendees_controller are rolul principal de a oferi posbilitatea fiecărui utilizator (participant) să-și poată actualiza profilul. Acesta oferă și modalitatea de a accesa agenda sau programul personal.

Pentru a restricționa accesul și posibilitatea de editare a unui profil ce nu aparține unui utilizator, am construit metoda is_owner care împreună cu funcția specifică gem-ului devise verifică ca id-ul profilului să fie același cu cel al utilizatorului autentificat. Apelarea lui is_owner se face la fiecare accesare a paginilor legate de acțiunile edit, update sau destroy. Acțiunile new și create sunt restricționate de existența unui administrator autentificat, iar acțiunea show este restricționată de existenta unui utilizator autentificat, fie administrator sau participant prin metoda someone_signed_in.

Pentru vizualizarea profilului și a agendei personale am construit metodele profile, respectiv agenda. Acestea sunt accesibile doar după autentificarea participantului.

ConversationsController oferă cele două acțiuni de bază pentru funcționarea sistemului de chat și anume create, respectiv show. create se ocupă de crearea unei noi conversații între doi utilizatori dacă cumva nu există una. În caz că există o conversație între cei doi, metoda returnează id-ul aceleia. Pentru a verfica prezența unei conversații, metoda create acceptă ca parametrii id-urile a doi utilizatori.

După ce se poate identifica conversația mă folosesc de metoda show pentru a recupera toate mesajele asociate ei. Acest lucru e util pentru a afișa utilizatorului un istoric cu mesajele trimise din cadrul conversației.

MessagesController are rolul doar de a crea mesaje. Metoda create primește ca parametru id-ul unei conversații, crează un obiect de tip Message pe care îl asociază conversației și utilizatorului curent autentificat.

Înainte de orice acțiune din cadrul controllerelor Conversation și Messages se aplică filtrul authenticate_attendee! ce verifică dacă utilizatorul este autentificat înainte de a folosi sistemul de chat.

3.3 View-uri

Sunt responsabile de interfața vizuală pe care utilizatorul o vede. Fiecare acțiune din cadrul unui controller poate avea un view. Spun că poate avea, deoarece nu este obligatoriu, uneori răspunsul dat de un controller este într-un format JSON sau XML.

În structura unui view se pot insera instrucțiuni în cod Ruby de toate tipurile, plecând de la variabile până la instrucțiune de decizie, repetitive etc. Pentru a putea folosi instrucțiuni de tip Ruby sau Rails, codul trebuie înfășurat între două elemente. La început se va pune <%, iar la sfârșit %>.

Pentru afișarea unor variabile sau a altor elemente tag-ul de început trebuie ușor modificat <%=.

Rails oferă funcții ce returnează bucăți întregi de cod HTML, precum formulare sau butoane.

De exemplu, în view-ul pentru editarea (edit.html.erb) sau adaugarea (new.html.erb) unui nou eveniment există funcția form_for care returnează un formular cu atributele precompletate în funcție de parametri.

Pentru crearea un formular ce trimite datele la acțiunea create a unui controller putem face asa:

<%= form_for(@event) do |f| %>

<%= f.label :title %>

<%= f.text_field :title %>

<%= f.label :short_description %>

<%= f.text_field :short_description %>

<%= f.submit %>

<% end %>

În exemplul de mai sus este reprezentat parțial un formular pentru crearea unui eveniment. Primul parametru al funcției form_for este un obiect gol de tipul clasei Event construit de acțiunea new din cadrul controllerului EventsController.

Pentru a afișa câmpurile necesare în format HTML am folosit funcțiile label, text_field, text_area și submit.

label afișează o etichetă (<label></label>);

text_field afișează un câmp de intrare (<input name=“email”>);

text_area afișează un câmp de text (<textarea></textarea>);

submit afișează butonul ce trimite formularul (<button type=“submit”></button> sau <input type=“submit”>).

Am spus mai înainte că la creare unui eveniment putem introduce și câmpuri ce aparțin altor clase asociate cu acesta. De exemplu, vrem să adăugăm și o listă cu invitați sau să construim activități odata cu crearea unui eveniment. Pentru a putea face asta trebuie să indroducem în formularul evenimentului câmpurile specifice fiecărei entități în parte. Acest lucru este posibil cu ajutorul funcției fields_for ce primește ca parametru numele entității.

<%= form_for(@event) do |f| %>

<%= f.label :title %>

<%= f.text_field :title %>

<%= f.fields_for :attendees do |a| %>

<%= a.label :email %>

<%= a.text_field :email %>

<% end %>

<%= f.submit %>

<% end %>

Codul de mai sus se transformă cod HTML:

<form action="/events" method="post">

<label for="event_title">Title</label>

<input type="text" name="event[title]">

<label for="event_attendees_attributes_0_email">Email</label>

<input type="text" name="event[attendees_attributes][0][email]">

<input type="submit" name="commit" value="Create Event">

</form>

Se observă că tipul cererii este POST, iar ruta la care este submis formularul este

/events. În funcție de tipul cererii se determină ce metodă din controller preia datele, în cazul de mai sus se dorește creare unui eveniment deci metoda este create.

Spuneam că în interiorul unui view putem adauga orice instrucțiune din Ruby atât timp cât se află între cele două elemente (<%, %>). De exemplu, pentru a afișa toate evenimentele pe care un utilizator le-a creat trebuie să parcurgem acea listă. Ne folosim de o structură repetitivă specifică lui Ruby și anume each.

<% @events.each do |event| %>

<%= event.title %>

<% end %>

Această instrucțiune ia fiecare element al listei în parte, creează variabila event și o asociază lui. Prin intermediul variabilei ne putem referi la fiecare atribut pe care un eveniment îl are (titlu, descriere, oraș, țară, etc.). Variabila se mai numeste și scope.

View-urile nu trebuie să fie neapărat în format HTML, ele sunt template-uri, pot fi și în JavaScript. În cazul sistemului de chat am fost nevoit să folosesc un astfel de view pentru a furniza o experiența cât mai plăcută și simplă. Trimiterea unui mesaj se face prin AJAX, astfel pagina nu trebuie reîncarcată de fiecare dată. La trimiterea unui mesaj se execută un apel AJAX către metoda create din MessagesController, aceasta creează mesajul și returnează tot prin AJAX codul JavaScript necesar pentru modificarea interfeței utilizatorului. Codul odata executat construiește instrucțiunile HTML folosindu-se de parțialul _message.html.erb, pentru a afișa mesajul. Parțialul _message.html.erb conține structura în cod HTML a unui mesaj. JavaScript are puterea de a modifica conținut în format HTML de aceea view-urile scrise în acest limbaj, în anumite cazuri, reprezintă un avantaj.

Pentru controller-ul ConversationsController singurul view este cel de afișare a unei conversații (show.html.erb). Acesta conține structura unei căsuțe de chat dintre doi interlocutori. Afișează numele persoanei cu care se face conversația, lista cu mesaje trimise și formularul pentru a trimite un nou mesaj. De asemenea există și butonul pentru a închide căsuța.

Lista cu mesaje este construită cu ajutorul parțialului _message.html.erb din directorul ce ține view-urile specifice unui mesaj, același parțial pe care view-ul create.js.erb îl folosește pentru a afișa dinamic un mesaj după trimiterea lui.

3.4 Teste

Ruby on Rails oferă nativ posibilitatea de a crea teste pentru fiecare componentă în parte. La generarea unui controller, model, mailer sau helper Rails crează automat fișierul de test pentru fiecare în parte. Fișierele se găsesc în directorul ,,tests” din directorul rădăcină al aplicației.

Ca majoritatea componentelor din Rails testele sunt definite tot prin clase precum sunt controllerele, modelele, etc.

Rails se folosește de pachetul ,,minitest” a executa diferite proceduri, tehnici de testare. Acesta oferă o suită completă de utilități pentru a crea, executa și automatiza testele.

Comanda de pentru executarea a tuturor testelor este: rake test

3.4. 1. Teste pentru componenta controller

Fiecare test din cadrul unui controller este asociat unei acțiuni și verifică dacă rezultatul s-a realizat cu succes. Se pot face verificări ce conținutul view-urilor, se testează dacă există anumite elemente HTML cum ar fi titlul, descrierea, meta taguri sau dacă acestea sunt valide. Se mai poate verifică daca anumite metode sunt definite în controller și daca acestea își execută corect sarcina, etc.

Exemplu de test ce verifică daca o metodă este definită:

setup do

@event = events(:one)

end

test ”should get index” do

get :index

assert_response :success

assert_not_nil assigns(:events)

end

Este asociată metode index testului prin comanda get :index, dacă asocierea se poate face prima, parte a testului este cu succes. A doua parte a testului verifică utilizând metoda

assert_not_nil dacă obiectul :events nu este null, deoarece metoda index returnează lista cu evenimentele. Lista nu poate să fie null, în cel mai rău caz poate să fie goală dacă nu există un eveniment.

Pentru verificarea unei metode adăugarea în baza de date testul crează un obiect și încearcă să îl trimită la acțiunea specifică. Acesta verifică tipul cererii (POST, GET, …), unde este redirecționat utilizatorul după submiterea formularului și multe altele.

test "should create event" do

assert_difference('Event.count') do

post :create, event: { city: @event.city, country: @event.country, end_date: @event.end_date, location: @event.location, logo: @event.logo, long_description: @event.long_description, short_description: @event.short_description, start_date: @event.start_date, title: @event.title }

end

assert_redirected_to event_path(assigns(:event))

end

Blocul assert_difference primește ca parametru o comandă ce este executată după rularea intrucțiunii din interior. În cazul de mai sus acesta verifică numărul de evenimente. Dacă intrucțiunea a fost cu succes atunci un eveniment a fost inserat în baza de date de test.

Funcția post trimite o cerere de tip POST acțiunii create cu parametrul event. Obiectul de tip Event conține toate câmpurile specifice unui eveniment.

La sfârșitul testului se verifică dacă pagina unde este redirecționat utilizatorul este cea corectă folosind comanda assert_redirect_to.

3.4. 2. Teste pentru componenta model

Testele specifice unui model verifică dacă inaintea inserării în baza de date a unui obiect acesta conține toate informațiile necesare și daca acestea sunt valide.

În cazul modelului User dorim ca adresa de email să fie în formatul specific. Se verifică prezența ei, numărul de caractere și formatul.

class User < ActiveRecord::Base

VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i

validates :email, presence: true, length: { maximum: 255 },

format: { with: VALID_EMAIL_REGEX }

end

test "email should be present" do

@user.email = ""

assert_not @user.valid?

end

În exemplul de mai sus se crează un obiect de tip User și i se asociază câmpului de email un text de lungime 0, invalid. Este verificată apoi validitatea obiectului, ce a fost definită în cadrul clasei User. Obiectul nu este valid dacă nu trece peste toate verificările cerute de clasa respectivă. În cazul de mai sus se verifică prezența câmpului de email, lungimea și formatul acesteia (folosind o expresie regulată).

test "email should not be too long" do

@user.email = "e" * 244 + "@example.com"

assert_not @user.valid?

end

Testul de mai sus verifică lungimea adresei de email, astfel ca și în cazul explicat mai sus, se asociază câmpului de email un text de 256 de caractere. Dacă obiectul este valid atunci testul eșuează deoarece lungimea maximă este de 255 și nu ar trebui sa fie permisă.

Testul ce verifică formatul adresei de email presupune încercarea de validare a unui obiect cu adrese de email invalide. Programatorul crează o listă cu astfel de adrese și comandă testului să o parcurgă.

test "email validation should reject invalid addresses" do

invalid_addresses = %w[user@example,com user_at_foo.org user.name@example. foo@bar_baz.com foo@bar+baz.com]

invalid_addresses.each do |invalid_address|

@user.email = invalid_address

assert_not @user.valid?, "#{invalid_address.inspect} should be invalid"

end

end

4. GHID DE UTILIZARE AL APLICAȚIEI

La prima accesare utilizatorul este întâmpinat de pagina de index unde îi sunt afișate două butoane de autentifiare. Fiecare buton în parte duce la propriul formular de autentificare în functie de nevoia utilizatorului.

Aplicația implică două fluxuri (moduri) de utilizare în funcție de scop: fluxul unui administrator și fluxul unui participant.

4.1 Fluxul unui administrator

Fluxul unui administrator sau organizator prezintă aplicația din perspectiva persoanei ce creează, administrază un eveniment. Este întâmpinat inițial de formularul de autentificare specific.

Se introduc emailul și parola apoi se apasă butonul ,,LOGIN”. Dacă utilizatorul nu are cont, acesta poate accesa linkul ,,Sign Up’’ de sub butonul de autentificare pentru a fi redirecționat către pagina cu formularul de înregistrare.

În caz că intervine vreo eroare și nu se poate realiza cu succes autentificarea, utilizatorul primește mesaje cu eroarea/erorile respective. Erorile pot fi din diverse cauze cum ar fi: pierderea conexiunii la internet sau la rețeaua în care aplicația se află, introducerea datelor de cerute incorect, etc.

Odată autentificat utilizatorului îi este expusă pagina principală a panoul de administrare unde are acces la toate utilitățile aplicației.

Pe centru se află lista evenimentelor sub formă de tabel pe care administratorul le are în desfășurare. Fiecare linie a tabelului reprezintă un eveniment și are în partea din dreapta a acesteia butoanele pentru toate acțiunile ce îi pot fi aplicate.

Butonul ,,Sessions’’ afișează lista cu toate activitățile sau prezentările existente din cadrul evenimentului.

Fiecare element din lista cu artivități conține un sumar al acesteia, mai exact sunt afișate ora de început și sfârșit, numele și o scurtă descriere. Pentru a vedea informații mai detaliate, utilizatorul poate accesa pagina de prezentare a sesiunii prim simpla apăsare a unui click oriunde în suprafața acelui chenar.

În pagina de prezentare a unei sesiuni sunt afișate toate informațiile specifice ei. În partea de sus numele acesteia și a evenimentului cât și butonul pentru editare, iar după, data, intervalul orar, descrierea și lista de prezentatori. Fiecare element din lista cu prezenzatori este un buton către pagina de profil a fiecăruia.

Inițial sunt afișate câteva informații importante despre aceștia, cum ar fi: numele, compania și funcția ocupată în cadrul companiei.

Profilul unui participant conține în prima parte numele acestuia, compania, funcția din cadrul companiei.

În partea a doua este afișată o listă cu toate metodele de contact ale acestuia cum ar fi: rețele de socializare (Facebook, Twitter, LinkedIn), site-ul personal, emailul și telefonul,

De asemenea utilizatorul își poate face și o scurtă biografie. Această scurtă prezentare este utilă în cazul în care un participant dorește să știe mai multe informații despre acesta.

Butonul ,,Attendees’’ duce utilizatorul către pagina unde poate vedea lista cu invitați.

Fiecare element din listă este un buton ce duce către pagina de profil a acelui utilizator. La fel ca și în cazul sesiunilor, sunt afișate doat câteva informații despre acesta (numele, compania și funcția ocupată în cadrul companiei).

Sub fiecare element se găsește butonul de ,,Remove’’. Acesta anulează invitația trimisă și revocă accesul persoanei la acel eveniment.

Odata anulată invitația, pagina se reîncarcă și afișează lista actualizată.

Butonul ,,Back to event’’ redirecționează utilizatorul către pagina evenimentului unde apare butonul ,,New invitation’’ ce afișează formularul de adăugare a unei invitații.

În formular se găsește numele evenimentului, câmpul pentru numele invitatului, emailul acestuia și butonul de ,,SEND’’ ce trimite invitația prin email.

Butonul ,,Back’’ redirecționează utilizatorul la pagina anterioară.

Revenind la tabelul cu evenimente, un alt buton ar fi cel numit ,,Speakers’’. Acesta afișează pagina ce conține o lista a tuturor invitaților speciali ce țin, prezintă diverse activități. Lista este în același format ca a celei cu invitați doar că lipsesc butoanele ,,New invitation’’ și ,,Remove’’. Eliminarea unui invitat special, prezentator se face din secțiunea ,,Sessions’’.

Butonul de editare, ,,Edit” , trimite utilizatorul în pagina ce conține formularul pentru modificarea unui eveniment. Același formular este vizibil și la accesarea paginii pentru crearea unui eveniment nou.

În prima secțiune a formularului sunt afișate informațiile de bază precum (numele evenimentului, descrierea, logoul, data de început și data de sfârșit, locația, orașul și țara.

În a doua secțiune se afla lista cu invitații și în dreptul fiecarei invitații există butonul de ,,remove’’ pentru a o elimina.

De asemenea la sfârșitul secțiunii este butonul ,,New invitation’’ ce adaugă dinamic câmpurile necesare pentru crearea unei noi invitații.

A treia secțiune conține câmpurile necesare unei sesiuni (numele, data, ora de început, ora de sfârșit și descrierea).

O subsecțiune este lista cu prezentatori ce țin acea activitate. Ca și în cazul invitațiilor există un butonul ,,remove’’ și butonul de ,,Add speaker’’ ce inserează câmpurile necesare pentru a adauga un nou prezentator.

La sfârșitul secțiunii se găsește butonul ,,Add session’’ ce adaugă un nou se de câmpuri pentru o nouă sesiune.

La sfârșitul formularului se află butonul de ,,Update event’’ în caz că se editează un eveniment sau butonul ,,Create event’’ în caz că se crează unul nou.

Pentru vizualizarea unui eveniment se face click, în tabelul cu evenimente, pe numele acestuia ce redirecționează utilizatorul la pagina de prezentare.

Pagina de prezentare conține toate informațiile specifice evenimentului. Primul element este logul, urmat apoi de nume și butonul pentru editare. În continuare sunt afișate perioada în care se desfășoară, locația și descrierea.

Butonul ,,Info’’ oferă invitaților o listă cu informații utile de care aceștia pot avea nevoie, cum ar fi: cum să procedeze în cazul unui accident când o persoană este rănită, hoteluri în apropiere, numere de telefon pentru taxi, parola pentru WiFi, etc. În principiu orice fel de informații pe care organizatorul le dorește. Butonul ,,Edit’’ permite administratorului să modifice acel element și il redirecționează către formularul ce face acest lucru.

Butonul ,,Partners’’ afișează lista cu toate informațiile partenerilor, sponsorilor. Fiecarei entități în parte îi sunt afișate date precum numele, descriere, logo precum și informații de contact.

Pentru a adăuga informații despre un nou partener utilizatorul poate accesa formularul specific prin apasarea butonului ,,Add partner’’ ce se află în partea dreaptă de sus a ecranului. De asemenea orice informație adaugată poate fie modificată sau stearsă utilizând butoanele ,,Edit’’ sau ,,Delete’’ aflate în dreptul fiecărui element din listă.

Butonul pentru meniu din colț dreapta sus are scopul de a afișa meniul setări specifice utilizatorului. De acolo acesta se poate deautentifica, accesa pagina de profil și pagina de modificare a parolei sau a emailului.

Butonul ,,New Event’’ oferă acces la formularul de adăugare a unui eveniment.

4.2 Fluxul unui participant

Ca și în cazul unui administrator utilizatorul trebuie să se autentifice pentru avea acces la contul său.

Odată autentificat utilizatorul este redirecționat către pagina ce conține lista de evenimente la care a fost invitat. Aceasta este foarte asemănatoare cu cea a unui administrator. Apare în plus butonul ,,Chat’’ și dispar acțiunile ce permit modificarea diferitelor elemente precum butoanele: ,,New event’’, ,,Edit’’ și ,,Delete’’.

În pagina cu sesiunile (activitățile) unui eveniment utilizatorului îi apare butonul ,,Add to schedule’’ ce îi permite să o adauge în agenda proprie.

În dreptul fiecărui element din agenda personala există butonul ,,Remove from schedule’’ ce elimină elementul. După eliminare pagina este reîncarcată.

Butonul ,,Chat’’ afișează o lista cu toate conversațiile pe care utilizatorul le-a avut. În dreptul fiecarei conversații apare între paranteze numărul de mesaje pe care acesta nu le-a citit.

În pagina cu lista de invitați pe langă informațiile fiecărui invitat apare și butonul ,,Send Message’’ ce deschide o căsuță a sistemului de chat. Prin această căsuță utilizatorul poate transmite mesaje altui invitat.

În partea de sus apare numele persoanei cu care se comunică, apoi sunt afișate mesajele trimise și în partea de jos casuța în case se scriu noile mesaje.

Butonul din colț dreapta sus este în mare parte la fel ca și în cazul unui administrator. Singurul lucru în plus ce apare este ,,Agenda’’, butonul ce duce către agenda personala.

Butonul ,,Settings’’ duce la formularul ce permite unui utilizator să-și editeze profilul.

CONCLUZIE

Lucrarea prezintă o aplicație care vine în sprijinul atât al organizatorilor cât și al participanților la diverse evenimente simplificând organizarea și desfășurarea acestora.

Dezvoltarea aplicației s-a realizat în cadrul rețelei web folosind platforma Ruby on Rails. Aceasta beneficiază de toate avantajele pe care o aplicație web le oferă, fiind portabilă și rapidă. Portabilă este pentru că nu necesită instalarea de programe utilitare, nu are nevoie de adaptări la diverse sisteme de operare și pentru că poate fi accesată oriunde și oricând. Platforma Ruby on Rails îi conferă rapiditate, scalabilitate și securitate.

Fiind construită pe baza unei arhitecturi MVC, în cadrul aplicației se pot adăuga cu ușurință noi funcționalități. Structura bazei de date este simplă cu redundanță minimă și este prezentată într-o diagramă de tip entitate-relație.

Fluxul aplicației este intuitiv, elementele grafice sunt bine definite și explicite ceea ce oferă utilizatorului o experință simplă și placută.

La sfârșitul lucrării sunt parcurse două cazuri de utilizare din perspective diferite împreună cu diagrama UML a cazurilor.

BIBLIOGRAFIE

https://en.wikipedia.org/wiki/Model-view-controller

https://en.wikipedia.org/wiki/Representational_state_transfer

https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol

https://en.wikipedia.org/wiki/Ajax_(programming)

https://en.wikipedia.org/wiki/JavaScript

https://en.wikipedia.org/wiki/HTML

http://www.w3schools.com/

https://en.wikipedia.org/wiki/Client%E2%80%93server_model

https://en.wikipedia.org/wiki/Cascading_Style_Sheets

http://www.techotopia.com/

http://c2.com/cgi/wiki?ModelViewController

http://www.acunetix.com/websitesecurity/web-applications/

http://searchnetworking.techtarget.com/definition/client-server

RUBY ON RAILS TUTORIAL (3RD ED.) – Michael Hartl (https://www.railstutorial.org/book)

http://guides.rubyonrails.org/

http://josephndungu.com/tutorials/gmail-like-chat-application-in-ruby-on-rails

BIBLIOGRAFIE

https://en.wikipedia.org/wiki/Model-view-controller

https://en.wikipedia.org/wiki/Representational_state_transfer

https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol

https://en.wikipedia.org/wiki/Ajax_(programming)

https://en.wikipedia.org/wiki/JavaScript

https://en.wikipedia.org/wiki/HTML

http://www.w3schools.com/

https://en.wikipedia.org/wiki/Client%E2%80%93server_model

https://en.wikipedia.org/wiki/Cascading_Style_Sheets

http://www.techotopia.com/

http://c2.com/cgi/wiki?ModelViewController

http://www.acunetix.com/websitesecurity/web-applications/

http://searchnetworking.techtarget.com/definition/client-server

RUBY ON RAILS TUTORIAL (3RD ED.) – Michael Hartl (https://www.railstutorial.org/book)

http://guides.rubyonrails.org/

http://josephndungu.com/tutorials/gmail-like-chat-application-in-ruby-on-rails

Similar Posts