Încălcarea regulilor: Utilizarea SQLite pentru a demonstra aplicațiile web
Publicat: 2022-03-10Majoritatea utilizatorilor potențiali vor dori să încerce software-ul sau serviciul înainte de a dedica timp și bani. Unele produse funcționează excelent, oferind utilizatorilor doar o perioadă de încercare gratuită, în timp ce alte aplicații au cea mai bună experiență cu date eșantioane deja existente. Adesea, aici intră în joc vechiul cont demo.
Cu toate acestea, oricine a implementat vreodată un cont demo poate atesta problemele asociate. Știți cum merg lucrurile pe Internet: oricine poate introduce date (fie că are sens sau nu pentru produs) și există șanse mari ca conținutul adăugat de utilizatori anonimi sau de boți să poată fi ofensator pentru alții. Sigur, poți oricând să resetați baza de date, dar cât de des și când? Și în cele din urmă, asta chiar rezolvă problema? Soluția mea de a folosi SQLite .
De ce să nu folosiți SQLite pentru versiunea de producție?
Este cunoscut faptul că SQLite nu gestionează mai multe fire de execuție, deoarece întreaga bază de date este blocată în timpul unei comenzi de scriere, ceea ce este unul dintre motivele pentru care nu ar trebui să o utilizați într-un mediu de producție normal. Cu toate acestea, în soluția mea, un fișier SQLite separat este utilizat pentru fiecare utilizator care demonstrează software-ul. Aceasta înseamnă că limitarea de scriere este limitată doar la acel utilizator, dar mai mulți utilizatori simultan (fiecare cu propriul fișier de bază de date) nu vor experimenta această limitare. Acest lucru permite o experiență controlată pentru testul de utilizare a software-ului și le permite să vadă exact ceea ce doriți să vadă.
Acest tutorial se bazează pe o soluție reală pe care am rulat-o cu succes pentru o aplicație web demo SaaS din 2015. Tutorialul este scris pentru Ruby on Rails (cadru ales de mine) versiunea 3 și ulterioară, dar conceptele de bază ar trebui să fie capabil să fie adaptat la orice altă limbă sau cadru. De fapt, deoarece Ruby on Rails urmează paradigma software „convenție peste configurație”, poate fi chiar mai ușor de implementat în alte cadre, în special în limbaje simple (cum ar fi PHP simplu) sau cadre care nu fac mare lucru în ceea ce privește gestionarea conexiunilor la baze de date. .
Acestea fiind spuse, această tehnică este deosebit de potrivită pentru Ruby on Rails. De ce? Pentru că, în cea mai mare parte, este „agnostic al bazei de date”. Înseamnă că ar trebui să puteți scrie codul Ruby și să comutați între bazele de date fără probleme.
O mostră a unei versiuni finalizate a acestui proces poate fi descărcată de pe GitHub.
Primul pas: Mediul de implementare
Vom ajunge la implementare mai târziu, dar Ruby on Rails este împărțit implicit în medii de dezvoltare, testare și producție. Vom adăuga la această listă un nou mediu demonstrativ pentru aplicația noastră, care va fi aproape identic cu mediul de producție, dar ne va permite să folosim diferite setări ale bazei de date.
În Rails, creați un mediu nou duplicând config/environments/production.rb
și redenumiți-l demo.rb
. Deoarece mediul demo va fi folosit într-o setare asemănătoare producției, s-ar putea să nu fie nevoie să modificați multe opțiuni de configurare pentru acest nou mediu, deși aș sugera schimbarea config.assets.compile
de la false
la true
, ceea ce va facilita testarea locală fără trebuind să precompileze.
Dacă rulați Rails 4 sau o versiune superioară, va trebui, de asemenea, să actualizați config/secrets.yml
pentru a adăuga o secret_key_base
pentru mediul demo. Asigurați-vă că faceți această cheie secretă diferită de producție, pentru a vă asigura că sesiunile sunt unice între fiecare mediu, securizând și mai mult aplicația dvs.
Apoi, trebuie să definiți configurația bazei de date în config/database.yml
. În timp ce mediul demo va folosi în primul rând baza de date duplicată pe care o vom trata în secțiunea următoare, trebuie să definim fișierul implicit al bazei de date și setările care vor fi utilizate pentru demonstrația noastră. Adăugați următoarele la config/database.yml
:
demo: adapter: sqlite3 pool: 5 timeout: 5000 database: db/demo.sqlite3
În Rails, este posibil să doriți să vă verificați Gemfile
pentru a vă asigura că SQLite3 este disponibil în noul mediu demonstrativ. Puteți seta acest lucru în orice număr de moduri, dar poate arăta astfel:
group :development, :test, :demo do gem 'sqlite3' end
Odată ce baza de date este configurată, trebuie să rake db:migrate RAILS_ENV=demo
și apoi să introduceți datele în baza de date, după cum doriți (fie că este dintr-un fișier seed, introducerea manuală a datelor noi sau chiar duplicarea fișierului development.sqlite3
). În acest moment, ar trebui să verificați pentru a vă asigura că totul funcționează, rulând rails server -e demo
din linia de comandă. În timp ce rulați serverul în noul mediu demonstrativ, vă puteți asigura că datele de testare sunt așa cum doriți, dar puteți oricând să reveniți și să editați acel conținut mai târziu. Când adăugați conținut la baza de date demonstrativă, aș recomanda crearea unui set curat de date, astfel încât fișierul să fie cât mai mic posibil. Cu toate acestea, dacă trebuie să migrați datele dintr-o altă bază de date, vă recomand YamlDb, care creează un format independent de bază de date pentru descărcarea și restaurarea datelor.
Dacă aplicația dvs. Rails rulează conform așteptărilor, puteți trece la pasul următor.
Al doilea pas: Utilizarea bazei de date Demo
Partea esențială a acestui tutorial este posibilitatea de a permite fiecărei sesiuni să utilizeze un fișier de bază de date SQLite diferit. În mod normal, aplicația dvs. se va conecta la aceeași bază de date pentru fiecare utilizator, astfel încât va fi nevoie de cod suplimentar pentru această sarcină.
Pentru a începe să permitem lui Ruby on Rails să schimbe bazele de date, mai întâi trebuie să adăugăm următoarele patru metode private în application_controller.rb
. De asemenea, va trebui să definiți un filtru înainte pentru metoda set_demo_database
, astfel încât logica care face referire la baza de date demonstrativă corectă să fie apelată la fiecare încărcare a paginii.
# app/controllers/application_controller.rb # use `before_filter` for Rails 3 before_action :set_demo_database, if: -> { Rails.env == 'demo' } private # sets the database for the demo environment def set_demo_database if session[:demo_db] # Use database set by demos_controller db_name = session[:demo_db] else # Use default 'demo' database db_name = default_demo_database end ActiveRecord::Base.establish_connection(demo_connection(db_name)) end # Returns the current database configuration hash def default_connection_config @default_config ||= ActiveRecord::Base.connection.instance_variable_get("@config").dup end # Returns the connection hash but with database name changed # The argument should be a path def demo_connection(db_path) default_connection_config.dup.update(database: db_path) end # Returns the default demo database path defined in config/database.yml def default_demo_database return YAML.load_file("#{Rails.root.to_s}/config/database.yml")['demo']['database'] end
Deoarece fiecare sesiune de server va avea o bază de date diferită, veți stoca numele fișierului bazei de date într-o variabilă de sesiune. După cum puteți vedea, folosim session[:demo_db]
pentru a urmări baza de date specifică pentru utilizator. Metoda set_demo_database
controlează ce bază de date să fie utilizată prin stabilirea conexiunii la baza de date setată în variabila de sesiune. Metoda default_demo_database
încarcă pur și simplu calea bazei de date așa cum este definită în fișierul de configurare database.yml
.
Dacă utilizați un limbaj simplu, în acest moment puteți actualiza probabil scriptul de conectare la baza de date pentru a indica noua bază de date și apoi treceți la secțiunea următoare. În Rails, lucrurile necesită încă câțiva pași, deoarece urmează paradigma software „convenție peste configurare”.
Al treilea pas: Duplicarea fișierului SQLite
Acum că aplicația este configurată pentru a utiliza noua bază de date, avem nevoie de un declanșator pentru noua sesiune demo. De dragul simplității, începeți prin a utiliza doar butonul de bază „Start Demo”. Puteți, de asemenea, să creați un formular în care să colectați un nume și o adresă de e-mail (pentru o urmărire din partea echipei de vânzări etc.) sau orice număr de lucruri.

Respectând convențiile Rails, creați un nou controler „Demo”:
rails generate controller demos new
În continuare, ar trebui să actualizați rutele pentru a indica noile acțiuni ale controlerului, împachetându-le într-un condițional pentru a preveni apelarea acestuia în mediul de producție. Puteți denumi rutele așa cum doriți sau le puteți numi folosind convențiile standard pentru șine:
if Rails.env == 'demo' get 'demos/new', as: 'new_demo' post 'demos' => 'demos#create', as: 'demos' end
În continuare, să adăugăm un formular de bază la views/demos/new.html.erb
. Poate doriți să adăugați câmpuri de formular suplimentare pentru a captura:
<h1>Start a Demo</h1> <%= form_tag demos_path, method: :post do %> <%= submit_tag 'Start Demo' %> <% end %>
Magia se întâmplă în acțiunea de a create
. Când utilizatorul se trimite la această rută, acțiunea va copia fișierul demo.sqlite3
cu un nou nume de fișier unic, va seta variabile de sesiune, va conecta utilizatorul (dacă este cazul) și apoi va redirecționa utilizatorul către pagina corespunzătoare (vom numi aceasta 'bord').
class DemosController < ApplicationController def new # Optional: setting session[:demo_db] to nil will reset the demo session[:demo_db] = nil end def create # make db/demos dir if doesn't exist unless File.directory?('db/demos/') FileUtils.mkdir('db/demos/') end # copy master 'demo' database master_db = default_demo_database demo_db = "db/demos/demo-#{Time.now.to_i}.sqlite3" FileUtils::cp master_db, demo_db # set session for new db session[:demo_db] = demo_db # Optional: login code (if applicable) # add your own login code or method here login(User.first) # Redirect to wherever you want to send the user next redirect_to dashboard_path end end
Acum ar trebui să puteți încerca codul demo la nivel local lansând din nou serverul utilizând rularea rails server -e demo
.
Dacă ați avut serverul care rulează deja, va trebui să-l reporniți pentru orice modificări pe care le faceți, deoarece este configurat să memoreze în cache codul ca serverul de producție.
Odată ce tot codul funcționează conform așteptărilor, trimiteți modificările la controlul versiunii și asigurați-vă că comiteți fișierul demo.sqlite3
, dar nu și fișierele din directorul db/demos
. Dacă utilizați git, puteți pur și simplu să adăugați următoarele în fișierul dvs. .gitignore
:
Dacă doriți să colectați informații suplimentare de la utilizatorul demonstrativ (cum ar fi numele și/sau e-mailul), probabil că veți dori să trimiteți acele informații prin intermediul unui API fie către aplicația dvs. principală, fie către un alt canal de vânzări, deoarece baza de date demonstrativă nu va fi de încredere. (se resetează de fiecare dată când reinstalați).
!/db/demo.sqlite3 db/demos/*
Pasul final: implementarea serverului dvs. demo
Acum că aveți configurația demo care funcționează la nivel local, evident că veți dori să o implementați, astfel încât toată lumea să o poată folosi. Deși fiecare aplicație este diferită, aș recomanda ca aplicația demo să locuiască pe un server separat și, prin urmare, să aibă un domeniu ca aplicația dvs. de producție (cum ar fi demo.myapp.com). Acest lucru vă va asigura că păstrați cele două medii izolate. În plus, deoarece fișierul SQLite este stocat pe server, servicii precum Heroku nu vor funcționa, deoarece nu oferă acces la sistemul de fișiere. Cu toate acestea, puteți utiliza în continuare practic orice furnizor de VPS (cum ar fi AWS EC2, Microsoft Azure etc.). Dacă vă place confortul automatizat, există alte opțiuni Platforme as Service care vă permit să lucrați cu VPS.
Indiferent de procesul de implementare, poate fi necesar să verificați dacă aplicația are permisiunile de citire/scriere adecvate pentru directorul dvs. în care stocați fișierele demo SQLite. Acest lucru poate fi gestionat manual sau cu un cârlig de desfășurare.
SQLite nu va funcționa pentru mine. Dar alte sisteme de baze de date?
Nu sunt create două aplicații la fel și nici cerințele lor pentru bazele de date. Folosind SQLite, aveți avantajul de a putea duplica rapid baza de date, precum și de a putea stoca fișierul în controlul versiunilor. Deși cred că SQLite va funcționa în majoritatea situațiilor (în special cu Rails), există situații în care SQLite ar putea să nu fie potrivit pentru nevoile aplicației dvs. Din fericire, este încă posibil să folosiți aceleași concepte de mai sus cu alte sisteme de baze de date. Procesul de duplicare a unei baze de date va fi ușor diferit pentru fiecare sistem, dar voi schița o soluție pentru MySQL și un proces similar există cu PostgreSQL și altele.
Majoritatea metodelor descrise mai sus funcționează fără modificări suplimentare. Cu toate acestea, în loc să stocați un fișier SQLite în controlul versiunii, ar trebui să utilizați mysqldump
(sau pg_dump
pentru PostgreSQL) pentru a exporta un fișier SQL din baza de date care are conținutul pe care doriți să-l utilizați pentru experiența dvs. demo. Acest fișier ar trebui să fie stocat și în controlul versiunii.
Singurele modificări ale codului anterior vor fi găsite în acțiunea demos#create
. În loc să copieze fișierul SQLite3, acțiunea controlerului va crea o nouă bază de date, va încărca fișierul sql în acea bază de date și va acorda permisiuni pentru utilizatorul bazei de date, dacă este necesar. Al treilea pas de acordare a accesului este necesar numai dacă utilizatorul administrator al bazei de date este diferit de utilizatorul pe care aplicația îl folosește pentru a se conecta. Următorul cod folosește comenzile standard MySQL pentru a gestiona acești pași:
def create # database names template_demo_db = default_demo_database new_demo_db = "demo_database_#{Time.now.to_i}" # Create database using admin credentials # In this example the database is on the same server so passing a host argument is not require `mysqladmin -u#{ ENV['DB_ADMIN'] } -p#{ ENV['DB_ADMIN_PASSWORD'] } create #{new_demo_db}` # Load template sql into new database # Update the path if it differs from where you saved the demo_template.sql file `mysql -u#{ ENV['DB_ADMIN'] } -p#{ ENV['DB_ADMIN_PASSWORD'] } #{new_demo_db} < db/demo_template.sql` # Grant access to App user (if applicable) `mysql -u#{ ENV['DB_ADMIN'] } -p#{ ENV['DB_ADMIN_PASSWORD'] } -e "GRANT ALL on #{new_demo_db}.* TO '#{ ENV['DB_USERNAME'] }'@'%';"` # set session for new db session[:demo_db] = new_demo_db # Optional: login code (if applicable) # add your own login code or method here login(User.first) redirect_to dashboard_path end
Ruby, ca multe alte limbi, inclusiv PHP, vă permite să utilizați backtick-uri pentru a executa o comandă shell (adică, `ls -a`
) din codul dvs. Cu toate acestea, trebuie să utilizați acest lucru cu prudență și să vă asigurați că nu pot fi inserate parametri sau variabile pentru utilizator în comandă pentru a vă proteja serverul de codul injectat rău intenționat. În acest exemplu, interacționăm în mod explicit cu instrumentele din linia de comandă MySQL, care este singura modalitate de a crea o nouă bază de date. Acesta este același mod în care cadrul Ruby on Rails creează o nouă bază de date. Asigurați-vă că înlocuiți ENV['DB_ADMIN']
și ENV['DB_ADMIN_PASSWORD']
fie cu propria dumneavoastră variabilă de mediu, fie cu orice altă modalitate de a seta numele de utilizator al bazei de date. Va trebui să faceți același lucru pentru ENV['DB_USERNAME']
dacă utilizatorul dvs. administrator este diferit de utilizatorul aplicației dvs.
Atât este nevoie pentru a trece la MySQL! Cel mai evident avantaj al acestei soluții este că nu trebuie să vă faceți griji cu privire la problemele potențiale care ar putea apărea din sintaxa diferită dintre sistemele de baze de date.
În cele din urmă, o decizie finală este luată în funcție de calitatea și serviciul așteptat, mai degrabă decât de comoditate și viteză, și nu este neapărat influențată doar de punctul de preț.
Gânduri finale
Acesta este doar un punct de plecare pentru ceea ce puteți face cu noul dvs. server demo. De exemplu, site-ul dvs. de marketing ar putea avea un link către „Încercați funcția XYZ”. Dacă nu aveți nevoie de un nume sau de un e-mail, puteți conecta metoda demos#create
cu un link precum /demos/?feature=xyz
și acțiunea va redirecționa pur și simplu către caracteristica și/sau pagina dorită, mai degrabă decât către tabloul de bord din exemplul de mai sus.
De asemenea, dacă utilizați SQLite pentru mediile de dezvoltare și demo, având întotdeauna această bază de date exemplu în controlul versiunilor le-ar oferi tuturor dezvoltatorilor acces la o bază de date curată pentru utilizare în dezvoltarea locală, medii de testare sau testare de asigurare a calității. Posibilitățile sunt nesfârșite.
Puteți descărca o demonstrație completă de pe GitHub.