Anda di halaman 1dari 104

LearnRubyonRails

LearnWebDevelopmentWithRubyonRails

WhoamI?

IamHarryandjustlikeyouIhadneverdoneanycodingbefore.AcompletebeginnerIwanted
tolearnhowtocreatewebappssuchasapersonalblog,Signupforms,Authenticationapps
thatallowuserstologinandlogout.Iwantedtoknowhowtocodeusefulappsthatcouldbe
usedforpersonalwebsitesorevenabusinessstartup.SoIstartedlearninghtmlandcssand
rubyandeventuallyrubyonrails.AndnowIwanttosharewithyouwhatIlearned.Ihopeyou
learnsomethingfromthesetutorials.

Howtoworkthroughthisbook

IfyouarenewtocodingIrecommendyoureadthebookandtypeoutallthecodeshown.This
willtakelongerbutitwillstopyoufromglazingover.TrustmeIknow.Alsoifyoutypeoutthe
codeexamplesandfollowalongthenyouwilllearnandretaintheinformationfarbetter.

Ifyouhavecodedbeforethenfeelfreetojumptowhateveryoufindmostrelevant.

Settingupourworkingenvironment

TheworkingenvironmentIamgoingtorecommendisacloudbasedenvironment,butwhyyou
mightask?Whynotalocalenvironmentonyourowncomputer?Wellsimplyputeveryone's
computerwillvaryandsoacloudbasedenvironmentisaneasydefaultthatallcanuse.Ifyou
wanttosetupalocalenvironmentthenfeelfree,butthisisabookoncodetutorialsandsoI
wantyoutobecodingasquicklyaspossible.Alsocloud9providesafreeaswellaspaid
serviceandthefreeserviceisverygoodsoitiswhatwewillbeusing.

Goto
http://c9.io/
thewebsiteforcloud9whichisacloudbasedcodingenvironment.

Clickonthegettingstartedbuttonorsignupbutton.
Youwillseeasignupform,goaheadandsignup.

Afteryouhaveputinyourdetailsandverifiedyouremailyouwillseeascreenliketheone
below:
Thisscreenisyourhomescreenandholdsallofyourworkspaces.Workspacescanbethought
ofasprojectfolders.Youcancreatemanyrailsapplicationsinsidetheseworkspaces,sodont
thinkyouhavetocreateanewworkspaceforeveryrailsapplication.

ClicktheCreateanewworkspacebutton
Thiswillleadyoutoascreenthatlookslikethis:
Itprovidesyouwithvariousdefaultstohelpsetupyourworkspacehoweverwewillgoforthe
customtemplateoption.

Fillintheworkspacenameatthetop,callitwhateveryoulikeandaddadescription.Icalledmy
workspacerailstutorials.Leavethehostedworkspaceoptionaspublic.Againmakesureyou
haveselectedthecustomtemplateoption.Itisthedefaultoptionanyway.Finallyclickthe
createworkspacebutton.

Itmaytake30secondsbutdontworryallisgood...

OkayoncetheworkspaceiscreatedyouwillbegreetedwithyourenvironmentorIDE
integrateddevelopmentenvironment.Basicallyitisyourowncomputerinthecloudandhas
everythingpreinstalledthatweneedtogetstarted.

Youwillseeatoolbaratthetop,fileeditfindetc.Onthelefthandsideisasidebarofyour
projectfolders.SinceInamedmyworkspacerailstutorialsIaminthatworkspace.Thesidebar
showsallthefilesandfoldersinthatworkspace.Theonlyfileinthereatthemomentwillbea
README.mdfile.Asyoucanseeitisalsobeingdisplayedinthecenterofthepage.Inthe
centerofthepagenearthetoparesometabs.ClosetheREADMEfilebyclickingthelittlexon
thetab.

Youwillseethewelcometabisalsoopen.Youcanadjustthesettingsasyouwish,I
recommendkeepingitthesame.Theonlychangeneedediswhereitsayssofttabs4,
Change
thesofttabsto2.
Thatishowfaryourcodeisindentedwhenpressingthetabkeyonyour
computer.Nowclickcloseonthewelcometab.

Atthebottomofyourscreenyouwillseeyourconsole,itwilldisplayyourusernamefollowedby
thefolder/directoryyouarein,inthiscasetheworkspacedirectory.

Coolourdevelopmentenvironmentisnowsetup.
LetscheckthattheprogramminglanguagerubyisinstalledandtheRailsframeworkisalso
installed.

Atthebottominyourconsoletypethecommand:

ruby

Hereismyoutput.Noticethatthedollarsignistheprompt.Youdonttypeit,itshowstheendof
yourpromptorthebeginningofwhereyoutypeyourcommands.SeehowitshowsIaminthe
workspacedirectory.

harryoliver
:~/
workspace$ruby
v
ruby
2.3
.
0p0

(
2015

12

25
revision
53290
)

[
x86_64

linux]

Asyoucanseetheoutputsaysruby2.3.0whichisfine.Ifyouhaveaversionthatisnewerthen
thatwillalsobefine.

Nextintheconsoletypethecommand:

rails

YoucanseetheoutputisRails4.2.5againifyourversionislaterthanthisversionthenitshould
befine.

harryoliver
:~/
workspace$rails
v
Rails

4.2
.5

Excellentthetherubyprogramminglanguagewerequireisinstalledandsoistherails
framework.

Thecommandline

Ifyouhaveexperiencewiththecommandlinealreadythenfeelfreetoskipthischapter.Itisfor
thepeoplewhohaverarelyusedorneverusedthecommandlineatall.Iwillcoversomebasic
commandsandwhattheydo,thesecommandswillcropupthroughoutthetutorialssodont
worryaboutmemorizingthemasyouwillseethemenoughthroughoutthisbook.

TheTouchCommand

Atthebottomofyourscreeninthecommandline/console(Iwillusethenames
interchangeably)type:

$touchhello.txt

Rememberyoudonttypethedollarsignasthatistheprompt.

Ifyoulooktotheleftofyourscreenwhereallyourfilesandfoldersareyoushouldseeafile
calledhello.txt.Ifyoudontthenlookforasmallgeariconnearthetopofthefilesandfolders
section.Clickitandyouwillseeadropdownmenuwithanoptionto
refreshthefiletree
which
willshowanynewfilesorfoldersthathavebeencreated.

Howdoesthetouchcommandwork?

Thetouchcommandcreatesanewemptyfile.Itworksbytypingthecommandnamewhichis
touchfollowedbyanyoptionsandthenthefilename.

touch
[
option
]
file_name

Dontworrythisactuallymakesthecommandlookmoreconfusing.Wewontbeusingany
optionswiththetouchcommandandsowecanjusttypetouchfollowedbythefilename.

Typethistouchcommandintotheconsole:

$touchfile1file2file3

Nowlookatyourfilestotheleft,inonecommandyouhavetouched3filesintoexistence,pretty
coolright?

TheLSCommand

Nowtypethiscommandintoyourconsole:

$ls
README.mdfile1file2file3hello.txt

YoushouldgetalistofallthefilesyouhavecreatedincludingtheREADMEfile.Thels
commandisshortforlistandliststhefilesinthecurrentdirectory.Prettycool,wecanalsopass
optionsorargumentstothelscommandaswell.Wecouldpassthelscommandthealikethis:

$lsa
./../.c9/README.mdfile1file2file3hello.txt

Whenyouaddanoptionsuchastheawhichstandsforall,youaresayinglistmethefilesbutI
wantallofthem.Eventhehiddenfiles.Hiddenfileshaveasingledotinfrontofthem..c9/isa
hiddendirectory,Iknowitisadirectory/folderandnotafilebecauseoftheforwardslashatthe
end.Thataoptionthatyouusedisknownasaflag,thatisthecorrectterminologyforthe
optionsyoupasstothecommands.So
ls
isthecommandandtheflagis
a
,itisanoptionyou
passtothelscommand.

ThePWDCommand

Thiscommandprintsyourcurrentlocationtothescreen.Youareintheworkspace
directory/foldersothatiswhatwillbeprintedtothescreen,trythis:

$pwd
/home/ubuntu/workspace

Thecommandstandsfor
PrintWorkingDirectory
andasyoucanseeyourcurrentdirectoryis
theworkspacedirectorythatcloud9hasgivenyou.Youcanalsoseethattheworkspace
directoryisinadirectorycalledubuntuwhichisinanotherdirectorycalledhome.Bydefault
cloud9actuallyshowwhatdirectoryyouarein,youcanseethisbylookingatyourprompt.

~/workspace$

Thepromptshowstheworkspacedirectory.


TheMkdirCommand

Thiscommandcreatesanewdirectoryorfolder.Rememberhowyouusedthetouchcommand
tocreateanewfile?Thiscommandisusedtocreateanewfolder.
Trytypingthisintoyourconsole:

$mkdirmyfolder

Themkdircommandisshortfor
makedirectory
andisquiteselfexplanatory.Ifyoulooktothe
leftatyourfilesandfoldersyouwillseeanewfoldercalledmyfolder.Itisemptyatthemoment
sowewilladdsomefilestoit.Wealreadyknowhowtocreateanewfilewiththe
touch
commandbuthowdowegetinsidethatnewfolderwejustcreated?

TheCDcommand

Thecdcommandisusedtochangethedirectoryyouarein.Itstandsfor
changedirectory
.If
youlookatyourpromptyouwillseeyouareintheworkspacedirectory.Trytypingthisto
changetothemyfolderdirectory.

$cdmyfolder
~/workspace/myfolder$

Seehowthepromptupdatesandyouarenowinthemyfolderdirectory.SohowdoIgetout?
Thewaytogetbacktoyourworkspacedirectoryistotype:

$cd../

Thatisthecdcommandthenaspacethentwodotsandaforwardslash.Thisjumpsyououtof
onefolderandintotheoneabove.Sincewewereintheworkspacedirectorywhenwecreated
themyfolderdirectorytheworkspacedirectoryistheoneabove.

Ifyoutypecdonitsownthenyouwillgototherootdirectory.Inthiscaseitisrepresentedbya
tilde~oncloud9.Ifyoulistallthefilesandfolderswiththelscommandyouwillseethe
workspacedirectorywhereyouhavebeenworking.

~/workspace$cd
~$ls
lib/workspace/
~$cdworkspace
~/workspace$

Iwantedtoshownewusersofthecommandlinehowtousethecommandscdandlshereso
thatyoudontgetstuck.Remembercd../isusedtojumpoutofthecurrentfolderyouarein.

TheRMcommand

Thermcommandisshortforremoveanditdeletesfilesandfolders.Trytyping:

$rmfile1

Youwillseethatthefilenamedfile1hasnowbeendeleted.
Nowtrytodeletethefoldernamedmyfolder.

$rmmyfolder

Youwillprobablygetamessagelikethis:

$rmmyfolder
rm:cannotremovemyfolder:Isadirectory

Okayyoucannotdeletemyfolderasitisadirectory.
Thenextcommandwillremovethefolder,trythecommandagainbutaddtherflag.

$rmrmyfolder

Asyouwillseethefolderisnowdeleted.Therisshortforrecursively,Itbasicallymeansthat
anyfilesinsidethatdirectorywillalsobedeletedandaregoneforever.Thatiswhywehadthat
originalerrormessage.Wewerebeingprotectedfromaccidentallydoingsomethingstupid.We
didntactuallyhaveanyfilesinourmyfolderdirectorybutyougettheidea.

Okaytogetbacktosquareonetype:

$rmfile2file3hello.txt

Thisremovesallthefileswecreated,wehavejustnamedthemoneafteranotherinsteadof
typingthermcommandmultipletimes.

DuringtherestofthetutorialsIwillmentionwhatcommandsneedtobeusedsoyoudontneed
tomemorizethesecommands,Theyarejusttheretoshowyouthebasicsofnavigating,
creatinganddeletingfiles.

Ifyouarebrandnewtoanyofthistryexperimentingandcreatingyourownfilesandfolders.
Thebestwaytolearnistogetstuckandthengetunstuck.Hopefullynottakingtoolonginthe
process.

YourFirstRailsApp
AStaticWebpage

Okaytimeforyoutocreateyourfirstrailsapp.Itwillbeverysimpleandonlydisplayapage,
howeverhopefullyyouwilllearnabitaboutthestructureofarailsapp(thewayallthefilesand
foldersarelaidout)aswellasafewofthebasicrailscommands(Thatwewillusetogenerate
thingsforus,similartothecommandswehavebeenusingabove)andalittlebitaboutrails
conventions(railsdoesthingsinacertainwaytosaveyoutime).

Inyourworkspacedirectorytypetherailscommandtogenerateanewrailsapp:

Creatingyourfirstrailsapp
/workspace
$rails_4.2.5_newstatic_page
create
createREADME.rdoc
createRakefile
createconfig.ru
create.gitignore
createGemfile
createapp
createapp/assets/javascripts/application.js
createapp/assets/stylesheets/application.css
createapp/controllers/application_controller.rb
createapp/helpers/application_helper.rb
createapp/views/layouts/application.html.erb
createapp/assets/images/.keep
createapp/mailers/.keep
...

Youwillgetanicebiglistofthingsthathavebeencreatedandinstalled,muchlongerthanthe
listhere,Ihaveshortenedittosavespace.

Letslookatthatrailscommandusedtogenerateanewapplication:

$rails_4.2.5_newstatic_page

Westartwiththewordrailsasweareusingarailscommand,thenwehaveanargumentwe
passedspecifyingaversionnumber.Let'sgetridofthatforaminuteandtakeanotherlookat
thecommand.

$railsnewstatic_page

OkaycoolthisisstartingtolookalittlebitmorelikeenglishIcanunderstand!Seethewords
static_page,thatisthenameofthedirectoryorrailsapp.Itiswhatwehavecalledthisproject.

$railsnew

Sorailsnewistheactualcommand.Weusethiscommandtogenerateanewapplication.A
newwhatthough?Thatiswhywenamedtheapplicationstatic_page.Itcouldhavebeennamed
anythingbutitmadesensetocallitsomethingrelevant.Sobacktotheoriginalcommand,why
theunderscoresandnumbers?

$rails_4.2.5_newstatic_page

The_4.2.5_wepassedtotherailsnewcommandisaversionnumber.Itmeansusethis
versionofrails.ThereasonIhavedonethisissothatyoucanfollowalongwithasfewhiccups
aspossible.Ifyouweremakingyourownappyoumightjustdo
railsnewmyapp
withouta
versionnumber.

Okaycdintoyournewrailsapp,andonthelefthandsidewherethefilesandfoldersare
displayedclickyournewfolder(thelittletriangle)toopenupthenewapplication.

$cdstatic_page
~/workspace/static_page$

Doyouseetheapp/directory,config/directorythesetwofoldersaretheoneswewillusemost
forthistutorial.Okayinorderforustocheckthateverythinghasinstalledcorrectlylet'sstartup
theserverandruntherailsapplication.Typethecommand:

Creatingyourfirstrailsapp
/workspace/static_page
$railsserverb$IPp$PORT

Theactualcommandisrailsserverallonitsown,howeverwehaveabflagandaglobal
variable$IPfollowedbyapflaganda$PORTglobalvariable.Whenusingcloud9youadd
thoseflagsandglobalvariablestoruntheserver.Whenusingcloud9ifyoutypejustrailsserver
itwontwork.Theextraflagsandglobalvariablesarealittlebitofapaintotype,sofeelfreeto
copythiscommandintoyourconsole.

Creatingyourfirstrailsapp
/workspace/static_page
$railsserverb$IPp$PORT
=>BootingWEBrick
=>Rails4.2.5applicationstartingindevelopmentonhttp://0.0.0.0:8080
=>Run`railsserverh`formorestartupoptions
=>CtrlCtoshutdownserver
[2016022313:05:55]INFOWEBrick1.3.1
[2016022313:05:55]INFOruby2.3.0(20151225)[x86_64linux]

[2016022313:05:55]INFOWEBrick::HTTPServer#start:pid=1677port=8080

Lookattheoutputitsaysbootingwebrick,thisisthedefaultrailsserver.Thenabitfurtherdown
itsaysCTRLCtoshutdowntheserver.ThatistheCTRLkeyplustheletterCkeyonyour
computer.

Seethecloud9helppopupontherightthere,clickthelinkanditwillopenyourrailsappina
newtab,Orintheconsoleoutputafterthebootingwebrickline,clickthe
http://0.0.0.0:8080
line
whereitsaysapplicationstartingindevelopment.Youshouldseethis:

Thisisthedefaultrailsapplication,Feelfreetocheckoutthelinkontherightsuchasrails
guides,railsapietc.ClickCTRLCtoexittheserver(youneedtoclickintheconsolefirst)and
closetheextratab.Coolyouhavecreatedadefaultrailsapplicationandruntheserverand
viewedtheapplication.LETSGETCUSTOMIZING!

GeneratingtheController

Westartbygeneratingthecontroller,asitsnamesuggestsitcontrolsthings.Ifwetypeinaurl
itwillcontrolwhatwesee(Dontworryagreaterexplanationwillfollow).Typethecommandin
yellow,asyoucanseethenameoftherailscontrollerisPages.

Creatingyourfirstrailsapp
/workspace/static_page
$railsgeneratecontrollerPages
RunningviaSpringpreloaderinprocess1711
createapp/controllers/pages_controller.rb
invokeerb
createapp/views/pages

invoketest_unit
createtest/controllers/pages_controller_test.rb
invokehelper
createapp/helpers/pages_helper.rb
invoketest_unit
invokeassets
invokecoffee
createapp/assets/javascripts/pages.coffee
invokescss
createapp/assets/stylesheets/pages.scss

$railsgeneratecontroller

Theactualcommandistheoneabove,wetellrailsgenerateacontroller.Wepassthe
commandthenameofthecontroller.InthiscasePages.Lookatwhatgetscreated,a
pages_controller.rb
filethatislocatedinthedirectory
app/controllers/pages_controller.rb
.
Alsolookattheapp/views/pagesdirectory.Apagesdirectoryhasbeencreated.Inyour
navigatorontheleftwithallyourfilesandfolderstryfindingthesefilesanddirectories
mentioned.

WeusedthecommandrailsgeneratecontrollerPageswithacapitalp.Thefilethatgot
generatedthoughwaspages_controller.rb.Railshasautomaticallyconvertedthefilenameto
snakecase(Theuseofunderscores).

Startupyourserveragain:

Creatingyourfirstrailsapp
/workspace/static_page
$railsserverb$IPp$PORT

Intheurlatthetopofthepageadd
/pages
totheendoftheurl.Youwillseearoutingerror.We
willsolvethisshortly.Basicallyweneedtotellrailsalltheroutes/urlsthatwewilluse.

Openupthefilepages_controller.rbthatyouhavejustgenerated.Seehowthe
pages_controller.rbisnicelylocatedintheappfolderthenthecontrollersfolderandthenyou
seethefilewewantpages_controller.rb.

Creatingyourfirstrailsapp
/workspace/static_page/app/controllers/pages_controller.rb
classPagesController<ApplicationController
end

Letseditthisfilealittlebit.SeewehaveaclassofPagesControllerthatgotgenerated,theless
thansign<meansthisclassinheritsfromtheApplicationControllerwhichispartofrails.Also
seethattheclassisdefinedwiththeclasswordfollowedbythenameoftheclassandthenona
newlinetheendword.Betweenthisiswhereweaddourcode.

Creatingyourfirstrailsapp
/workspace/static_page/app/controllers/pages_controller.rb
classPagesController<ApplicationController

defhome
end

end

Addthehomeaction.ThethingIfounddifficultaboutlearningrailswasthatthingshaddifferent
names,forexamplethehome
action
isactuallyaruby(programminglanguage)method.Rails
isbuiltontopofrubyandthewayyoudefineamethodinrubyiswiththedefandend
keywords.Inotherprogramminglanguagesamorecommonnameformethodisafunction.So
technicallyyoucouldcallwhatyoujustwroteahomemethodorfunction.Howeverwewillstick
withthecorrectterminologyhereandcallitahomeaction.Alsoyouwillseethatthemethod
itselfisempty.Thisisokay,innormalrubyprogrammingthiswoulddonothing,howeverwith
railssincethisPagesControllerclassinheritsfromtheApplicationControllerfromrailsinsteadof
doingnothingbydefaultitrendersaview.Wewillcreatetheviewinaminute.
FirstSaveThe
FileByPressingCTRLSasmallcircleinthetabnearthetopwillbecomeanx.Always
saveeverychangeyoumake!

Lookatthepages_controller.rbfile,itisnamedwithsnakecaseorunderscoresbuttheclass
insidethefilePagesControllerhasbeennamedincamelcasewhereeveryfirstletterofaword
iscapitalized.Thisisanotherwayrailsdoesthingsanditwasautomaticallydonewhenwe
generatedthePagesController.Donttypethatbitbelow.

$railsgeneratecontrollerPages

Sincethecommandstateswewanttogeneratea
controller
wedontneedtotypetheword
controllerafterpages,itisconvertedforus.AlsoifyoulookatthewordPagesnoteIused
camelcaseforthenameofthecontroller.SoifIhadcalledthecontrollerwebsitepagesitwould
havebeennamed:WebsitePages.

AddingtheRoute

Nowthatwehaveourcontrollerwiththehomeaction,letsaddtheroute.Ifyourememberwhen
wetypedin/usersontotheendoftheurlwegotanerror,aroutingerror.Railsdidntknow
wheretolook.Soletsfixtheproblem.Gotoyourroutes.rbfilelocatedintheconfigfolder.

Creatingyourfirstrailsapp
/workspace/static_page/config/routes.rb
Rails.application.routes.drawdo
#Thepriorityisbaseduponorderofcreation:firstcreated>highestpriority.
#Seehowallyourrouteslayoutwith"rakeroutes".

#Youcanhavetherootofyoursiteroutedwith"root"
#root'welcome#index'

#Exampleofregularroute:
#get'products/:id'=>'catalog#view'

#Exampleofnamedroutethatcanbeinvokedwithpurchase_url(id:product.id)
#get'products/:id/purchase'=>'catalog#purchase',as::purchase

#Exampleresourceroute(mapsHTTPverbstocontrolleractionsautomatically):
#resources:products

#Exampleresourceroutewithoptions:
#resources:productsdo
#memberdo
#get'short'
#post'toggle'
#end
#
#collectiondo
#get'sold'
#end
#end
...

Okaythereisalotgoingonbuttheyareallcommentsapartfromthetopandbottomlines.Add
thiscodetothefile:

Creatingyourfirstrailsapp
/workspace/static_page/config/routes.rb
Rails.application.routes.drawdo

root'pages#home'
#Thepriorityisbaseduponorderofcreation:firstcreated>highestpriority.
#Seehowallyourrouteslayoutwith"rakeroutes".

#Youcanhavetherootofyoursiteroutedwith"root"
#root'welcome#index'

#Exampleofregularroute:
#get'products/:id'=>'catalog#view'

#Exampleofnamedroutethatcanbeinvokedwithpurchase_url(id:product.id)
#get'products/:id/purchase'=>'catalog#purchase',as::purchase

...

Ihavenotdeletedanything,onlyaddedsomecodetoline2.Therootwordtellsrailswhatpage
toloadfirstwhenyougototheapplication.Ahomepageiswhatyouwouldusuallygoto,this
canofcoursebeanypageyoucreatebutinthistutorialweonlyhaveonepagesodontworry.

Lookatthelinepages#home,rememberwegeneratedthepagescontrollerwearetellingrails
usethatsamepagescontroller.Openupthatpages_controller.rbfileandyouwillseethehome
actionwecreated.Afterthewordpagesweaddahashorpoundsign(railssyntax)andthenwe
sayusethishomemethodIwrote.

Sohopefullythatroutinglinemakesalittlebitmoresense.Rootmetothepages_controllerand
Iwanttoseethehomeaction.Soitisthecontrollerfirstthenapoundsignandthentheaction
name.

Startupyourserver:

Creatingyourfirstrailsapp
/workspace/static_page
$railsserverb$IPp$PORT

Okaywehavingamissingtemplateerror.Notaproblem.RememberIsaideventhoughour
homeactionisemptyrailsstilldoesstuffbydefault.Wellbydefaultitrendersaview.Timeto
createthatview.

PressCTRLCtoclosetheserver.

CreatingTheView

Lookintheappfolderthenviewsfolderandyouwillseeanemptypagesfolder.Thisfolderwas
generatedwhenweusedtherailsgeneratecontrollerPagescommand.Itautomatically
generatedafoldertoputallofourviewsrelatedtothepages_controller.

Youhavetwowaystocreatetheviewfilethatweneed.Youcanusethetouchcommand
coveredearlieroryoucanrightclickandhitcreatenewfile.Eitherwayweneedafilenamed
home.html.erb
Thefileisnamedhomebecausewecreatedahomeactionremember?The
HTMListoletusknowitisahtmlfileandthe.erbletsusknowwecanuseembeddedrubya
typeofsyntaxthatletsustyperubycodeinahtmlfileaswellasnormalhtmltagssuchas
<p></p>and<div></div>.

Method1
~/workspace/static_page$touchapp/views/pages/home.html.erb

Seehowwespecifythepathwherewewanttocreatethefile,Wewantitintheappfolderthen
intheviewsfolderthenouremptypagesfolderandthentheactualfilenameitself
home.html.erb
Rememberrailsisbuiltwithruby,thefilenamethereforehasthe.erbextension
sothatwecanuseembeddedrubyinthefileifwewantto.

Method2
Oryoucanrightclickandnamethenewfilehome.html.erbwhicheveriseasierforyou:

Okayopenupyournewlycreatedhome.html.erbfileandaddsomehtmltothepage.

Creatingyourfirstrailsapp
/workspace/static_page/app/views/pages/home.html.erb
<h2>WelcomeHome</h2>
<p>Afteryourlongjourneythroughrockymountainsanddrydustbowlsyouhavefinally
nearedtheend.</p>

Feelfreetocopyandpastethehtml.OnceagaindontforgettosavebypressingCTRLSYou
candofilethensavebutthattakestoolong.Ihavenotmentionedsavingverymuchbutmake
sureyousaveinordertoseethechangesyouhavemade.

Okaystartupyourserveragain:

Creatingyourfirstrailsapp
/workspace/static_page
$railsserverb$IPp$PORT

Youshouldhavesomethingsimilartothis:

Welldoneyouhavecreatedyourfirstrailsapplication.Sowhatexactlyhaveyoudonethen?
YoustartedbygeneratingaPagescontrollerandaddingahomeactiontothePagesController
class.Youthendefinedtherootroutewhichmeantyourapplicationwouldbydefaultloadthe
homeactionofthePagescontroller,Andfinallyyouaddedthehome.html.erbview.Youhave
createdastaticrailsapp.Iknowitdoesntseemveryimpressivebuttheseareallthingsyouwill
domultipletimeswhencreatingrailsappssoithelpstonailthebasics!

Ifyouarestillinyourrailsapplicationfolderyoucancdoutofitbackintoyourworkspace.Onto
applicationnumber2.

~/workspace/static_page$cd../
~/workspace$pwd
/home/ubuntu/workspace

WELLDONE!

AStyledApp
Thesecondappyoubuildwillbesimilartothefirstapp.Itwillhelpdrumhomevariousrails
commandsandthingsyouneedtoremember.Thestartofthisappisgoingtohavealittleless
explanationcomparedtothefirstapp.Thisissothatwecanspeedilygetsetupandcontinue
learning.ThenwhenweareatanewpointIwillstarttheexplanationsagain.Thisfirstbitwont
beanythingtoonew,itwillbeverysimilartothepreviouschapter.

Youmaybewonderingwhynotjustcontinuewiththefirstappandbuildontopofthat?Wellin
myopinionabetterwaytolearnistobuildmultipleappsbecauseyouarefarmorelikelytobe
typingthecommandshundredsoftimescomparedtojustafewtimes.Forexampleyoudont
actuallytypetherailsnewcommandthatoften,onlyatthestartofanapplication.Howeveritis
stillimportanttorememberthecommandotherwiseyouwontbecreatinganynewapps
hahahaha.

Makesureyouareintheworkspacedirectory:

~/workspace$pwd
/home/ubuntu/workspace

Generateanewrailsappcalledstyled_app

Astyledapp
/workspace
$rails_4.2.5_newstyled_app
create
createREADME.rdoc
createRakefile
createconfig.ru
create.gitignore
createGemfile
createapp
createapp/assets/javascripts/application.js
createapp/assets/stylesheets/application.css
createapp/controllers/application_controller.rb
createapp/helpers/application_helper.rb
createapp/views/layouts/application.html.erb
createapp/assets/images/.keep
createapp/mailers/.keep
...

Changedirectoryintothenewapp:

$cdstyled_app/
~/workspace/styled_app$


Runtheserver:
Checkallisfine.

Astyledapp
/workspace/styled_app
$railsserverb$IPp$PORT

Generateapagescontroller:

Astyledapp
/workspace/styled_app
$railsgeneratecontrollerPageshome
RunningviaSpringpreloaderinprocess3734
createapp/controllers/pages_controller.rb
routeget'pages/home'
invokeerb
createapp/views/pages
createapp/views/pages/home.html.erb
invoketest_unit
createtest/controllers/pages_controller_test.rb
invokehelper
createapp/helpers/pages_helper.rb
invoketest_unit
invokeassets
invokecoffee
createapp/assets/javascripts/pages.coffee
invokescss
createapp/assets/stylesheets/pages.scss

Okaytimeforacloserlookatthatgeneratecommand.Mostofthecommandshouldmake
sense,youaretellingrailstogenerateacontrollernamedPages,howeverifyoulookwehave
addedthewordhome.Wehaveusedthesamecommandbutaddedanargument.
railsgeneratecontrollerNAME[action]

Theargumentweaddedwasanaction.Rememberinsidethecontrollerwecanaddruby
methodshowevertheyarecalledactions.Rememberthehomeactionfromtheprevious
chapter.Thisisaquickerwayofgeneratingthesamething.

Lookatwhatgotcreated,aroutepages/homeaswellasahome.html.erbtemplateinits
appropriatepagesfolderwhichisagaininsidetheviewsfolder.Attheverytopthe
pages_controller.rbgotcreatedandifyoulookatthebottomyoucanseesome
app/assets/stylesheetsgotgeneratedwhichwecanusetostyletheapplicationwithcss.

Lookatyourpages_controller.rbfile:
Thehomeactionautomaticallygotgenerated.

Astyledapp
/workspace/styled_app/app/controllers/pages_controller.rb
classPagesController<ApplicationController
defhome
end
end

Lookatyourhome.html.erbfileitalsogotautomaticallygenerated:

Astyledapp
/workspace/styled_app/app/views/pages/home.html.erb
<h1>Pages#home</h1>
<p>Findmeinapp/views/pages/home.html.erb</p>

Nowtakealookatyourroutes.rbfile:

Astyledapp
/workspace/styled_app/config/routes.rb
Rails.application.routes.drawdo
get'pages/home'

#Thepriorityisbaseduponorderofcreation:firstcreated>highestpriority.
#Seehowallyourrouteslayoutwith"rakeroutes".

...

Agetroutealsogotaddedautomatically.Thisisabitdifferentthantherootrouteweused
earlier.Howeveritstillusesthepagescontrollerandhomeactioninthatcontroller.

Runtheserver:

Astyledapp
/workspace/styled_app
$railsserverb$IPp$PORT

Add
/pages/home
totheendofyoururltoviewtheaboutpage,Thiscomesfromtheroutes.rb
filewhereitcreatesagetrequestforthepagescontrollerandthehomeactionwhichdefaultsto
renderingthehome.html.erbviewfile.Youshouldseethehomepagefirst:

ClosetheserverCTRLC
Remembertobesavingyourwork.

Addanaboutactiontothepages_controller.rbfile:

Astyledapp
/workspace/styled_app/app/controllers/pages_controller.rb
classPagesController<ApplicationController
defhome
end

defabout
end
end

Addanabout.html.erbfiletoyourapp/view/pagesdirectory:

Iusethetouchcommandherebutrememberyoucanrightclickifyoulike.

Astyledapp
/workspace/styled_app
$touchapp/views/pages/about.html.erb

Updatetheroutes.rbfile:

Astyledapp
/workspace/styled_app/config/routes.rb
Rails.application.routes.drawdo

get'pages/about'

root'pages#home'

#Thepriorityisbaseduponorderofcreation:firstcreated>highestpriority.
#Seehowallyourrouteslayoutwith"rakeroutes".

...

Iremovethegetrouteandreplaceitwithtwolinesabove.Therootoftheapplicationbecomes
thepagescontrollerhomeactionwhichdefaultstorenderingthehome.html.erbfile.Ifyoutype
/pages/about
ontotheendofyoururlyouwillgettotheabout.html.erbfile,thisfilewillbe
blankaswehavenotaddedanythingtoityet.Thepages/aboutrouteusesthekeywordget.
Thisisatypeofhttprequestbetweenawebbrowserandserver.Agetrequestretrievesdata
fromaparticularsource.Inthiscasewewanttogettheabout.html.erbfile.Toreadmoreonget
requestsandpostrequestscheckout
w3schools
.

Okaywherehavewegottowiththisapp?Wehavecreatedthesamehomepagelikewedidin
thepreviousappandwehavealsoaddedanaboutpageaswell,Hopefullyyoudidthisina
muchshortertimethanthelastchapter.

AddingLinks

Addthefollowinglinestoyourhome.html.erbfile:

Astyledapp
/workspace/styled_app/app/views/pages/home.html.erb
<h1>Pages#home</h1>
<p>Findmeinapp/views/pages/home.html.erb</p>
<%=link_to'ABOUT'%>

Saveyourworkandruntheserver:

Astyledapp
/workspace/styled_app

$railsserverb$IPp$PORT

LookatyourhomepageandyouwillseewehaveaddedalinkwiththetextABOUT.Howeverif
youclickitthenitwontgoanywhere.Whynot?Okaylookatthelineyouadded,youused
embeddedruby.

Embeddedrubyuseseithertwoformats
1. <%%>
2. <%=%>
Versiononeisalessthansignandapercentagesign.itisusedforprocessinglogicsuchasif
statements.Versiontwoisalessthansignapercentagesignandanequalssign.Itisusedfor
OUTPUTTING
tothescreen.Ifyouwanttoseetheresultthenyouusetheembeddedrubywith
theequalssign.Asyoubuildmoreappsthiswillbecomealotclearer.

Insidetheembeddedrubyweusearailshelpermethod.Itiscalledthatbecauseitishelping
generatealink.Themethodislink_toittakesthenameofthelinkinthiscasewenamedit
ABOUTanditalsotakesthepathtogotoasanargument.Beforeweaddthatthoughlets
inspectourhomepage.

Rightclickonthepageandselectinspect:

Ifyouopenupthebodytagsandlookattheaboutanchorlinkyouwillseethelink_tojust
generatesanormallinkinhtml.Ifyoulookatthehref=/youwillseewehaventprovideda
destinationsothelinkhasdefaultedtoforwardslashwhichjustreturnsustothehomepage.
Okaytimetoupdatethelinktotakeustotheaboutpage.

Updatethehome.html.erbfile:

Astyledapp
/workspace/styled_app/app/views/pages/home.html.erb
<h1>Pages#home</h1>
<p>Findmeinapp/views/pages/home.html.erb</p>
<%=link_to'ABOUT',pages_about_path%>

Youaddacommafollowedbythetextpages_about_path,Thislinewilltakeyoutotheabout
page.Ifyourestarttheserverandinspecttheanchorelementagainyouwillseethehyperlink
referencenowpointstothepagescontrollerandaboutaction:href=/pages/about.

Wheredoesthepages_about_pathcomefrom?

Youdefinedsomeroutesinyourroutes.rbfilesothelinepages_aboutisaprefixthatweuseto
gettotheaboutpage.Insteadofhardcodingtheactuallinkweusethisprefixsothatifthe
actuallinkchangestheprefixwillstillwork.
Inyourconsoletypethefollowing:

Astyledapp
/workspace/styled_app
$rakeroutes
PrefixVerbURIPatternController#Action
pages_aboutGET/pages/about(.:format)pages#about
rootGET/pages#home

Youcanseealltheroutesthataredefinedintheroutes.rbfile.Theleftcolumnshowstheprefix,
thenthetypeofhttpverbwhichforthetworoutesdefinedisaGETrequest.Wethenhavethe
URIpatterncolumn,ThisishowthelinkwouldlookintheURL,itistheactualpathtothe
resource.Thenthefinalcolumnshouldlooksomewhatfamiliar,itisthecontrollerfortheroute
anditsaction.

Wecanusetheprefixalongwiththerailslink_tohelpermethodtocreatealink.Allwedowith
theprefixisadd_pathtotheendofitandthepathtothatresourcegetsgeneratedforthe
anchorlink.Sotogettotheaboutpagewelookattheprefixwhichispages_aboutandappend
_pathtothengetpages_about_path.Ifwewantedtogetourhomepageorrootroutewelookat
ourhomeactionandseetherootprefix,wecanthenadd_pathtothengetroot_pathwhichcan
againbeusedincombinationwiththerailshelpermethodlink_totosendustothehomepage.

Excellentnowwewilladdalinktotheaboutpage:


Astyledapp
/workspace/styled_app/app/views/pages/about.html.erb
<%=link_to'Home',root_path%>

Remembertheroot_pathhelpercomesfromappending_pathtotherootprefix.

Ifyousaveandstartupyourserveryoushouldbeabletonavigatebetweenthepages:

Astyledapp
/workspace/styled_app
$railsserverb$IPp$PORT

Shuttheserverdownwhenyouaredone.

TheApplicationLayoutFile

Intheviewsfolderaboveyourpagesfolderyouwillseealayoutsfolder.Openitupandyouwill
findtheapplication.html.erbfile.Youcanseethatitlookslikeanormalhtmlwebpageexcept
forsomestylesheetandjavascripthelpermethodsinthe<head>tag.

Alsointhebodytagyouwillseeapieceofembeddedrubycode,Itoutputssomethingbecause
ofthe=sign.

Astyledapp
/workspace/styled_app/app/views/layouts/application.html.erb
<!DOCTYPEhtml>
<html>
<head>
<title>StyledApp</title>
<%=stylesheet_link_tag'application',media:'all','dataturbolinkstrack'=>true%>
<%=javascript_include_tag'application','dataturbolinkstrack'=>true%>
<%=csrf_meta_tags%>
</head>
<body>

<%=yield%>

</body>
</html>

Theyieldwordmeansthatitwillshowwhateverview/templateyouarerequesting.Sowhenyou
visittheaboutpageitistheabout.html.erbviewfilethatgetsyielded.

Alsonoteyouarenotpassinganyargumentstoyield,Youarejustusingthewordyieldonits
own,Inthissituationyieldrendersthetemplateorviewofthecontrollerandactionthatyouare
requesting.WhenwevisittheaboutpagewerequestthePagesControllerandinthattheabout
action.

Whyisthisuseful?Itmeansyoudonthavetokeepontypingoutthedoctypedeclarationand
htmlandheadtagsetc.Itremainsinoneplace.Ifyoulookatyourabout.html.erbfileyouwill
seeithasnoneofthosetags,Thisisbecauseyouareessentiallyfillinginthecontentforthe
bodyofthewebpage.Lookbackatyourapplicationlayoutfileandyouwillseeyieldisinsideof
thebodytags.Sotheabouttemplategetsyieldedwhenrequestedandagainsodoesthehome
template.

Allofthismeansyoucaneasilyaddcontentthatremainsthesameoneverypage,suchas
navigation.Inyourapplication.html.erbfileadd:

Astyledapp
/workspace/styled_app/app/views/layouts/application.html.erb
<!DOCTYPEhtml>
<html>
<head>
<title>StyledApp</title>
<%=stylesheet_link_tag'application',media:'all','dataturbolinkstrack'=>true%>
<%=javascript_include_tag'application','dataturbolinkstrack'=>true%>
<%=csrf_meta_tags%>
</head>
<body>

<nav>
<%=link_to'HOME',root_path%>
<%=link_to'ABOUT',pages_about_path%>
</nav>

<%=yield%>

</body>
</html>

Addanavtagandinsideitaddthesamelinks.Removethelinksfromyourhome.html.erband
about.html.erbviewtemplates:

Astyledapp
/workspace/styled_app/app/views/pages/about.html.erb

Astyledapp
/workspace/styled_app/app/views/pages/home.html.erb
<h1>Pages#home</h1>
<p>Findmeinapp/views/pages/home.html.erb</p>

Remembertosaveandrunyourserver:

Astyledapp
/workspace/styled_app
$railsserverb$IPp$PORT

Nomatterwhatpageyouareonyouwillseethelinks.Thisisbecausetheyareinthe
applicationlayoutfile.Theyarenotinatemplatethatisbeingyieldedsotheyremaintherethe
wholetime.

Letsaddalittlebitmoretothelayoutfile.Aswellasanavtagweshalladdafooteraswellas
mostpageshaveafooterbeneaththecontent.


ThethreedotsrepresentcodeIamnotshowing,justtosavespace,Onlyaddthehighlighted
code.

Astyledapp
/workspace/styled_app/app/views/layouts/application.html.erb
<!DOCTYPEhtml>

...

<nav>
<%=link_to'HOME',root_path%>
<%=link_to'ABOUT',pages_about_path%>
</nav>

<%=yield%>

<footer>
<p>Copyright<%=Date.current.year%></p>
</footer>

</body>
</html>

Asyoucanseewehaveasemantic(itdescribesitself)htmlfootertagandinsideitisa
paragraphtag.Ifyoulookattheparagraphtagthereisthewordcopyrightandthensome
embeddedrubytags,rememberthesetagsallowustouserubycodeinourhtmlviewfiles.The
=signmeansthecodegetsoutputtedtothescreen.

WeusetheDatemethod,wethencalltherailscurrentmethodonthedatemethodwhichgives
usthecurrenttime,Wethenusetheyearmethodonthecurrenttimeandtheresultofthese
chainedtogethermethodsisthecurrentyear.Thesemethodsmayseemabitconfusing
howevertheyareallmethodsoftheDateclass.Youcanseeandtryoutothermethods
here
suchastheyesterdaymethod(Iwonderwhatthatwilloutput)ortheagomethodwhichcanbe
usedtoseehowmanysecondsagosomethingwassubmittedforexample.

NowthatwehaveanavigationandafooterIthinkthehomepageandaboutpageneed
sprucingupabit.Youcanaddwhatyouwantinsideofthefilesorjustcopyme,itsuptoyou.

Astyledapp
/workspace/styled_app/app/views/pages/home.html.erb
<h1>HOMELY</h1>
<p>Welcomehome</p>
<p>Sometimesitisnicetojustputyourfeetupandrelax</p>
<p>Ifyouhaven'tdoneitrecentlythenIwouldreallyrecommendit!</p>

Astyledapp
/workspace/styled_app/app/views/pages/about.html.erb
<h1>ABOUT</h1>
<h3>WhoamI?</h3>
<p>ToyouIamastrangerbuttoothersIamafriend</p>
<p>Whichoneareyou?OnlyIdecideintheend.</p>

Okaynowthatthehomeandaboutpageshavesomecontentitstimetoaddalittlebitofstyle
tothepage!

StylingThePages

Intheassetsfolderandinthestylesheetsfolderisapages.scssstylesheet.Thisiswherewe
willputourCSStostylethewebpage.

Astyledapp
/workspace/styled_app/app/assets/stylesheets/pages.scss
//PlaceallthestylesrelatedtothePagescontrollerhere.
//Theywillautomaticallybeincludedinapplication.css.
//YoucanuseSass(SCSS)here:http://sasslang.com/

*{
margin:0;//resetthepaddingandmargin
padding:0;
}

body{
fontfamily:sansserif;//changethefontofthewebpage
textalign:center;//centerthetext
}

nav{
background:#222;//colorthenavigationblack
marginbottom:1em;//addmarginatthebottomofnavforwhitespace

a{//stylethelinks
display:inlineblock;//alignthelinksnexttoeachother
padding:1em2em;//paddthelinksoutmakethembigger
color:#fff;//colorthetextwhite
textdecoration:none;//removetheunderlinefromthelinks
}
}

h1,h3{
margin:1em0;//addatopandbottommarginof1emtotheheadings,giveleftandright
0margin
}

p{

padding:.5em0;//givetheparagraphssomepadding
}

footer{//stylethefooter
bordertop:1pxsolid#eee;//addalightgreybordertothetopofthefooter
padding:1em0;//paddoutthefooter
fontstyle:italic;//changethefonttoitalic
position:absolute;//changethepositionsothefooterstickstothebottomofthepage
bottom:0;//makethefootersticktotheverybottom
left:0;//centerthetext
right:0;//centerthetext
}

Feelfreetocopyandpastethiscssoraddyourown.Inrealityyouwouldntusethiscssina
website,youwoulduseacssframeworklikebootstrapthataddssomenicedefaultstyleswe
canuse.Howeverthatwillcomelater.

Thetextafterthetwoforwardslashes//isacsscomment,youdontneedtotypethemout,they
areherejustforaquickexplanation.

Nicelydoneyouhavejustbuiltyoursecondrailsapp,Itwassimilartothefirstapphoweveryou
addedanextraaboutactionandviewtemplate.Youthenaddedanavandafootertothelayout
sothatyoucouldnavigatebetweenpageswiththelink_torailshelpermethod.Finallyyou
styledthewebpagewithcss.

WELLDONE!

Challenge:AStaticRailsApp

Okayitistimeforachallenge,Iwillgiveyousomeinstructionstofollowandyouwillbuildyour
ownrailsapp.What!IhearyousaybutI'vejustbuilttworailsappsandyourmakingmebuild
yetanother??!!?Yeahsorry,exceptthistimeyouwillbegettinglesshelp.Itisagoodwayto
learn,alsoyouwillquicklyrealizethethingsthatyoudontknow.Whendoingthisexercise
remembertodoublecheckeverythingyoutypeanddontworryifyoumuckupasyoucanjust
startover.WhenIfirststartedoutsomesimplethingsIgotstuckonwerenotaddingacomma
inthecorrectplaceonalink_tohelpermethodorforgettingtousean=signwhenusing
embeddedrubysonothinggotoutputtothescreen,Essentiallyjustsyntaxerrors,Okaywith
thatsaidfeelfreetolookbackatthepreviouschaptersforhelp.

Step1
CD
intoyour
workspace
directory

Step2
Generateanewrailsapp
calledmy_pages(Youdontneedtouseaspecificversionnumber)

Step3
CD
intothenewrailsapp
(my_pages)

Step4
Runtheserver
andcheckthatyougetthedefaultrailspage

Step5
Generateacontroller
named
Pages
andatthesametimegeneratea
home
and
about
action
(Youshouldgettheviewsgeneratedaswelletc.)

Step6
Openyour
routes.rb
fileandchangethegethomeroutetoa
rootroute
,(rememberthe#sign
syntax)

Step7
Runtheserver
andcheckyouaredirectedtothehomepage

Step8
Openthe
application.html.erb
fileandaddanavhtmltag.Insidethenavtagaddtworails
links:
OnelinkfortheHomepageandonelinkfortheAboutpage.

(Rememberyoucan:
rakeroutes
)

Step9
Updatethe
home.html.erb
fileand
about.html.erb
file,addyourowncontent.

Step10
Openthe
pages.scss
stylesheetandaddsomestylestoyourapp.

SuccessIn10stepsyouhavemadeyourownrailsappwithnohelp,prettygoodgoingifyou
askme.Whatdidyougetstuckon?Wasitrememberingcertainrailscommandsormaybe
somespecificsyntax?Makeanoteofitandstickittoyourscreen!

ASimpleFormApp

Thenextrailsappwillbeaverysimpleform,youwillgenerateamodel(aclassthatdefines
attributes)withanameattribute,andthensubmitthedatatothedatabase.Youwillthenshow
allthenamesonapage.Thereareafewnewthingstolearninthislesson,howeveritshould
soonclicktogether.

Makesureyouareintheworkspacedirectory:

~/workspace$pwd
/home/ubuntu/workspace

Generateanewrailsappcalledform_app

Asimpleformapp
/workspace
$rails_4.2.5_newform_app
create
createREADME.rdoc
createRakefile
createconfig.ru
create.gitignore
createGemfile
createapp
createapp/assets/javascripts/application.js
createapp/assets/stylesheets/application.css
createapp/controllers/application_controller.rb
createapp/helpers/application_helper.rb
createapp/views/layouts/application.html.erb
createapp/assets/images/.keep
createapp/mailers/.keep
...

Changedirectoryintothenewapp:

$cdform_app/
~/workspace/form_app$

Runtheserver:
Checkallisfine.

Asimpleformapp

/workspace/form_app
$railsserverb$IPp$PORT

Generateapeoplecontroller:

Asimpleformapp
/workspace/form_app
$railsgeneratecontrollerPeopleindexnew
RunningviaSpringpreloaderinprocess726
createapp/controllers/people_controller.rb
routeget'people/new'
routeget'people/index'
invokeerb
createapp/views/people
createapp/views/people/index.html.erb
createapp/views/people/new.html.erb
invoketest_unit
createtest/controllers/people_controller_test.rb
invokehelper

HerewearegeneratingacontrollercalledPeople,Thisisbecauseinthisappwewillbe
submittingpeople'snamessoacontrollerofpeopleseemsappropriate.Ifyourememberwe
alsogettheindex.html.erbfileandthenew.html.erbfilegeneratedforus,(aswearespecifying
thosetwoactionsinthecommand)andwealsogetsomeroutesautomaticallygeneratedinthe
routes.rbfile.

Updatetheroutes

Asimpleformapp
/workspace/form_app/config/routes.rb
Rails.application.routes.drawdo

resources:people
root'people#index'

#Thepriorityisbaseduponorderofcreation:firstcreated>highestpriority.
#Seehowallyourrouteslayoutwith"rakeroutes".

#Youcanhavetherootofyoursiteroutedwith"root"
#root'welcome#index'

Changetheindexactionsothatitistherootroute,whenyouloadtheapplicationthiswillbethe
firstpagethatshows.Theresourceslineautomaticallycreatesmanyroutesforus.Use
rake
routes
totakeaquicklook.(Wewillcoverthemmorelater).

Runtheserver:

Asimpleformapp
/workspace/form_app
$railsserverb$IPp$PORT

Youshouldseetheindex.html.erbpage,ifyouadd/people/newtotheendoftheurlyouwill
alsoseethenewpage.Asyoumighthaveguessedthiswillbethepagewherewecreateanew
person.

Generatethepersonmodel

Asimpleformapp
/workspace/form_app
$railsgeneratemodelPerson
RunningviaSpringpreloaderinprocess875
invokeactive_record
createdb/migrate/20160226194318_create_people.rb
createapp/models/person.rb
invoketest_unit
createtest/models/person_test.rb
createtest/fixtures/people.yml

Herewearegeneratinga
model
,wehavenamedthemodelPerson.Amodelisusedtodefine
anobject.WhatdoImeanbyobject?Anobjectcanbeanything,inthiscasewearedefininga
singleperson.Themodelfilecanbefoundunderapp/models/person.rbifyouopenitupyouwill
seethatitisempty.Soamodelfileofperson.rbgotgenerated.Ifyoulookyouwillseea
migrationfilegotgeneratedunderdb/migrate/20160226194318_create_people.rb,thatnumber
isatimestamp,yourswillbedifferent.

Themigrationfileisthefilethatupdatesthedatabase,Eventhoughyouhaveaperson.rb
modelfileyourapplicationdoesnotactuallyhaveanywheretosavethepersonintobecausewe
havenotupdatedthedatabase.Sothemigrationfileisusedtoupdatethedatabase.

Lookclosely,youusedtherailsgeneratemodelcommandtogenerateaPersonmodel,the
modelfilethatgotgeneratedwasindeedcalledperson.rb,butlookatthemigrationfile,
db/migrate/20160226194318_create_people.rbthefileiscalledcreate_
people
.rbsoitgot
pluralizedtopeople.Themigrationfilecreatesthetableinthedatabase.Itupdatesthe
databasewiththeinformationthatwewillputinit.Sinceitisatablethatholdsinformationon
notonepersonbutmanypeoplethispluralizationstartstomakealittlemoresense.Thisisone
ofrailsconventions,Amodelwillbesingular(person)butadatabasetablewillbeplural(people
asitholdsinformationonmanypeople).Dontworryaboutmemorizingthisinitially,Iwillremind
youthroughoutthebook.


Asimpleformapp
/workspace/form_app/app/models/person.rb
classPerson<ActiveRecord::Base
end

Eventhoughyourperson.rbfileisemptyitisstillusedbyrailstogenerateapersonobjectand
saveittothedatabase.Wewillseelaterhowwecanusethisfiletovalidateattributes.For
exampleifyouwantedpeopletoonlyenteranamelongerthan3characters.

Updatingthemigrationfile

Asimpleformapp
/workspace/form_app/db/migrate/20160226194318_create_people.rb
classCreatePeople<ActiveRecord::Migration
defchange
create_table:peopledo|t|

t.timestampsnull:false
end
end
end

ThemigrationfilehasaclassofCreatePeople,whichisjustanormalrubyclass.Thisclass
inheritsfromActiveRecord::Migrationwhichispartofrails.Thisallowsustothenusethisfileto
updateourdatabase.

InsidetheCreatePeopleclasswehaveamethod(definedwiththedefandendkeywords)
calledchange.Thechangemethodhasinsideitsomethingcalledaschemastatement.The
create_tablestatementisastatementthatisusedtocreateatablecalledpeople.

Thecreate_tablestatementtakesaparameterforthename.
:people
isthenameofthetable
andithasacoloninfrontofit.why?Itiscalledasymbol,Ifyouhavenevercomeaccrossa
symbolbeforethenknowthatitissimilartoastringexceptthatitusesfarlessmemory.Itis
usedtorepresentsomething,inthiscasethenameofthetable.

Afterthesymbolwehavea
do
keywordand
end
keywordafewlinesdown.Thisiswhatyou
callablock.Ablockiscodethatisusedbyothercode.Ifyoulookjustafterthedokeywordyou
see
|t|
Thisisatemporaryvariablethatisusedtospecifythecolumnswewilladdtothetable.
Youcanseethiswitht.timestampswhichcreatescreated_atandupdated_atcolumns,(dont
worrytoomuchaboutthatfornowthough).

Addthefollowinglinetoyourmigrationfile.

Thislinecreatesacolumninthepeopletable,thecolumniscallednameanditisoftypestring.
Thetypeofstringmeansthatwewillbeputtingshortcontentinthere,lessthan255characters.

Asimpleformapp
/workspace/form_app/db/migrate/20160226194318_create_people.rb
classCreatePeople<ActiveRecord::Migration
defchange
create_table:peopledo|t|

t.string:name
t.timestampsnull:false
end
end
end

UpdateTheDatabase

Asimpleformapp
/workspace/form_app/
$rakedb:migrate
==20160226194318CreatePeople:migrating=====================================
create_table(:people)
>0.0012s
==20160226194318CreatePeople:migrated(0.0013s)============================

Thiscommandrunsthemigrationfilethatyoujustupdated.Asyoucanseebytheoutputa
tablegetscreatedcalledpeople.

Ifyoulookinthedbfolderyouwillseeanewfilecalledschema.rb,Thedatabaseschemahas
beenupdatedandifyouopenupthefileyouwillseethetableyouhavecreated.

Asimpleformapp
/workspace/form_app/db/schema.rb

...

ActiveRecord::Schema.define(version:20160226194318)do

create_table"people",force::cascadedo|t|
t.string"name"
t.datetime"created_at",null:false
t.datetime"updated_at",null:false
end

end

Youcanseethepersontablehasacolumncallednamewhichisoftypestring.Youcanalso
seethatthetimestampslineinthemigrationfilecreatedtwocolumns,oneofcreated_atand
oneofupdated_at.Thesecanbeusedtoseewhenanattributewascreated,Agoodexampleis
ablogpostgetscreated_atacertaintime.

Okayyouhavecreatedapersonmodelfile,youhavecreatedandupdatedyourmigrationfile
andyouhavealsomigratedyourdatabaseschematoupdateitwithyourpeopletable.What
next?

UpdateThePeopleController

Asimpleformapp
/workspace/form_app/app/controllers/people_controller.rb
classPeopleController<ApplicationController
defindex
end

defnew

@person=Person.new
end
end

Thetext@personiscalledaninstancevariable.Itisavailabletoanymethodthatyouwritein
thepersonclass(person.rbfile).Irecommendyoureadupalittleoninstancevariablesifyou
areshakyonthem.Inrails,instancevariablesinthecontrolleraremadeavailabletotheview
files.

Herewecreateanewpersonobject/instancewiththelinePerson.new(capitalP).Thisisusing
ourperson.rbfiletocreateapersonobject,whichthengetssavedintheinstancevariable
@person.The=signistheassignmentoperator,thenewPersonobjectisstored/assignedto
the@personvariable.Nowwewillusethis@personvariableinourviewfile.

AddAFormToThenew.html.erbView

Asimpleformapp
/workspace/form_app/app/views/people/new.html.erb
<%=form_for@persondo|f|%>
<%=f.text_field:name,:placeholder=>"Name"%>
<%=f.submit"Submit"%>
<%end%>

Inthisviewfileweuseerborembeddedrubytocreatetheform.Weusean=signonthefirst
linetooutputtheform,thentheform_formethodwhichusesthe@personinstancevariablethat
wedefinedinourcontrollernewaction.SointheviewwearenowusingthatnewPersonobject

thatwehavecreated.Wethencreateablockwiththedokeywordandatemporaryvariable
called|f|whichisusedtocreatetheformfields.

Thetoplineoferbisthenclosed,ifyoulookatthebottomyouwillsee<%end%>whichcloses
outourblockofrubycode.Noticeitdoesnthaveanequalssignsincewedontwanttooutput
thatcode.

InBetweenourblockofcodewehavemoreembeddedrubythatoutputsstuff.weusethe
temporaryvariabletocreateatext_fieldwhichrelatestoournamefieldinthepeopletable.(Go
openuptheschema.rbfileagainandseethatthepeopletablehasanamecolumnsoweare
creatinganametext_fieldsothatwecansaveanametothedatabase)Alsoyouwillseea
placeholder,thisputstextinsidethetextfieldautomaticallysoastoprompttheuser.Theother
erblineisf.submitwhichcreatesasubmitbuttonsothatwecansubmitourdatatothe
database.ThelineSubmitiswhatwillshowonthebutton.

Runtheserver:

Asimpleformapp
/workspace/form_app
$railsserverb$IPp$PORT

Navigateto/people/newandyouwillseeanametext_fieldandasubmitbuttonthatlookslike
this:

Ifyouclickthesubmitbuttonhoweveryouwillgetanerror:

Theerrorsaysthecreateactioncouldnotbefound.Theformisusingthenewactioninthe
peoplecontrollerandthenlooksforanactioncalledcreatewhenthesubmitbuttonispressed.

AddingTheCreateAction

Asimpleformapp
/workspace/form_app/app/controllers/people_controller.rb
classPeopleController<ApplicationController
defindex
end

defnew
@person=Person.new
end

defcreate
@person=Person.create(person_params)
if@person.save
redirect_to/
else
render:new
end
end

private
defperson_params
params.require(:person).permit(:name)
end
end

Wehaveaddedacreateactionandaperson_paramsmethodwhichisprivateasitis
underneaththeprivatekeyword.Thismeansthatthemethodperson_paramscannotbecalled
withareceiver.
Theideaisthatprivatemethodsarehidden,andcanonlybecalledintheirownclass.Inthis
casethePersonclass.Irecommendyougoogleaboutrubyprivatemethodsasitisabit
confusing.

Inrailsanactionrendersatemplate,thenewactionrendersthenew.html.erbfile.Sowehide
theperson_paramsmethodtoensurerailsdoesntrouteanyHTTPcallstothataction.

Theperson_paramsmethodusesthelineparams.require(:person).permit(:name)towhitelist
whatwesubmittoourdatabase.Herewesayonlyallowthe:nametobesubmitted.

IfwelookbackatthecreateactionnowwearecreatinganewPersonwiththecreatemethod,
andwearepassingtheperson_paramsmethodtothecreatemethod,sothatwhenwecreatea
newpersonweonlyallowthename.Wethenstorethisinthe@personinstancevariable.
Wehaveanifstatementthatchecksisthe@personwecreatedgotsavedtothedatabase.If
thisistrueanditgotsavedtothedatabasethenweredirecttotheindextemplate.


Thecreatemethodautomaticallycreatesanobject(apersonobject)andtriestosaveittothe
database,Ifthecreatemethodcannotdothisthentheelsestatementthatcheckswhetherthe
@persongotsavedwillrunandwewillrenderthenewpageagain.

Runtheserver:

Asimpleformapp
/workspace/form_app
$railsserverb$IPp$PORT

Navigateto/people/newandaddsomenamesandsubmitthem,dothisacoupleoftimes.

UpdatingTheIndex.html.erbPageAndIndexAction

Ifyoulookatyourindexpageyouwillseethatitisntshowinganyofthenameswehave
submittedtothedatabase.Timetofixthat.

Asimpleformapp
/workspace/form_app/app/controllers/people_controller.rb
classPeopleController<ApplicationController
defindex

@people=Person.all
end

defnew
@person=Person.new
end

defcreate
@person=Person.create(person_params)
if@person.save
redirect_to/
else
render:new
end
end

private
defperson_params
params.require(:person).permit(:name)
end
end

Inthepeoplecontrollerindexactionwecreateaninstancevariablecalled@peoplebecausewe
wanttostoreeverypersoninourdatabaseinthatinstancevariablesowepluralizethename
(despitethefactitcouldbecalledanything).WethentargetourPersonclassandcallthe.all

methodtoqueryallthepeopleinthedatabase.Wecannowusetheinstancevariableinour
index.html.erbview.

Asimpleformapp
/workspace/form_app/app/views/people/index.html.erb
<%@people.eachdo|p|%>
<p>Name:<%=p.name%></p>
<%end%>
<%=link_to"AddName",new_person_path%>

Intheindexfileaddtheembeddedrubyabove,Wetaketheinstancevariable@peoplefromour
controllerindexactionandcalltherubymethodeachonit.Thisiteratesthrougheverypersonin
thedatabase.Wecreateaparagraphwiththetextname:andthenusingatemporaryvariable
|p|anderbweprintoutthenameofeachpersonobject.Thenamecomesfromthename
attributeinourdatabase.Ifyouopentheschema.rbfileandlookatthepeopletableyouwillsee
thenamecolumn,Thisiswhatwearetargetingforeachpersonobjectthatweloopthroughwith
theabovecode.Rememberweuseanequalssigninerbtooutputtothescreen,Sinceweonly
wanttoprintoutthenameweonlyuseerbwithanequalssignintheparagraphtag.
Youcanaddan=signtothefirstlineoferbifyouwish,tryitandseewhathappens.Then
removeitwhenyouaredone.(Inorderforanythingtoshowupmakesureyouhaveadded
somenamestoyourdatabase).

Runtheserver:

Asimpleformapp
/workspace/form_app
$railsserverb$IPp$PORT

Tryaddingsomenames,Eachtimeyoudoyouwillberedirectedtotheindexpage.Ifyouadda
blanknamethenthatwillshowupasblank.Wewillcovervalidationsinthenextprojectsothat
youcanmakesureanameisacertainlengthbeforeitissavedtothedatabase.


Theindexpageshowsnamesthathavebeensubmittedaswellasblanknames.

Thatwasalot,nicelydone!Youcreatedaverysimpleformwithoneformfieldforpeopletoput
theirnamesandthensubmittheirnamestothedatabase.Youthencollectedallthosenames
andloopedthroughthemanddisplayedthemontheindexpage.NiceJob!

WELLDONE!

AStyledFormApp
Inthisprojectyouwillbuildaformforausertosubmitanemailandname.Youwilllearnhowto
addvalidationstothemodelfilesothatanameforexample,hastobeaminimumlengthbefore
beingsubmitted.Youwillalsolearnhowtoaddgemstothegemfileandinstallthem,aswellas
configuringthem.Thegemyouwilllearnaboutisbootstrap,andisusedforstylingyourapp.

Makesureyouareintheworkspacedirectory:

~/workspace$pwd
/home/ubuntu/workspace

Generateanewrailsappcalledstyled_form

Astyledform
/workspace
$rails_4.2.5_newstyled_form
create
createREADME.rdoc
createRakefile
createconfig.ru
create.gitignore
createGemfile
createapp
createapp/assets/javascripts/application.js
createapp/assets/stylesheets/application.css
createapp/controllers/application_controller.rb
createapp/helpers/application_helper.rb
createapp/views/layouts/application.html.erb
createapp/assets/images/.keep
createapp/mailers/.keep
...

Changedirectoryintothenewapp:

$cdstyled_form/
~/workspace/styled_form$

Runtheserver:
Checkallisfine.

Astyledform
/workspace/styled_form
$railsserverb$IPp$PORT

.
GenerateaUsermodel:

Astyledform
/workspace/styled_form
$railsgeneratemodelUser
RunningviaSpringpreloaderinprocess718
invokeactive_record
createdb/migrate/20160301193656_create_users.rb
createapp/models/user.rb
invoketest_unit
createtest/models/user_test.rb
createtest/fixtures/users.yml

Updatethemigrationfile:

Astyledform
/workspace/styled_form/db/migrate/20160301193656_create_users.rb
classCreateUsers<ActiveRecord::Migration
defchange
create_table:usersdo|t|
t.string:name
t.string:email
t.timestampsnull:false
end
end
end

Addanamecolumnandanemailcolumnandmakethe,bothoftypestring.

Migratethedatabase:

Astyledform
/workspace/styled_form
$rakedb:migrate
==20160301193656CreateUsers:migrating======================================
create_table(:users)
>0.0024s
==20160301193656CreateUsers:migrated(0.0026s)=============================

MigrateyourdatabaseandcreatetheUserstable.Youcanseetheresultinthe
db/schema.rb
file.

GenerateaUserscontroller

Astyledform
/workspace/styled_form
$railsgeneratecontrollerUsersindexnew
RunningviaSpringpreloaderinprocess789
createapp/controllers/users_controller.rb
routeget'users/new'
routeget'users/index'
invokeerb
createapp/views/users
createapp/views/users/index.html.erb
createapp/views/users/new.html.erb
invoketest_unit
createtest/controllers/users_controller_test.rb
invokehelper
createapp/helpers/users_helper.rb
invoketest_unit
invokeassets
invokecoffee
createapp/assets/javascripts/users.coffee
invokescss
createapp/assets/stylesheets/users.scss

Thegeneratecontrollercommandcreatesausers_controller.rbfilewiththeactionsindexand
new.Openthefileuptotakealook.IfyouarewonderingwhydidntIaddthecreateactionto
thelistitisbecauseacreate.html.erbviewfilewouldalsogetgeneratedandwewouldendup
deletingit.(Arailsactionbydefaultrendersaview).

Updatetheroutes:

Astyledform
/workspace/styled_form/config/routes.rb

Rails.application.routes.drawdo

resources:users
root'users#index'

...

Updatetheroutesinyourroutes.rbfile.Setuptherootrouteandaddtheresourcesline.
Rememberyoucanseetheroutesresourcesgeneratesbyusingtherakeroutescommand.

Runtheserver:

Astyledform
/workspace/styled_form
$railsserverb$IPp$PORT

Checkthelinksworkbyloadinguptheserverandthennavigateto/users/newaswell.

Updatetheusers_controllerfile:

Astyledform
/workspace/styled_form/app/controllers/users_controller.rb
classUsersController<ApplicationController
defindex
end

defnew

@user=User.new
end

defcreate
@user=User.create(user_params)
if@user.save
flash[:success]="YouSignedUpwoo!"
redirect_to'/'
else
flash[:danger]="Therewasanerrortryagain!"
render:new
end
end

private

defuser_params
params.require(:user).permit(:name,:email)
end
end

InthenewactionyoucreateanewuserbycallingthenewmethodonyourUserclass.You
thenstorethenewUserobjectinthe@userinstancevariable.
InthecreateactionyoucreateaUserwiththepermittedparamswhichareintheuser_params
privatemethod.Inthemethodyouallowonlythenameandemailparameters.
Iftheuserissavedthenyouredirecttotherootpageandiftherewasanerroryourenderthe
newactionagain.

Iftheuserwassavedthenwesetaflashhash,thisisallowsustoshowamessageinthenext
actionthatgetsrendered.Withtheflashhashwecanshowamessagetotheuserandletthem
knowiftheyweresuccessfulornot.

Thekeyornameoftheflashis:successandthevalueormessageisthestringYouSignedUp
WooThismessageiswhatwedisplaytotheuser.Thekeyornameofthehashiswhatweuse
forstyling/identifying.
IftheUserisnotsavedtothedatabasethenwerenderthenewactionandtryagain.However
wealsodisplayadifferentflashhashwithanewmessage.
Thehashhasakeyornameof:dangerandavalueormessageofTherewasanerrortry
again!Themessagewillgetdisplayedtotheuseriftherewasaproblem.

Ifyouarewonderingcanthekeyornameofthehashbeanything?Theanswerisyes,justlike
thevalueormessageyoucangiveitanynameyouwant,ThereasonIchose:successand
:dangerisbecausethesearetwostylesusedinbootstrap.

ShowTheFlashMessages:

Astyledform
/workspace/styled_form/app/views/layouts/application.html.erb
<!DOCTYPEhtml>
<html>
<head>
<title>StyledForm</title>
<%=stylesheet_link_tag'application',media:'all','dataturbolinkstrack'=>true%>
<%=javascript_include_tag'application','dataturbolinkstrack'=>true%>
<%=csrf_meta_tags%>
</head>
<body>

<%flash.eachdo|name,message|%>
<%=content_tag:div,message,class:"alertalert#{name}"%>
<%end%>

<%=yield%>

</body>
</html>

Weusesomeembeddedrubyinthelayoutfiletoiteratethrougheachflashmessage(ifthereis
morethanone)andshowitscontent.Wetargettheflashhashandcalltheeachmethodonitto
gothrougheachflashhash.
Inrubyahashhasakeyandavalue.Wesetthekeyandvaluebackinthecontrollerfile.The
keywas:successandthevaluewasastring.
Herethekeyisnameandthevalueismessage.Wehaveusedvariablestorepresentthekey
andvalueofthehash.Theycouldbecalledanything.Wecouldhavecalledthevariables|k,v|
forkeyandvalue,butitisnicertobeabitmoredescriptive.

Wethenoutput(noticetheerbwithanequalssign,theothererbislogiccodethatwedont
wanttooutput)adivtag,Railshasahelpermethodcalledcontent_tagwhichallowsusto
specifyahtmltagthatwecanthenaddcontentto.

Themessageinthedivthatgetsdisplayedisthevariablecalledmessage,Thismessage
variableissettothestringfromthecontrollerfile.Afterthecommayouseetheclass:word,This
istherailswayofaddingaclasstoahtmlelement.Aswearegeneratingthedivtagwiththe
helpermethodwecantaddtheclassinthenormalwaylikewithhtmlclass=classnameWe
usetherailssyntaxofclass:withacolonafterit.

Thedivgetsgivenaclassofalertandaclassofalertname,thenameisactuallythevariable
justlikemessageisalsoavariable.Thenamevariablewilleitherhaveavalueofsuccessor
dangerbecauseofhowwenamedourflashhashesinthecontroller.
Justafterthedashisapoundsignfollowedbytwocurlybraces,Thisisinterpolationand
convertsthenamevariableintoitsvalue,soeithersuccessordanger.
Theclassthenbecomesalertalertsuccessnotalertalertname.Ifwedidntusestring
interpolationtoconvertthevariablethentheclasswouldremainasalertnamewhichisnotwhat
wewant.
Youdonthavetodoitthisway,youcouldjusthaveastaticclassofnoticeifyoulike,however
thisisabitnicerforthepersonviewingthesite.

Updatethenew.html.erbfilewithaform:

Astyledform
/workspace/styled_form/app/views/users/new.html.erb
<%=form_for@userdo|f|%>
<%=f.text_field:name,:placeholder=>"Name"%>
<%=f.email_field:email,:placeholder=>"Email"%>
<%=f.submit"Submit"%>
<%end%>

Runtheserver:

Astyledform
/workspace/styled_form
$railsserverb$IPp$PORT

Ifyounavigateto/users/newyoushouldseeaform,Entersomedetailsandsubmitthem.You
willberedirectedtotheindexpage,Youwillalsoseetheflashmessageofsuccess.
Prettycool!

Validations

Astyledform
/workspace/styled_form/app/models/user.rb
classUser<ActiveRecord::Base
validates:name,presence:true
validates:email,presence:true
validates:name,length:{minimum:3}
validates:email,length:{minimum:5}
end

Addthefollowinglinestoyouruser.rbmodelfile.ThesearethevalidationsthatItalkedabout
earlier.Thevalidateshelpermethodtakesasymboloftheattributeyouarelookingtovalidate.
Theuserstablehastheattributesnameandemailsothesearewhatwetarget.

Herewevalidatethepresenceandsetittotruetomakesurethatsomethinghasbeentyped
intotheinputboxes.Wealsovalidatethelengthoftheattributesandsetthemaminimum
constraint.
Thenamemustbeatminimum3charactersandwemakesuretheemailisalsoaminimumof5
characters.Thesearesomesimplevalidations,wewillcoversomeotherslateron.

Ifyouentersomeinformationintotheinputfieldsnowandtheyareblankortooshort.thenyou
willgetaflasherrormessagethatyousetupinthecontrollerandapplication.html.erbfilesand
youwillberedirectedtothenew.html.erbpagetotryagain.

Runtheserver:

Astyledform
/workspace/styled_form
$railsserverb$IPp$PORT

AddTheBootstrapGem:

Astyledform
/workspace/styled_form/app/gemfile
source'https://rubygems.org'


#BundleedgeRailsinstead:gem'rails',github:'rails/rails'
gem'rails','4.2.5'
#Usesqlite3asthedatabaseforActiveRecord
gem'sqlite3'
#UseSCSSforstylesheets
gem'sassrails','~>5.0'
#UseUglifierascompressorforJavaScriptassets
gem'uglifier','>=1.3.0'
#UseCoffeeScriptfor.coffeeassetsandviews
gem'coffeerails','~>4.1.0'
#Seehttps://github.com/rails/execjs#readmeformoresupportedruntimes
#gem'therubyracer',platforms::ruby
gem'bootstrapsass','~>3.3.6'
...

Thegemfileisthelocationofallyourpreinstalledgems(prepackagedcode)Theyallowyouto
quicklyaddfeaturestoyourappwithouthavingtoreinventthewheelanddoeverythingfrom
scratch.Forexampleifyouneedtouploadattachmentsorimagesthereisagemforthatcalled
paperclip,allyoudoisinstallitandsetitupandoffyougo.Configurationofgemswillvaryfrom
gemtogemhoweveryoucanfindsimpletutorialsontheirassociatedgithubpages.

Ihaveexcludedsomeofthegemfileasitisquitelarge.Addthegembootstrapsassline.

BundleInstall

Astyledform
/workspace/styled_form
$bundleinstall
Fetchinggemmetadatafromhttps://rubygems.org/...........
Fetchingversionmetadatafromhttps://rubygems.org/...
Fetchingdependencymetadatafromhttps://rubygems.org/..
Resolvingdependencies...
...

Thebundleinstallcommandinstallsallthegemsinthegemfile(Ihaveshortenedtheoutput).
Sincethebootstrapgemwasaddedtothefilethebundleinstallcommandhastoberun.This
fetchesthegemsandanydependenciesandinstallsthemforyoutouseinyourapplication.
Afterthatyoujustneedtodosomeconfiguration.

RenameTheapplication.cssFileToapplication.scss

Astyledform
/workspace/styled_form/app/assets/stylesheets/application.css
$mvapp/assets/stylesheets/application.cssapp/assets/stylesheets/application.scss

HereIusethemovecommandtorenamethefileandchangetheextensionfrom
css
to
scss
Thatisallwearechanging.Youcanjustrightclickonthefileandclickrenameifyouprefer.

ImportBootstrapStyles:

Astyledform
/workspace/styled_form/app/assets/stylesheets/application.scss
/*
*Thisisamanifestfilethat'llbecompiledintoapplication.css,whichwillincludeall
thefiles
*listedbelow.
*
*AnyCSSandSCSSfilewithinthisdirectory,lib/assets/stylesheets,
vendor/assets/stylesheets,
*oranyplugin'svendor/assets/stylesheetsdirectorycanbereferencedhereusinga
relativepath.
*
*You'refreetoaddapplicationwidestylestothisfileandthey'llappearatthebottom
ofthe
*compiledfilesothestylesyouaddheretakeprecedenceoverstylesdefinedinany
styles
*definedintheotherCSS/SCSSfilesinthisdirectory.Itisgenerallybettertocreatea
new
*fileperstylescope.
*
*=require_tree.
*=require_self
*/

Yourfilewilllookliketheoneabove,Makethechangesshownbelow:

Astyledform
/workspace/styled_form/app/assets/stylesheets/application.scss
/*
*Thisisamanifestfilethat'llbecompiledintoapplication.css,whichwillincludeall
thefiles
*listedbelow.
*
*AnyCSSandSCSSfilewithinthisdirectory,lib/assets/stylesheets,
vendor/assets/stylesheets,
*oranyplugin'svendor/assets/stylesheetsdirectorycanbereferencedhereusinga
relativepath.
*
*You'refreetoaddapplicationwidestylestothisfileandthey'llappearatthebottom
ofthe
*compiledfilesothestylesyouaddheretakeprecedenceoverstylesdefinedinany
styles
*definedintheotherCSS/SCSSfilesinthisdirectory.Itisgenerallybettertocreatea
new
*fileperstylescope.
*

*/
@import"bootstrapsprockets";
@import"bootstrap";

Removetherequire_selfandrequire_treelinesandaddthe@importlinesbeneath.

RequireBootstrapJavascripts:

Astyledform
/workspace/styled_form/app/assets/javascripts/application.js
//Thisisamanifestfilethat'llbecompiledintoapplication.js,whichwillincludeall
thefiles
//listedbelow.
//
//AnyJavaScript/Coffeefilewithinthisdirectory,lib/assets/javascripts,
vendor/assets/javascripts,
//oranyplugin'svendor/assets/javascriptsdirectorycanbereferencedhereusinga
relativepath.
//
//It'snotadvisabletoaddcodedirectlyhere,butifyoudo,it'llappearatthebottom
ofthe
//compiledfile.
//
//ReadSprocketsREADME(https://github.com/rails/sprockets#sprocketsdirectives)for
details
//aboutsupporteddirectives.
//
//=requirejquery
//=requirejquery_ujs
//=requirebootstrapsprockets
//=requireturbolinks
//=require_tree.

Youonlyneedtoaddonelinetotheapplication.jsfile.Makesureyouadditbelowtheothertwo
jquerylines.

Runtheserver:

Astyledform
/workspace/styled_form
$railsserverb$IPp$PORT

Loaduptheserverandyoushouldseesomeslightlydifferentstylingsuchasasansseriffont.
Youwillalsoseethattheflashmessageshavebeenstyledwithbootstrap.Thatisbecausewe
namedtheclassalertsuccessandalertdangerwhicharebootstrapstyles.

Byaddingagemandinstallingitandthendoingasmallamountofconfigurationfortheappwe
getsomeprettynicestyles.

StyleTheIndexPage:

Updatetheindex.html.erbviewfileandaddalinktothenew.html.erbpage.

Astyledform
/workspace/styled_form/app/views/users/index.html.erb
<divclass="container">
<divclass="row">
<divclass="colmd6colmdoffset3textcenter">

<%=link_to'SIGNUP',new_user_path,class:'btnbtnsuccess'%>

</div>
</div>
</div>

Herewehavestyledtheindexpagewithbootstrapclasses.Bootstrapclassesaredesignedso
thatyoudontneedtowriteyourownutilityclassesetc.Ifyouneedtocentersometextthen
thereisabootstrapclassforthat.Theframeworkhelpstospeedupthestylingofyour
application.Ofcourseifyouwanttooverrideastylethenallyouneedtodoisaddyourown
classandthenaddtherulestothatcssclassinyourstylesheet.

Youwillseethefirsthtmltagisadivandithasaclassofcontainer,Thisisabootstrapclass
anditisrequiredifweareaddingarowclasslateron,Allrowsmustgoinacontainersothat
theyareformattedproperly.
Thenexthtmltagisanotherdivandhasaclassofrow,Therowisthewidthofthescreenand
canbebrokendowninto12columns.Thisistheamountbootstraphasspecified.Thisisknow
asagridsystemandyoucanreadmoreaboutitonthebootstrapwebsite.

Thenexthtmldivhasafewmorebootstrapclasses,theclasstextcenterisquiteself
explanatory,Ifyouremoveitandreloadyourpageyouwillseethetextisnolongercentered.
Ontheleftisaclassofcolmd6whichstandsforacolumnthatis6wideonamediumdevice.
Themdmeansmedium.Dontworrytoomuchaboutthemdpart,Itallowsyoutostyleyoursite
dependingonwhatdevicesyouthinkyoursitewillbeviewedon.Soifyouweretargeting
mobileusersthenyoumightusecolsm6smstandsforsmall.Checkoutthesebootstrap
grid
examples
.

RememberIsaidthegridismadeupof12columns.Thecurrentdivis6columnswidebutitwill
beontheleftsideofthepageunlessweoffsetitwithaclass.WhenisayoffsetImeanpush
over.Weaddtheclasscolmdoffset6noticethatthereisanextraword(offset)andthatitis
onlyoffsetby3.Thisisbecauseitadds3totheleftandright.So6wideplus3ontheleftand3
ontherightmeansa12columngrid.Tryadjustingtheclassesandremovingtheoffsetclassto
seewhathappens.

Ifyoulookattherailslink_tomethodyoucanseeweaddaclasstherailswaybecauseweare
generatingthislinkwithrails,Itisnotplainhtmlsowechangethesyntax.(
class:classname
)
Thelinkgetsgivenabootstrapclassofbtnwhichstandsforbuttonandthenanotherbootstrap
classofbtnsuccesswhichstylesthebuttonagreencolour.Trychangingtheclassto
btnprimaryandseewhathappens.

Soinveryfewlinesyouhavestyledalink/anchorintoabuttonandcentereditonthepage.If
youweretowritethosecssrulesyourselfitwouldhavetakensignificantlymorecode.

StyleTheNewPage:

Updatethenew.html.erbviewfileandstylewithbootstrapclasses.

Astyledform
/workspace/styled_form/app/views/users/new.html.erb
<divclass="container">
<divclass="row">
<divclass="colmd6colmdoffset3">

<%=form_for@userdo|f|%>

<divclass="formgroup">
<%=f.text_field:name,:placeholder=>"Name"
,class:'formcontrol'
%>

</div>

<divclass="formgroup">
<%=f.email_field:email,:placeholder=>"Email"
,class:'formcontrol'
%>

</div>

<%=f.submit"Submit"
,class:'btnbtnprimary'
%>
<%end%>

</div>
</div>
</div>

First3divsareaddedwithacontainerclass,arowclasswhichhastobeinsideacontainer
class,andadivwithcolumnclassesandoffsetclassessoastocentertheformonthepage.

Thenintheformtwodivsareadded,theyeachwraparoundaninputfield.Theyhavea
bootstrapclassofformgroup,Thisclassaddssomespacingandformattingsothattheinput
boxesarenotsquashedupnexttoeachother.Theneachinputfieldgetsgivenaclassof
formcontrol.Thisincreasesthewidthoftheinputfield,addssomestylingsuchaspaddingand
borderradiusandmakestheinputsdynamicsothattheyadjusttothesizeofthescreen.
Thesubmitbuttonalsogetsgivenaclassofbtnandbtnprimarytostyleitblue,

Excellentyouhavecreatedaformwithmodelvalidationsthatcheckwhetheranythingispresent
intheinputboxesandalsomakesurethattheinputisaminimumlength,Ifnotanicelystyled
errormessageisdisplayed.Youalsoinstalledthebootstrapgemandconfigureditforusein
yourapp.Youthenstyledthepageswiththebootstrapclasses.

WELLDONE!

Challenge:ABootstrapRailsApp

Inthischallengeyouwillcreateanewrailsappandinstallthetwitterbootstrapgem.Youwill
thenconfigurethegemsothatthebootstrapstylescanbeusedinyourapp.

Step1
CD
intoyour
workspace
directory

Step2
Generateanewrailsapp
calledbootstrap_app(Youdontneedtouseaspecificversion
number)

Step3
CD
intothenewrailsapp
(bootstrap_app)

Step4
Runtheserver
andcheckthatyougetthedefaultrailspage

Step5
Generatea
Pagescontroller
,indexactionandindex.html.erbviewfile

Step6
Openyour
routes.rb
fileandchangethegetindexroutetoa
rootroute
,(rememberthe#sign
syntax)

Step7
Runtheserver
andcheckyouaredirectedtothehomepage

Step8
Addthebootstrapgemtothegemfile
gem
'bootstrapsass'
,

'~>3.3.6'

Step9
Installthegemwiththecommand:
bundleinstall

Step10
Renameyour
application.css
filetohavea
.scss
extension.
app
/
assets
/
stylesheets
/
application
.
css
app
/
assets
/
stylesheets
/
application
.
scss

Step11
Inyourapplication.scssfileaddthe@importlinesatthebottomofthefile
@import

"bootstrapsprockets"
;
@import

"bootstrap";

Step12
Removetherequiretreelinesfromtheapplication.scssfile

*=
require_tree.

*=
require_self

Step13
Addtherequirebootstrapsprocketslinetoyourapplication.jsfile(additbelowthejquerylines)
//=requirebootstrapsprockets

Step14
Addalinktoyourindexpagethatjustlinkstotheroot_path,Stylethelinkintoabuttonwith
bootstrapclasses.(btnbtnprimary)

Welldoneinafewstepsyouhaveconfiguredanewrailsapptousetwitterbootstrap,The
actualconfigurationdoesnttakelongatallandthereareonlyafewstepsrequiredbeforeyou
areupandrunningandreadytousebootstrapclassesforstyling.

AnEmailMailchimpApp
Forthisrailsappyouwillcreateanemailformtosubmitanemailhowevertheappwillconnect
tothemailchimpapiandsubmittheemailtoalist.Youwillusethegibbongemtosimplifythe
processofconnectingtothemailchimpapi.

Tobuildthisappyouwillneedtosignupforamailchimpaccount.Goto
mailchimp.com
and
signupforafreeaccount.Youwillneedtwothingstobuildthisapp,amailchimp
apikey
so
thatyoucanconnecttothemailchimpservice,anda
listid
Whenyoucreateamemberslistit
willhaveanid,thisisusedtosubscribepeopletothatparticularlist.

Anapikeyisalineofcodethatgetspassedbetweencomputerprogramsandisusedtoidentify
theperson(computer)thatwantstousethewebsite.Wewanttousethemailchimpwebsiteso
weneedanapikeysothatwecanbeidentified.

Onceyouhavesignedupclickonthe
dropdownmenu
inthetoolbaratthetop,itwillbe
namedafteryourname/username.Clickthe
accountbutton
.

Youwillnowbeonyouraccountpagewhichwillshowanoverviewforyou.Youwillseeanother
toolbar/menubelow.Clickthe
extras
dropdownandthenselect
apikeys
.

Ontheapikeypageyouwillseeabuttoncalled
createakey
Clickitandanewapikeywillbe
created.Copyitdownasyouwilluseitinyourapp.

Nowinthemenuatthetopclickthe
lists
link,Youwillseeabutton
createlist
,clickthatbutton
andfilloutthedetailsonthenextpage.Onceyouaredoneatthebottomclickthe
save
button.

Clickthe
list
linkatthetopofthepageagain,Nexttoyournewlycreatedlistisa
stats
dropdownmenu,Clickthedropdownarrowandclickon
settings
,Atthebottomofthesettings
pageyouwillseea
uniquelistid
,copyitdownasthisistheidforthelistyoujustcreated.

AlsoifyoufoundthemailchimpwebsitealittlebitconfusingdontworryasIdotoo,yousoon
getusedtoitthough.

Whydidyouneedtogetanapikeyandalistidagain?Itissothatwhenuserssubscribeto
yourapp(hypotheticallyasthisisatestapp)Theemailwillgetsubscribedtothelistyoujust
created,Youcanthenemailusersandkeepthemupdated.

Mailchimpsetupdone!

Makesureyouareintheworkspacedirectory:

~/workspace$pwd
/home/ubuntu/workspace

Generateanewrailsappcalledemail_mailchimp

Anemail_mailchimpapp
/workspace
$rails_4.2.5_newemail_mailchimp
create
createREADME.rdoc
createRakefile
createconfig.ru
create.gitignore
createGemfile
createapp
createapp/assets/javascripts/application.js
createapp/assets/stylesheets/application.css
createapp/controllers/application_controller.rb
createapp/helpers/application_helper.rb
createapp/views/layouts/application.html.erb
createapp/assets/images/.keep
createapp/mailers/.keep
...

Changedirectoryintothenewapp:

$cdemail_mailchimp/
~/workspace/email_mailchimp$

Runtheserver:
Checkallisfine.

Anemail_mailchimpapp
/workspace/email_mailchimp
$railsserverb$IPp$PORT

GenerateaUsermodel

Anemail_mailchimpapp
/workspace/email_mailchimp
$railsgeneratemodelUseremail:string
RunningviaSpringpreloaderinprocess788
invokeactive_record
createdb/migrate/20160305100909_create_users.rb
createapp/models/user.rb
invoketest_unit

createtest/models/user_test.rb
createtest/fixtures/users.yml

Hereinthegeneratecommandemail:stringisaddedsothatthemigrationfileautomaticallyhas
theemailcolumninit.Openthemigrationfiletosee.

Migratethedatabase

Anemail_mailchimpapp
/workspace/email_mailchimp
$rakedb:migrate
==20160305100909CreateUsers:migrating======================================
create_table(:users)
>0.0019s
==20160305100909CreateUsers:migrated(0.0020s)=============================

Youcanviewthe/db/schema.rbfiletoseetheuserstablethatgotgenerated.Ithasacolumn
namedemailoftypestring.

GeneratetheUserscontrollerandactions

Anemail_mailchimpapp
/workspace/email_mailchimp
$railsgeneratecontrollerUsersindexnew
RunningviaSpringpreloaderinprocess819
createapp/controllers/users_controller.rb
routeget'users/new'
routeget'users/index'
invokeerb
...

Edittheroutes.rbfile

Anemail_mailchimpapp
/workspace/email_mailchimp/config/routes.rb
Rails.application.routes.drawdo
resources:users,only:[:index,:new,:create]
root'users#index'
...

Addtherootrouteandsetittotheindexpage.Ifyouremembertheresourceslineit
automaticallycreateslotsofroutesforourcontroller/actions.Inthiscasetheuserscontroller.
Thesearecalledrestfulroutesandtheyarecommonroutesthatareusedinwebapp
development.

Sevendifferentroutesgetcreatedandaremappedtocontrolleractions.
Theroutesareindex,new,create,show,edit,update,destroy.See
railsguides
formore
informationandcheckoutsection3.2foratableshowingyouthecombinations.Justlookingat
thetableofroutes,actionsandhttpverbsdoesntdoitjustice,orhelpyoulearn,Sotheroutes
willbecoveredmorelateron.

Notethe
only:[:index,:new,:create]
line,Thistellsrailsthatyouwanttocreatetherestful
routesbutonlytheonesnamedthere.Forexamplewedontneedthedestroyaction/routeso
dontgenerateit.Usetherakeroutescommandtoseethereducedamountofroutes.

Runtheserver:

Anemail_mailchimpapp
/workspace/email_mailchimp
$railsserverb$IPp$PORT

UpdatetheUserscontroller:

Anemail_mailchimpapp
/workspace/email_mailchimp/app/controllers/users_controller.rb
classUsersController<ApplicationController
defindex
end

defnew

@user=User.new
end

defcreate
@user=User.create(user_params)
if@user.save
flash[:success]="Thankyouforsigninguptothemailinglist!"
redirect_toroot_path
else
flash[:error]="Therewasanerror,tryagain"
render:new
end
end

private

defuser_params
params.require(:user).permit(:email)
end
end

Addthecreatemethodandprivateuser_paramsmethod.


Updatetheindexandnewpages:

Anemail_mailchimpapp
/workspace/email_mailchimp/app/views/users/index.html.erb
<%=link_to"SUBSCRIBE",new_user_path%>

Anemail_mailchimpapp
/workspace/email_mailchimp/app/views/users/new.html.erb
<%=form_for@userdo|f|%>
<%=f.email_field:email,:placeholder=>"Email"%>
<%=f.submit"SUBMIT"%>
<%end%>

Addalinkintheindexpageandaforminthenewpage.

Updateapplicationlayoutfiletoshowflashmessages:

Anemail_mailchimpapp
/workspace/email_mailchimp/app/views/layouts/application.html.erb
<!DOCTYPEhtml>
<html>
<head>
<title>EmailMailchimp</title>
<%=stylesheet_link_tag'application',media:'all','dataturbolinkstrack'=>true%>
<%=javascript_include_tag'application','dataturbolinkstrack'=>true%>
<%=csrf_meta_tags%>
</head>
<body>

<%flash.eachdo|name,message|%>
<%=content_tag:div,message,class:name%>
<%end%>

<%=yield%>

</body>
</html>

AddbasicvalidationstotheUsermodelfile:

Anemail_mailchimpapp
/workspace/email_mailchimp/app/models/user.rb
classUser<ActiveRecord::Base

validates:email,presence:true

validates:email,length:{minimum:5}
end

Runtheserver:

Anemail_mailchimpapp
/workspace/email_mailchimp
$railsserverb$IPp$PORT

Testthatyougetasuccessflashmessagewhenyousubscribeyouremail,andalsoanerror
flashmessageifyouremailistooshort.

Addthegibbongemtothegemfile:

Anemail_mailchimpapp
/workspace/email_mailchimp/gemfile
source'https://rubygems.org'

#BundleedgeRailsinstead:gem'rails',github:'rails/rails'
gem'rails','4.2.5'
#Usesqlite3asthedatabaseforActiveRecord
gem'sqlite3'
#UseSCSSforstylesheets
gem'sassrails','~>5.0'
#UseUglifierascompressorforJavaScriptassets
gem'uglifier','>=1.3.0'
#UseCoffeeScriptfor.coffeeassetsandviews
gem'coffeerails','~>4.1.0'
#Seehttps://github.com/rails/execjs#readmeformoresupportedruntimes
#gem'therubyracer',platforms::ruby

#UsejqueryastheJavaScriptlibrary
gem'jqueryrails'
#Turbolinksmakesfollowinglinksinyourwebapplicationfaster.Readmore:
https://github.com/rails/turbolinks
gem'turbolinks'
#BuildJSONAPIswithease.Readmore:https://github.com/rails/jbuilder
gem'jbuilder','~>2.0'
#bundleexecrakedoc:railsgeneratestheAPIunderdoc/api.
gem'sdoc','~>0.4.0',group::doc
gem'gibbon','~>2.2','>=2.2.1'
...

Runbundleinstall

Anemail_mailchimpapp
/workspace/email_mailchimp

$bundleinstall

Addyourmailchimpapikeyandlistidtoyoursecrets.ymlfile

Anemail_mailchimpapp
/workspace/email_mailchimp/config/secrets.yml
...

development:
secret_key_base:
bc65b2dfe8afd3dc0cbdbe1bbbee3811d0fa94088936711c356eb3dc9fc8548227eb3bc70527e56d6ca8b9e1c762
2e80ac6f117d6bdb31e79f23c8fc6222a8d3
mailchimp_api_key:hfuksolfjd83j38d39ik9skj989dk
list_id:h3g5ll89sf

test:
secret_key_base:
67ef21b8a50815bfa531a4fdcd4beae45634589b53f2aee3976abd6ddfe526c1193583e7e612773f419d6dce3171
fdeb176cb154735d40537fa6eedcf2e007f6

#Donotkeepproductionsecretsintherepository,
#insteadreadvaluesfromtheenvironment.
production:
secret_key_base:<%=ENV["SECRET_KEY_BASE"]%>

Inyoursecrets.ymlfileaddyourapikeyandlistid,useaspacebetweenthecolonandthe
key/code.Thosekeysabovearefaketheywontwork,youwillneedyourownbysigningup.
Alsothisisnotnormallyhowyouwouldaddsensitiveinformationtoyouapp,youwoulduse
environmentvariableswhichIwillcoverlater.Howeversincethisisonlyatestapprunningin
developmentmodeyoucanaddyourkeystothesecretsfileunderdevelopment.

Addasubscribemethodtosubscribetheemailtomailchimp:

Anemail_mailchimpapp
/workspace/email_mailchimp/app/models/user.rb
classUser<ActiveRecord::Base

validates:email,presence:true
validates:email,length:{minimum:5}

before_save:downcase_email
after_save:subscribe

defdowncase_email
self.email=email.downcase
end

defsubscribe
gibbon=Gibbon::Request.new(api_key:Rails.application.secrets.mailchimp_api_key)
list_id=Rails.application.secrets.list_id


begin
gibbon.lists(list_id).members.create(
body:{
email_address:self.email,
status:"subscribed"
})
rescueGibbon::MailChimpError=>e
puts"TryAgain:#{e.message}#{e.raw_body}"
end
end
end

Ifyoulookattheusermodelyouwillseeamethodcalleddowncase_email,thismethodcalls
theemailattributeforthecurrentuser(self)andconvertsthecharacterstolowercase.
Lookatthelinebefore_save:downcase_email
Thisisacallbackmethodthatrunsbeforethedataissavedtothedatabase.SoBeforewesave
theemailtothedatabaserunthedowncase_emailmethod.

Ifyoulookfurtherdownyouwillseethesubscribemethod.
Themethodstartswithalocalvariablecalledgibbonwhichcreatesanewgiboninstance
request.Itusestheapikeyinthesecrets.ymlfile.Theapikeygetspassedviatheline:
api_key
:

Rails
.
application
.
secrets
.
mailchimp_api_key
Youcanseewetargetthesecretsfileandthemailchimp_api_keyvariable.
Theninthelist_idvariablewealsostorethelistidfromthesecrets.ymlfilewiththeline:
list_id
=

Rails
.
application
.
secrets
.
list_id
Withthesetwopiecesofinformationyoucannowtargetaspecificlist(list_id)andsubscribean
emailtoit.

Nextisabeginrescueblockthatisusedtocatchanyerrorsandprintthemtotheconsole.In
thebeginsectionwehavethelinegibbon.lists(list_id).members.createwhichwilltargetthelist
withtheidstoredinthelist_idvariableandcreateanewmember,(subscribeanewemailtothe
list).

Thenyouhavethebodyofthecreatemethod,Thisiswhatgetspassedtotheapiandisadded
toyourmailchimplist.Inthebodyweaddtheemailaddresswithself.emailandweaddastatus
ofsubscribed.Thestatusisneededinordertoaddanemailaddresstoamailchimplist.

Belowthebodywehavearescuestatement,Ifthereisanerroritgetsstoredinthevariablee.
Theerrormessagethengetsputs(printedtotheconsolescreen)Thee.messageprintsthe
errormessageande.raw_bodygivesyougreaterinformationabouttheerror.

Runtheserverandsubscribesomeemails.Thenlogintoyourmailchimpaccountandyouwill
seethesubscribedemailswhenyouclickonthelist.Ifyoutypeinsomethingthatisobviouslya
fakeemailthenitmaynotwork.Checktheconsoletoseeiftherewasanerror.

WELLDONE!

Youcreatedanappthatsubscribesanemailtoamailchimplist.Youlearnedhowtouseanapi
toconnecttoanothersystem/service.Youlearnedalittlebitaboutstoringkeys/codeinthe
secrets.ymlfileandyoualsolearnedaboutcallbackmethodsthatcanberunatcertaintimes
duringtheappsprocessing(beforesavingtothedatabase,aftersavingtothedatabaseetc.).

Usingfigarotostoresensitiveinformation

Thisappwillbesimilartothelasthoweveritwillcovertheuseofthefigarogem.Thisgemis
usedforstoringsensitiveinformationinenvironmentvariables.Itisimportanttoknowthisas
whilstitisokaytoputapi_keysandcodeinyoursecrets.ymlfileitisnotideal.

Makesureyouareintheworkspacedirectory:

~/workspace$pwd
/home/ubuntu/workspace

Generateanewrailsappcalledemail_mailchimp

Anemailappwithfigaro
/workspace
$rails_4.2.5_newemail_with_figaro
create
createREADME.rdoc
...

Changedirectoryintothenewapp:

$cdemail_with_figaro/
~/workspace/email_with_figaro$

Runtheserver:
Checkallisfine.

Anemailappwithfigaro
/workspace/email_with_figaro
$railsserverb$IPp$PORT

GenerateaUsermodel

Anemailappwithfigaro
/workspace/email_with_figaro
$railsgeneratemodelUseremail:string
RunningviaSpringpreloaderinprocess788

Migratethedatabase

Anemailappwithfigaro
/workspace/email_with_figaro
$rakedb:migrate
==20160305100909CreateUsers:migrating======================================
create_table(:users)
>0.0019s
==20160305100909CreateUsers:migrated(0.0020s)=============================

GeneratetheUserscontrollerandactions

Anemailappwithfigaro
/workspace/email_with_figaro
$railsgeneratecontrollerUsersindexnew
RunningviaSpringpreloaderinprocess819
...

Edittheroutes.rbfile

Anemailappwithfigaro
/workspace/email_with_figaro/config/routes.rb
Rails.application.routes.drawdo
resources:users,only:[:index,:new,:create]
root'users#index'
...

Runtheserver:

Anemailappwithfigaro
/workspace/email_with_figaro
$railsserverb$IPp$PORT

UpdatetheUserscontroller:

Anemailappwithfigaro
/workspace/email_with_figaro/app/controllers/users_controller.rb
classUsersController<ApplicationController
defindex

end

defnew

@user=User.new
end

defcreate
@user=User.create(user_params)
if@user.save
flash[:success]="Thankyou!"
redirect_toroot_path
else
flash[:error]="Therewasanerror!"
render:new
end
end

private

defuser_params
params.require(:user).permit(:email)
end
end

Updatetheindexandnewpages:

Anemailappwithfigaro
/workspace/email_with_figaro/app/views/users/index.html.erb
<%=link_to"SUBSCRIBE",new_user_path%>

Anemailappwithfigaro
/workspace/email_with_figaro/app/views/users/new.html.erb
<%=form_for@userdo|f|%>
<%=f.email_field:email,:placeholder=>"Email"%>
<%=f.submit"SUBMIT"%>
<%end%>

Updateapplicationlayoutfiletoshowflashmessages:

Anemailappwithfigaro
/workspace/email_with_figaro/app/views/layouts/application.html.erb
<!DOCTYPEhtml>
<html>
<head>
<title>EmailWithFigaro</title>
<%=stylesheet_link_tag'application',media:'all','dataturbolinkstrack'=>true%>
<%=javascript_include_tag'application','dataturbolinkstrack'=>true%>
<%=csrf_meta_tags%>
</head>

<body>

<%flash.eachdo|name,message|%>
<%=content_tag:div,message,class:name%>
<%end%>

<%=yield%>

</body>
</html>

AddbasicvalidationstotheUsermodelfile:

Anemailappwithfigaro
/workspace/email_with_figaro/app/models/user.rb
classUser<ActiveRecord::Base

validates:email,presence:true
validates:email,length:{minimum:5}
end

Runtheserver:

Anemailappwithfigaro
/workspace/email_with_figaro
$railsserverb$IPp$PORT

Testthatyougetasuccessflashmessagewhenyousubscribeyouremail,andalsoanerror
flashmessageifyouremailistooshort.

Addthegibbongemtothegemfileandthefigarogem:

Anemailappwithfigaro
/workspace/email_with_figaro/gemfile
source'https://rubygems.org'

...

#Turbolinksmakesfollowinglinksinyourwebapplicationfaster.Readmore:
https://github.com/rails/turbolinks
gem'turbolinks'
#BuildJSONAPIswithease.Readmore:https://github.com/rails/jbuilder
gem'jbuilder','~>2.0'
#bundleexecrakedoc:railsgeneratestheAPIunderdoc/api.
gem'sdoc','~>0.4.0',group::doc
gem'gibbon','~>2.2','>=2.2.1'

gem
"figaro",~>1.1.1
...

Runbundleinstall

Anemailappwithfigaro
/workspace/email_with_figaro
$bundleinstall

Runbundleexecfigaroinstall

Anemailappwithfigaro
/workspace/email_with_figaro
$bundleexecfigaroinstall
createconfig/application.yml
append.gitignore

Asyoucanseethisfigarocommandcreatesafilecalledapplication.ymlintheconfigfolder.
Theappend.gitignoremeansthatifyouareusingversioncontrolsuchasgit,thenifyou
push/submityourworkpubliclythatfilewillbeignored.Thismeansyoucansafelyadd
informationsuchasyourapikeysasitwontbesubmittedanywhere(Ifyouareusingversion
control).

Addyourmailchimpapikeyandlistidtotheapplicationymlfile
(notabsjustspaces)

Anemailappwithfigaro
/workspace/email_with_figaro/config/application.yml
#Addconfigurationvalueshere,asshownbelow.
#
#pusher_app_id:"2954"
#pusher_key:7381a978f7dd7f9a1117
#pusher_secret:abdc3b896a0ffb85d373
#stripe_api_key:sk_test_2J0l093xOyW72XUYJHE4Dv2r
#stripe_publishable_key:pk_test_ro9jV5SNwGb1yYlQfzG17LHK
#
#production:
#stripe_api_key:sk_live_EeHnL644i6zo4Iyq4v1KdV9H
#stripe_publishable_key:pk_live_9lcthxpSIHbGwmdO941O1XVU
MAILCHIMP_API_KEY:hfuksolfjd83j38d39ik9skj989dk
LIST_ID:h3g5ll89sf

Wewilltargettheseenvironmentvariablesinoursecrets.ymlfile.

Targettheenvironmentvariablesinthesecrets.ymlfile:

Anemailappwithfigaro
/workspace/email_with_figaro/config/secrets.yml
...

#Makesurethesecretsinthisfilearekeptprivate
#ifyou'resharingyourcodepublicly.

development:
secret_key_base:
0e8108dc2f3b58b38c75734cadf6842b7472fc7ebd6191f5c37a1a30cefee176687d7d45a68666f9a3b7ec9c5093
86e9fca1bc58deca2faf35743f890791f2e1
mailchimp_api_key:<%=ENV["MAILCHIMP_API_KEY"]%>
list_id:<%=ENV["LIST_ID"]%>
test:
secret_key_base:
bc8b9479f36a56748cc7c8902e5f18b37cce19abbabceb4e019c288f6e60cea6847a847b1cc9d9d183131bbf34da
74a9bae0397ac8c010ae5f926b33ef2d5c31

#Donotkeepproductionsecretsintherepository,
#insteadreadvaluesfromtheenvironment.
production:
secret_key_base:<%=ENV["SECRET_KEY_BASE"]%>

Wearenowtargetingthethevariablesinourapplication.ymlfileusingtheENVenvironment
variableandthenameofthevariableintheapplication.ymlfile.Asyoucanseewedonthave
theapi_keyinthisfilesotheapplicationisnowsaferespeciallyifsubmittingthecodepublicly.

Addasubscribemethodtosubscribetheemailtomailchimp:

Anemailappwithfigaro
/workspace/email_with_figaro/app/models/user.rb
classUser<ActiveRecord::Base

validates:email,presence:true
validates:email,length:{minimum:5}

after_save:subscribe

defsubscribe
gibbon=Gibbon::Request.new(api_key:Rails.application.secrets.mailchimp_api_key)
list_id=Rails.application.secrets.list_id

begin

gibbon.lists(list_id).members.create(
body:{
email_address:self.email,
status:"subscribed"
})
rescueGibbon::MailChimpError=>e
puts"TryAgain:#{e.message}#{e.raw_body}"
end
end
end

Asyoucanseewiththegibbonlocalvariablewearestilltargetingthemailchimp_api_keyinthe
secrets.ymlfile,
gibbon
=

Gibbon
::
Request
.
new
(
api_key
:

Rails
.
application
.
secrets
.
mailchimp_api_key)
Butifyoulookinthatfileyouwillseeenvironmentvariablesarenowbeingusedtostorethe
information.

WELLDONE!
Coolyourecreatedtheappusingthefigarogemandenvironmentvariables.Youmaythinkthis
wasabitofapointlessappasnothingmuchwasnewhoweveritisimportanttoknowhowto
useandstoreinformationthatismoresensitive.Youdontwantotherpeopletoaccessyourapi
keysoranyotherinformation.Youcanknowbuildanappknowingyourinformationissafe.

Anexplanationonenvironmentvariables:

Environmentvariablesareusedtokeepsensitiveinformationsecure.
Let'ssayyouwereconnectingtotheGmailapi.Youcoulduseenvironmentvariablesforthe
usernameandpassword.
user_name
:
ENV
[
"GMAIL_USERNAME"
]
password
:
ENV
[
"GMAIL_PASS"]

ENVtellsrailstolookforanenvironmentvariablewiththenameGMAIL_USERNAMEor
GMAIL_PASSontheserverthattheappisrunningon.

Soinourearlierexamplewewererunningonthelocalserver,andinthesecrets.ymlfileyou
canseeweplacedthevariablesunderthedevelopmentlineofcode.(Wearebuildingtheapp).
IfweweregoingtousetheappinreallifethenwewouldaddENVvariablesbeneaththe
productionlineofcodeandpushourcodetoaliveserver.TheENVvariablesaredividedup
dependingontheenvironmentinwhichtheappisrunning.

TherearevariouswaystosetENVvariablesforuse,aymlfileisinmyopiniononeoftheeasier
approaches,especiallywhenagemlikefigarocanbeusedtohelpgeneratethefilesforyou
andaddthefiletothe.gitignorefileautomatically.Thegemdoestheheavyliftingandyoudont
needtoreinventthewheel.

Makesureyouareinyourpreviousappcdintoemail_with_figaro:

Anemailappwithfigaro
/workspace/email_with_figaro
$railsconsole
RunningviaSpringpreloaderinprocess1038
Loadingdevelopmentenvironment(Rails4.2.5)
2.3.0:001>
ENV['MAILCHIMP_API_KEY']
=>"hfuksolfjd83j38d39ik9skj989dk"

2.3.0:002>
2.3.0:002>
exit
~/workspace/email_with_figaro$

Therailsconsolecommandletsyouinteractwithyourappfromthecommandline.
Youcanuseittomakequickcheckswhendevelopingyourappetc.
Typetherailsconsolecommandtoopenuptheconsole.
ThentypetheENV[MAILCHIMP_API_KEY]ENVvariableintotheconsole.Thevariablewillbe
printedout.
Lookaboveandyouwillseethelinesaysloadingdevelopmentenvironment,Ifyouhaddifferent
ENVvariablesforproductionandaliveserverthentheywouldgetloadednotthedevelopment
ENVvariables.Howeversincetheconsoleisrunningindevelopmentmodethesearethe
variablesthatgetloaded.

APostsapp
Inthisappyouwillutilizealloftherestfulroutes/actionsindex,new,create,show,edit,update,
destroy,andbuildanappthatallowsyoutocreateanewpostwithatitleandbody.Youwill
thenbeabletoeditthepostandupdateitscontentsaswellasdeleteit.

Makesureyouareintheworkspacedirectory:

~/workspace$pwd
/home/ubuntu/workspace

Generateanewrailsappcalledposts

APostsapp
/workspace
$rails_4.2.5_newposts
create
createREADME.rdoc
...

Changedirectoryintothenewapp:

$cdposts/
~/workspace/posts$

Runtheserver:
Checkallisfine.

APostsapp
/workspace/posts
$railsserverb$IPp$PORT

GenerateaPostmodel

APostsapp
/workspace/posts

$railsgeneratemodelPosttitle:stringbody:text
RunningviaSpringpreloaderinprocess1147

Migratethedatabase

APostsapp
/workspace/posts
$rakedb:migrate
==20160306094443CreatePosts:migrating======================================
create_table(:posts)
>0.0012s
==20160306094443CreatePosts:migrated(0.0013s)=============================

checkoutyourschema.rbfiletoseethepoststablethatgotgenerated.

GeneratethePostscontrollerandactions

APostsapp
/workspace/posts
$railsgeneratecontrollerPostsindexneweditshow
RunningviaSpringpreloaderinprocess819
...

Thereisnothingnewhere,theoutputtotheconsoleislargeraswearecreatingmoreactions
andviewswiththegeneratecommand.Ifyoulookatwhatgotcreatedyouwillseeallthe
associatedviewfiles.

Edittheroutes.rbfile

APostsapp
/workspace/posts/config/routes.rb
Rails.application.routes.drawdo
resources:posts
root'posts#index'
...

Thistimewewillbewantingalltheresourcesforthepostscontroller.

Runtheserver:
Trygoingtothevariouspages/posts/new

APostsapp
/workspace/posts
$railsserverb$IPp$PORT

Updatethepostscontroller:

APostsapp
/workspace/posts/app/controllers/posts_controller.rb
classPostsController<ApplicationController
defindex

@posts=Post.all
end

defnew

@post=Post.new
end

defcreate
@post=Post.create(post_params)
if@post.save
flash[:success]="Youcreatedanewpost"
redirect_to@post
else
flash[:danger]="Therewasanerror."
render:new
end
end

defedit

@post=Post.find(params[:id])
end

defupdate
@post=Post.find(params[:id])
if@post.update(post_params)
flash[:success]="Postupdated."
redirect_to@post
else
flash[:danger]="Therewasanerrorwhenupdating."
render:edit
end
end

defshow

@post=Post.find(params[:id])
end

defdestroy
@post=Post.find(params[:id])
@post.destroy

redirect_toroot_path
end

private

defpost_params
params.require(:post).permit(:title,:body)
end
end

Therearequiteafewnewactionsgoingontherebutitisquitesimilartowhatyouhavebeen
doing.Takealookattheshowaction.Thecodeinthatactionusestheparamshashandlooks
foranid,itthendisplaysthepostwiththatid.

@post=Post.find(params[:id])

Theidispassedfromtheurl,eachnewpostthatgetscreatedinthetablewillhaveanid
attribute,youwontseethiscolumnonthetableintheschema.rbfilebutitisgenerated
automaticallyforeverytableanditisthere.Thefirstpostyoucreatewillhaveanidof1andthe
secondanidof2andsoon.Thatiswhythelineabovelooksfortheidparameterintheparams
hash(whichcomesfromtheurl)whichitthenusestodisplayaparticularpost.

Ifyoudothe
rakeroutes
commandyouwillseethisline
postGET
/
posts
/:
id
(.:
format
)
posts
#show
Youcanseethe/posts/:idURIpattern,Thisshowsusthatweneedauniqueidinorderforthis
routetowork.Remembertheidisanautomaticallygeneratedcolumninyourtable.

Thepostthatgetsfoundwiththefindmethodandidpassedtoitfromtheurl,iswhatgets
storedinthe@postinstancevariable.Thisinstancevariablewillbeusedinthepost.html.erb
viewlateron.

Asyoucanseebylookingatthevariousactionsweusefindtofindapostwithaparticularid
quiteoften.

Theupdateactionisverysimilartothecreateaction,ifyoulookweareupdatingwhich
automaticallysavestothedatabaseagain,andweareonlyupdatingwiththepost_params
privatemethod.Iftheupdatewasasuccessweredirecttothat@postthatjustgotcreated.
(Theshowaction)otherwisewerendertheeditactionagain.

WiththedestroyactionweagainlocateaPostbyid,wethencalldestroyonthatposttodelete
itandfinallyredirecttotheroot_path.

Updatetheindexpage:

APostsapp

/workspace/posts/app/views/posts/index.html.erb
<%@posts.eachdo|p|%>
<pclass="title"><%=p.title%></p>
<pclass="body"><%=p.body%></p>
<%=link_to"EditPost",edit_post_path(p)%>
<%=link_to"ShowPost",post_path(p)%>
<%end%>

Youcyclethrougheachpostthatisstoredinthe@postsinstancevariablebyusingtheeach
method.Youthendisplaytheinformationthatgetsoutputfromtheerbtags.
Lookatthelinksthatarebeinggenerated,runtherakeroutescommand,seetheeditandshow
routesrequireanid(URIpatterncolumn)Wepassthatidinthelink_tomethodbypassingthe
prefix(post_path)thelocalvariablewhichcontainstheidforthatparticularpost.Wecan'tuse
the@postsinstancevariablebecausethatcontainsalltheposts.

Showaparticularpostsinformationontheshowpage:

APostsapp
/workspace/posts/app/views/posts/show.html.erb
<pclass="title"><%=@post.title%></p>
<pclass="body"><%=@post.body%></p>

Usingthepostthatisstoredinthe@postinstancevariableyououtputitstitleandbody
attributesontheshowpage.

Updatethenew.html.erbfilewithaform

APostsapp
/workspace/posts/app/views/posts/new.html.erb
<%=form_for@postdo|f|%>
<%=f.text_field:title,:placeholder=>"Title"%>
<%=f.text_field:body,:placeholder=>"Body"%>
<%=f.submit"CreatePost"%>
<%end%>

Updatetheedit.html.erbfilewithaform

APostsapp
/workspace/posts/app/views/posts/new.html.erb
<%=form_for@postdo|f|%>
<%=f.text_field:title,:placeholder=>"Title"%>
<%=f.text_field:body,:placeholder=>"Body"%>
<%=f.submit"Update"%>
<%end%>


Thisformisexactlythesameastheoneonthenewpage,Ijustchangedthebuttonname.Also
ifyouwanttolearnhowtoreducetherepetitionofthecodewiththeseformsthenyoucan
renderapartial.Iwontcoveritherebutitallowsyoutorendercommoncodeandstoreitina
singlefile.NotacrossmultiplefileslikeIhavedonehere.

Updateapplicationlayoutfiletoshowflashmessagesandaddlinks:

APostsapp
/workspace/posts/app/views/layouts/application.html.erb
<!DOCTYPEhtml>
<html>
<head>
<title>Posts</title>
<%=stylesheet_link_tag'application',media:'all','dataturbolinkstrack'=>true%>
<%=javascript_include_tag'application','dataturbolinkstrack'=>true%>
<%=csrf_meta_tags%>
</head>
<body>
<%=link_to"Home",root_path%>
<%=link_to"CreatePosts",new_post_path%>

<%flash.eachdo|name,message|%>
<%=content_tag:div,message,class:"alertalert#{name}"%>
<%end%>

<%=yield%>

</body>
</html>

AddbasicvalidationstothePostmodelfile:

APostsapp
/workspace/posts/app/models/post.rb
classPost<ActiveRecord::Base
validates:title,presence:true,length:{minimum:3}
validates:body,presence:true,length:{minimum:5}
end

Runtheserver:
Andcheckflashmessagesdisplaycorrectly,addapostandthenupdateit,try
updatinginformationthatisbelowtheminimumlength.

APostsapp
/workspace/posts

$railsserverb$IPp$PORT

Youshouldnowbeabletoaddapostandedititandupdateit.Youshouldalsobeabletoview
anindividualpost.

Addthedestroylinktotheshowpage:

Addalinkontheshowpagesothatwhenyouclicktoviewapostyoucanthendeletethatpost
ifyouwish.

APostsapp
/workspace/posts/app/views/posts/show.html.erb
<pclass="title"><%=@post.title%></p>
<pclass="body"><%=@post.body%></p>
<p><%=link_to'Delete',post_path(@post),method::delete,data:{confirm:"Doyoureally
wanttodeletethispost?"}%></p>

Hereweaddalink_tomethodwiththetextDelete.Ifyourakeroutesyouwillseetheprefixfor
thedestroyactionispost,_pathgetsappendedtothisandwepasstheIDofthepostwewant
todeleteinparenthesis.The@postinstancevariablecontainsthepostasitwasfoundusing
theparamshash.
The:deletemethodusedisthenexplicitlystatedasanoptionthatweaddtothelink_tomethod.
Thedataoptionisalsoadded,thisprovidesapopupconfirmationboxbeforetheactionis
carriedthrough.Ifyoucancelthenthepostisnotdeleted.
Inyourjavascriptfileyouhavethelinejquery_ujsautomaticallyincludedwhentheappwas
made.Thisisthejavascriptthatisusedtoshowthedialogbox.

Addbootstrapstylestotheapp:

APostsapp
/workspace/posts/app/gemfile
gem
'bootstrapsass'
,

'~>3.3.6'
...

Addthebootstrapgemtoyourgemfile.

Bundleinstall:

APostsapp
/workspace/posts/
$bundleinstall

Renamethestylesheetwitha.scssextension:

APostsapp
/workspace/posts/

$mvapp/assets/stylesheets/application.cssapp/assets/stylesheets/application.scss

Updatethestylesheet:

APostsapp
/workspace/posts/assets/stylesheets/application.scss
...

*
fileperstylescope.
*

*/
@import

"bootstrapsprockets";
@import

"bootstrap";
@import"posts";//importtheposts.scssstylesheet

Removetherequiretreelinesandaddtheimportlines.

Updatethejavascriptfile:

APostsapp
/workspace/posts/assets/javascripts/application.js
//
//=requirejquery
//=requirejquery_ujs
//=requirebootstrapsprockets
//=requireturbolinks
//=require_tree.

Addthebootstrapsprocketslinetotheapplication.jsfile.

Starttheserverupandyourpageshouldbestyledwithsomebootstrapstyles:

Updateapplicationlayoutfilewithbootstrapstyles:

APostsapp
/workspace/posts/app/views/layouts/application.html.erb
<body>

<divclass="container">
<%=link_to"Home",root_path
,class:"btnbtnprimary"
%>
<%=link_to"CreatePost",new_post_path
,class:"btnbtnsuccess"
%>

<%flash.eachdo|name,message|%>
<%=content_tag:div,message,class:"alertalert#{name}"%>
<%end%>

<%=yield%>
</div>

</body>

Updatetheposts.scssfilewithcssrules:

APostsapp
/workspace/posts/app/assets/stylesheets/posts.scss
.title{

fontweight:bold;
margin:.75em0;
fontsize:1.8em;
}

.body{
background:#eee;
padding:.5em;
}

Addsomestylestothetitleandbodyrules.

Updatetheeditandnewpageswithbootstrapstyles:

APostsapp
/workspace/posts/app/views/posts/new.html.erb
<divclass="row">
<divclass="colmd6colmdoffset3">
<divclass="well">

<pclass="textcenterlead">NewPost</p>

<%=form_for@postdo|f|%>

<divclass="formgroup">
<%=f.text_field:title,:placeholder=>"Title"
,class:"formcontrol"
%>

</div>

<divclass="formgroup">
<%=f.text_field:body,:placeholder=>"Body"
,class:"formcontrol"
%>

</div>

<%=f.submit"CreatePost"
,class:"btnbtnprimary"
%>

<%end%>

</div>
</div>
</div>

APostsapp
/workspace/posts/app/views/posts/edit.html.erb
<divclass="row">
<divclass="colmd6colmdoffset3">
<divclass="well">

<pclass="textcenterlead">NewPost</p>

<%=form_for@postdo|f|%>

<divclass="formgroup">

<%=f.text_field:title,:placeholder=>"Title"
,class:"formcontrol"
%>

</div>

<divclass="formgroup">
<%=f.text_field:body,:placeholder=>"Body"
,class:"formcontrol"
%>

</div>

<%=f.submit"UpdatePost"
,class:"btnbtnprimary"
%>

<%end%>

</div>
</div>
</div>

Ifyourunyourserverandgototheneworeditpageyouwillseeanicelystyledform:

Thefinalappshouldlooksomethinglikethis:

Youshouldbeabletoaddapost,show/viewit,updateitanddeleteitifneeded.

WELLDONE!
Youcreatedanappthatyoucanaddaposttoandviewit.Youcaneditandupdatethepost
andevendeleteit.Therewasquitealottothisappincludinginstallingandconfiguring
bootstrap.Hopefullyyoucanseehowthisappcouldbeturnedintoablogwithalittlebitmore
elbowgrease.


FINALTHOUGHTS
Youhavecomealongwayfromnowknowinganyrubyonrails,youhavebuiltmultipleapps
andlearnedthebasicsofcreatingyourownapps.Youcangenerateanewapp,addcontrollers
modelsandviewstoyourapplicationandeveninstallandconfiguregems.Youalsolearneda
littleaboutENVvariablesandkeepingsensitivedatasecureandalsoaboutinteractingwiththe
mailchimpapi.NicelyDone.

Ifyouenjoyedthebookthencouldyoupleaseleaveareviewonamazonitwouldbegreatly
appreciated.

IfyoufindanyerrorsinthetutorialsjustdropmeanemailandIwillcorrectthem:
allforcoding@gmail.com

ThereisplentythatIhaventcoveredinthisbooksuchasrelationshipsbetweenmodels,
renderingpartials,basicauthenticationandmuchmore.AtthebareminimumIhopeyou
enjoyedthebookandfoundituseful,

KindRegards
Harry

Anda mungkin juga menyukai