perjantai 26. joulukuuta 2014

Päivämäärällä pallottelua

Halusin saada mukaan tavoitteisiin aikarajan. Minulla olikin tietokannassa jo sarake targetdate, mutta en ollut käyttänyt sitä vielä mihinkään.

Sain tavoitteen luontiin mukaan aikarajan kyselyn näin:

<%= f.date_select :targetdate, include_blank: true, use_two_digit_numbers: true, start_year: Date.today.year, end_year: Date.today.year + 10, order: [:day, :month, :year] %>

Eräässä ohjeessa luki että ennen attribuuttia (targetdate) olisi pitänyt olla se objekti (goal) mutta niin se ei toiminut.

Tämä apuri osaa tehdä kolme select-valintalaatikkoa, päivälle, kuukaudelle ja vuodelle omansa, ja yhdistää ne itse kokonaiseksi päivämääräksi. Lisämääreitä on paljon, valitsin mahdollisuuden jättää ruudut tyhjäksi, numerot kuunnimien sijasta, näytettävien vuosien määrityksen sekä missä järjestyksessä valikot sivulla ovat.

Kirjoitin Goal-modeliin pari metodia, mutta ne eivät toimineet tai jopa aiheuttivat internal server erroria. Debuggasin ja googletin monta tuntia ja olin aivan tuskastunut kun en keksinyt syytä. Loppujen lopuksi ongelmien juuri oli siinä, että Goal-modelin tiedostomuoto oli väärä! Yritin palauttaa metodista stringiä jossa oli skandi, ja siinä kohdassa se räjähti. Kun muunsin tiedoston UTF-8:ksi, kaikki alkoi toimia.

    def relevant_deadline
        if (self.targetdate == nil)
            return "Ei määräaikaa"
        elsif (self.targetdate.year - Date.today.year > 2)
            return "Yli 2 v. päästä"
        else
            return self.targetdate.strftime('%d.%m.%Y')
        end
    end


Viimeisessä palautuksessa on käytetty päivämäärän formatointia. Se toimi ohjetta soveltaen heittämällä. Mukavaa että joskus niinkin!

Seuraavaksi minua kiinnostaisi ottaa selville vaikkapa miten tavoitteet voisi järjestää targetdaten mukaan.

maanantai 22. joulukuuta 2014

Sliderin arvo tallentuu muun formin mukana!

Nyt on juhlapäivä! Löysin kuin löysinkin ratkaisun siihen miten javascript sliderin arvo saadaan lähetettyä muun formin mukana ja tallennettua tietokantaan.

Edelliseen postaukseen lisää tuli tämä:

goals.js

function setSliderColor() {
...
    $( "#slaideriteksti" ).text( progress );
    $( "#edistys").val(progress);


.erb

<div id="slaideri"></div>
<%= f.hidden_field :progress, :id => "edistys" %>
(<span id="slaideriteksti"></span>)



:) :) :) \o/

Javascript Slider input näkyviin muokkaussivulle

Halusin muuttaa tavoitteenmuokkaussivua niin, että tavoitteen täyttymisasteen saisi valita sliderilla sen sijaan, että kirjoittaisi numeron.

Railsissa on oma liukuri-input range_field. Sainkin sen toimimaan formissa muuten hienosti, mutta ui:lla ei näkynyt mikä luku oli valittuna, vain tuo liukuri. Minua valistettiin, etten saa valittua lukua muuten näkyviin kuin laittamalla mukaan javascriptiä. Rails-sivuhan luodaan kerran ja se on sitten siinä, mutta javascriptillä saisi sivua muutettua lennossa esimerkiksi päivittämällä sivulle sen valitun luvun sen mukaan, miten liukuria liu'uttaa.

Javascript-liukurin saaminen sivulle arvonäyttöineen ei ollutkaan ihan yksinkertainen tehtävä. Allaolevilla keinoilla se kuitenkin onnistui. Mukana on myös liukurin värin vaihtaminen sen mukaan, mitä arvoa se näyttää.

En ole vielä löytänyt neuvoa siihen, miten saan liukurin arvon lähetettyä formin mukana controlleriin. Eli tässä on vasta puolet ratkaisusta.

.erb

<%= content_tag :div, class: "progress_information", data: {progress: @goal.progress} do %>
<% end %>


...

<div id="slaideri"></div>
(<span id="slaideriteksti"></span>)


goals.js

function setSliderColor() {
    var progress = $( "#slaideri" ).slider( "value" );
    if (progress >= 0 && progress < 17) {
        $( "#slaideri .ui-slider-range" ).css( "background", "#FF0000" );
        $( "#slaideri" ).css( "background", "#FF0000" );
    } else if (progress >= 10 && progress < 33) {
        $( "#slaideri .ui-slider-range" ).css( "background", "#cc3300" );
        $( "#slaideri" ).css( "background", "#cc3300" );
    } else if (progress >= 20 && progress < 50) {
        $( "#slaideri" ).css( "background", "#996600" );
        $( "#slaideri .ui-slider-range" ).css( "background", "#996600" );
    } else if (progress >= 30 && progress < 66) {
        $( "#slaideri" ).css( "background", "#669900" );
        $( "#slaideri .ui-slider-range" ).css( "background", "#669900" );
    } else if (progress >= 40 && progress < 83) {
        $( "#slaideri" ).css( "background", "#33cc00" );
        $( "#slaideri .ui-slider-range" ).css( "background", "#33cc00" );
    } else if (progress >= 50 && progress <= 100) {
        $( "#slaideri" ).css( "background", "#00FF00" );
        $( "#slaideri .ui-slider-range" ).css( "background", "#00FF00" );
    }

    $( "#slaideriteksti" ).text( progress );
   
}

function initializeSlider() {
    $( "#slaideriteksti" ).text( $( "#slaideri" ).slider( "value" ) );
    setSliderColor();
}

$(function () {
    $("#slaideri").slider({
        range: "min",
        value: $('.progress_information').data('progress'),  //edit-sivun content-tag div antaa tiedon
        min: 0,
        max: 100,
        step: 1,
        create: initializeSlider,
        slide: setSliderColor,
        change: setSliderColor
    });
});


application.js

//= require goals

application.css

 *= require_self
 *= require_tree .
 *= require main
 *= require jquery-ui
*/



torstai 11. joulukuuta 2014

Mallin lihotus

Opin juuri, että mahdollisimman paljon ei-kyselyistä-riippuvaa logiikkaa kannattaa painaa model-tasolle asti.

Halusin näyttää viewssä projektin kohdalla kuinka paljon yhteensä tavoitteista oli toteutettu. Minun piti siis jotenkin laskea yhteen jokaisen tavoitteen edistyminen-luku ja näyttää summa jaettuna suurimmalla mahdollisella edistyminen-luvulla.

Onnistuin tekemään sen Project modelissa eli \app\models\project.rb tiedostossa.

    def nr_of_completed_goals
        return self.goals.all.where('progress' => '100').length
    end
   
    def nr_of_uncompleted_goals
        return self.goals.all.where('progress' => !'100').length
    end
   
    def total_completion_of_goals
        @goals = self.goals.all
        max_progress = @goals.length * 100.0
        progress_total = 0.0
        @goals.each do |g|
            progress_total = progress_total + g.progress
        end
        return (progress_total / max_progress).round(2)
    end


Näitä voi käyttää viewssä:

    <td><%= project.nr_of_uncompleted_goals %> + <%= project.nr_of_completed_goals %>, total <%= project.total_completion_of_goals %></td>

En tiedä olisiko "kauniimpaa" lyhentää nuo jotenkin tuossa view:ssä käytettäessä vai onko ok laittaa noin. Toiminnallisuus on kuitenkin oikea.

keskiviikko 10. joulukuuta 2014

Tyylitiedosto ja tyylitön tiedosto

Päätin kokeilla miten tyylitiedostot toimivan Railsin kanssa. Se olikin hyvin yksinkertaista. CSS-tiedostot laitetaan \app\assets\stylesheets hakemistoon. Tein yhden main.css-tyylitiedoston, joka piti lisätä myös samassa hakemistossa olevaan application.css -tiedostoon rivillä

 *= require main

Sitten tyylitiedosto toimi kaikilla sivuillani.

Paitsi... ei parilla sivulla! Itse asiassa kaikki <HTML> tagit ja vastaavat alkuhärpäkkeet puuttuivat näiltä sivuilta.

Kuumeisen googlettamisen jälkeen löysin mistä kenkä puristi. Olin lisännyt toimimattoman sivun controlleriin initialize-metodin asettaakseni siinä default-arvon, kuten olin jossain ohjeessa nähnyt. No, näinhän ei missään tapauksessa olisi saanut tehdä. Initialize kuulemma korvasi ylemmän tason vastaavan metodin ja samalla menivät layoutit pesuveden mukana.

Laitoin nyt alkuarvon new-metodiin ja se näyttää toimivan.

torstai 4. joulukuuta 2014

Juhlistaminen

Halusin että tavoitteen täytyttyä eli kun progress = 100, edistyspistemäärä korvautuu linkillä juhlistussivulle. 

Loin käsin uuden actionin goals controlleriin, sen nimi on goal_completed.

Linkin luominen tällaiselle goal_completed-sivulle ei mennyt ihan heittämällä, mutta saatuani hieman apua oikea yhdistelmä löytyi.

routes.rb
  get 'goal_completed/:id', to: 'goals#goal_completed', as: :goal_completed

goals_controller.rb
    def goal_completed
        @goal = Goal.find(params[:id])
        @celebration = @goal.celebration
    end


_showgoals.html.erb
    <% if goal.progress == 100 %>
    <%=   link_to 'Juhlitaan!', :goal_completed, id: goal.id %>
    <% else %>
    <%= goal.progress %>/100</td>
    <% end %>

Tavoite täyttynyt

Halusin lisätä tavoitteen muokkaukseen napin tms, josta voi suoraan merkata tavoitteen täyttyneeksi ilman että pitää muokata täyttymysastetta erikseen.

Sainkin sen tehtyä, mutta pientä venkslausta tarvitsin, ja haluaisin ymmärtää asian paremmin.

   <p>
     <%= f.label "Tavoite 100% valmis" %>
     <%= f.check_box :progress, {}, "100", @goal.progress %>
   </p>
  
   <p>
    <%= f.label :progress,'Valmiina %' %><br>
    <%= f.text_area :progress %>
  </p>


Nyt jos laitan täpän check-boxiin, progress-muuttuja laitetaan 100:ksi. Muuten siihen menee arvo, joka alempana määrätään.

Mutta jos käännän nämä inputit toisin päin, jatkoon pääsee @goal.progress eli arvo joka sillä oli ennen editoimista. Eli arvo ei päivity. En saanut sitä vielä toimimaan, mutta olkoon näin kunnes bongaan ratkaisun jostain.

Muokkaus: Tämä ei ihan toiminutkaan, vaikka näytti ensin toimivan. En saanut arvoa muutettua satasesta muuksi. Se johtuu piilotetusta check-box kentästä, joka on kiertotie unchecked-arvon välittämiseksi palvelimelle. Nyt tuossa piilotetussa kentässä meni aina 100.

Näin homma näyttää toimivan ees sun taas oikein:

   <p>
    <%= f.label :progress,'Valmiina %' %><br>
    <%= f.text_area :progress %>
  </p>

   <p>
     <%= f.label "Tavoite 100% valmis" %>
     <%= f.check_box :progress, {}, "100", false %>
   </p>

keskiviikko 3. joulukuuta 2014

Sain näkyviin oman kuvatiedoston

Haluan lisätä appikseeni kuvitusta. Aion saada sen jossain vaiheessa liikkumaan jollakin interaktiivisella tavalla, mutta tässä vaiheessa olen iloinen jo siitä, että sain yhden staattisen kuvan näkymään.

Näin se käy:

Laitoin kissankuvatiedoston app/assets/images -kansioon.

Sivulle, jossa halusin kissan näkyvän, lisäsin rivin

<%= image_tag("kissa.png") %>

Ta-daa, siellä on!

perjantai 14. marraskuuta 2014

Päiväys tuli valmiiksi

Halusin lisätä tehtävälistaukseen päivän, jolloin tehtävä on saatu valmiiksi.

Tietokantaan tehtävänluontipäivämäärä on tallentunut automaattisesti luotuun created_at -kenttään.

Jos sen sisältämää tietoa käyttää suoraan, saa tämän tapaisen pätkän:

task.created_at -> 2014-10-13 19:31:57 UTC

Tästä "raaka-ajasta" voi poimia ja muotoilla strftime:lla haluamiaan osia tämän ohjeen mukaan

task.created_at.strftime("%d.%m.%y") -> 13.10.14

Nyt näyttää jo aika hyvältä!



torstai 30. lokakuuta 2014

Edistyminen haittaa edistymistä

Yritän saada mukaan jonkinlaista mittaria edistymiselle ja tavoitetta kohti etenemiselle. Mittari olkoon numero, ajatellaan sitä vaikka prosenttina. Kun tavoite luodaan, numeron pitäisi alkaa automaattisesti nollasta ja käyttäjä saisi päivittää sitä.

Ensimmäinen haasteeni oli saada tavoitteenluontilomakkeeseen piilokenttä välittämään nolla controllerille. Lisäsin lomakkeeseen seuraavan rivin:

<%= hidden_field_tag 'progress', 0 %>

Näin sain aikaan html-koodin

<input id="progress" name="progress" type="hidden" value="0" />

kuten pitikin. Sitten tulikin tenkkapoo. Lomakkeeni kyllä lähetti hienosti progress-muuttujan, mutta controller ei tallentanut sitä tietokantaan.

Started POST "/projects/5/goals" for 127.0.0.1 at 2014-10-30 12:56:05 +0200
Processing by GoalsController#create as HTML
  Parameters: {"utf8"=>"V", "authenticity_token"=>"JFtUcbAFJiAs8y08trBS/y/KqmrlIOsfrkppFAqwabE=", "goal"=>{"title"=>"Tavoite1", "description"=>"Kuvaus1", "celebration"=>"Juhlistus1"}, "progress"=>"0",
 "commit"=>"Luo tavoite", "project_id"=>"5"}
DEBUG params inspect {"utf8"=>"V", "authenticity_token"=>"JFtUcbAFJiAs8y08trBS/y/KqmrlIOsfrkppFAqwabE=", "goal"=>{"title"=>"Tavoite1", "description"=>"Kuvaus1", "celebration"=>"Juhlistus1"}, "progress"=>"0", "commit"=>"Luo tavoite", "action"=>"create", "controller"=>"goals", "project_id"=>"5"}
  ←[1m←[36mProject Load (0.0ms)←[0m  ←[1mSELECT  "projects".* FROM "projects"  WHERE "projects"."id" = ? LIMIT 1←[0m  [["id", 5]]
  ←[1m←[35m (0.0ms)←[0m  begin transaction
  ←[1m←[36mSQL (1.0ms)←[0m  ←[1mINSERT INTO "goals" ("celebration", "created_at", "description", "project_id", "title", "updated_at") VALUES (?, ?, ?, ?, ?, ?)←[0m  [["celebration", "Juhlistus1"], ["created_at", "2014-10-30 10:56:05.533493"], ["description", "Kuvaus1"], ["project_id", 5], ["title", "Tavoite1"], ["updated_at", "2014-10-30 10:56:05.533493"]]
  ←[1m←[35m (108.8ms)←[0m  commit transaction
  ←[1m←[36m (0.0ms)←[0m  ←[1mbegin transaction←[0m
  ←[1m←[35m (0.0ms)←[0m  commit transaction
  ←[1m←[36mProject Load (1.0ms)←[0m  ←[1mSELECT  "projects".* FROM "projects"  WHERE "projects"."id" = ? LIMIT 1←[0m  [["id", 5]]
Redirected to http://localhost:3000/projects/5
Completed 302 Found in 118ms (ActiveRecord: 110.8ms)


Tarkistin sen vielä konsolin kautta hakemalla kaikki tavoitteet tietokannasta.

irb(main):002:0> Goal.all
<snip>
 #<Goal id: 13, title: "Tavoite1", description: "Kuvaus1", project_id: 5, created_at: "2014-10-30 10:56:05", updated_at: "2014-10-30 10:56:05", celebration: "Juhlistus1", progress: nil>]>

Ensin virhe oli ollut siinä, että en ollut sallinut progress-muuttujan tallentamista controllerin turvaosuudessa:

    private
        def goal_params
            params.require(:goal).permit(:title, :description, :celebration, :progress)
        end


Mutta syytä oli vielä jossain muuallakin. Mikä kummempaa, edistysnumeron päivitys onnistui olemassaolevaan tavoitteeseen mutta ei sen asettaminen nollaksi tavoitetta luodessa.

Googlailun jälkeen näytti siltä että en voi käyttää hidden_field_tagia, koska se ei ole jotenkin yhteydessä modeliin eli tietokantaan. Siitä seurasikin seuraava tenkkapoo. Mikä on hidden_fieldin oikea formaatti? Katsokaapa nimittäin tätä keskustelua: http://stackoverflow.com/questions/6636875/rails-hidden-field-undefined-method-merge-error

<%= f.hidden_field :service, "test" %>

<%= f.hidden_field :service, :value => "test" %>

<%= f.hidden_field :service %>

<%= f.hidden_field :service, value: "test" %>

Mitä näistä kuuluu käyttää? Dokumentaatiosta ei ole kovasti apua:

Examples

hidden_field(:signup, :pass_confirm)


<input type="hidden" id="signup_pass_confirm" name="signup[pass_confirm]" value="#{@signup.pass_confirm}" />

Mikä ihme tuo härpäke tuossa value-kohdassa on? Jos haluan vain arvoksi vaikka 0, miten saan sen siihen?

Ei auta kuin kokeilla.

<%= f.hidden_field :progress, '0' %>

undefined method `merge' for "0":String

<%= f.hidden_field :progress, :value =>'0' %>

<input id="goal_progress" name="goal[progress]" type="hidden" value="0" />

Jes! Nyt näyttää hyvältä!

keskiviikko 15. lokakuuta 2014

Sekavat näkymät. Errorista eteenpäin

Mainitsin tuossa aiemmin jo controllerit ja modelit, niin kirjoitanpa vielä lisää niistä vieweistä. Näkymän tarkoitus on tosiaan vain tuoda data controllerista ihmisen ihasteltavaksi. Kuten get started -oppaassakin tehtiin, loin itsekin näkymiä sitä mukaa kun selaimelle tuli virhe puuttuvasta näkymästä. Se olikin lempivirheeni, koska tiesin heti mitä sille piti tehdä.

Controllerissa pitää olla kullekin käytetylle toiminnalle oma def-end, esim.

    def show
        @temptask = Temptask.find(params[:id])
        @projects = Project.all
    end    


Sitten niillä pitää olla oma näkymänsä, eli app\views-hakemistossa kaikille controllereille on omat hakemistot ja niiden sisällä esimerkiksi \app\views\temptasks\show.html.erb

Näkymät kirjoitetaan template-kielellä, jossa html-koodin sekaan voi laittaa Railsin tulkkaamia pätkiä.

Esimerkiksi näin

<H1>Olet saanut aikaan tämän!</H1>

<p><%= @temptask.text %> (temptask id <%= @temptask.id %>)</p>


Tuossa sivun H1-otsikko on aina sama, mutta temptaskista riippuen seuraavaan kappaleeseen tulee eri teksti eli annetulla id:llä modelin kautta haetun temptaskin tekstikenttä. Id-kohdan olen laittanut vähän debuggaussyistä näkyviin.

Eniten tuskaa on aiheuttanut se mikä viewn mielestä on tunnettu muuttujan arvo ja mikä ei ja miten sen saa sieltä ulos.

Nämä asiat olen oppinut: 1) View tietää ne arvot, jotka controller on sille hakenut tai laskenut tai muuten muodostanut. Jos jokin ei näy, katse controlleriin. 2) Viewn tietämät arvot löytyvät paramsista. Olen käyttänyt sitä esim. näin:

<p><%= link_to 'Muokkaa', edit_project_goal_path(params[:project_id],@goal.id) %></p>

Sen mitä params pitää sisällään saa näkyviin seuraavan kaltaisella komennolla:

logger.debug "DEBUG params inspect #{params.inspect}"

Logger.debug siis printtaa viestejä serverin komentokehote-ikkunaan sinne kaikkien muiden printtien sekaan. Siksi laitoin selkeästi isoilla kirjaimilla tuon DEBUG rivin alkuun. Params:n varsinainen sisältö tulostuu #-merkistä alkavalla rimpsulla.

Joskus, itselleni vielä epäselvästä syystä, params:ssä on se haluttu arvo hashin sisällä. Eli jos normaalisti params:ssa on jutska1 => arvo1, jutska2 => arvo2, niin joskus se onkin jutska1 => {zydeemi1 => arvo3}. Tämän arvon saa ulos laittamalla nuo jutskat ja zydeemit peräkkäin omissa hakasuluissaan. Eli näin:

goal_id = params[:goal][:id]


Reitit solmussa

Sitten yhteen hankalimmista mutta tärkeimmistä asioista: routes.rb tiedostoon ja reitteihin ylipäänsä.

Ensimmäinen muutos, jonka routes.rb tiedostoon tein, oli

   root 'welcome#index'

Tämä tekee sen, että kun joku tulee nettisivun "juureen", hänet ohjataan welcome-controlleriin ja siellä index-actioniin.

Railsissa on eräänlaisia controllerien vakiotoimintoja. Toimintoja voi ja varmasti myöhemmin pitääkin tehdä myös itse, mutta vakiotoiminnot ovat helppokäyttöisiä ja hoitelevat paljon automaattisesti.

Toiminnot eli actionit ovat index, new, create, show, edit, update ja destroy.

Index on se mitä tehdään, kun käyttäjä haluaa nähdä kaikki tietyn tyyppiset jutskat, vaikka kaikki projektit.

New: luodaan uusi jutska mutta ei vielä tallenneta sitä mihinkään. Tätä tarvitaan vaikkapa siihen, kun näytetään sivu "Luo uusi projekti".

Create: luodaan uusi jutska ja tallennetaan se tietokantaan.

Show: näytetään yksi tietty jutska.

Edit: haetaan tietyn jutskan tiedot selaimelle muokkausta varten.

Update: tallennetaan muutokset tietokantaan.

Destroy: tuhotaan haluttu jutska.

Railsissa oikeaan toimintoon pääsee oikealla urlilla eli sillä mitä selaimen osoiterivillä lukee. Rails tulkitsee siitä mitä käyttäjä tai ohjelmoija haluaa. Nämä urlit saa tietoonsa kirjoittamalla komentoriville rake routes.

Siitä sujahtaa näkyville seuraavanlainen Railsin maagisesti koostama käsittämätön töräys:


Valitettavasti kyseessä on erittäin tärkeä lista, joka ymmärtäminen on ihan keskeistä.

Melko pitkään piti tukkaa nyhtää, mutta nyt tajuan mistä tuossa on kysymys. Otetaan yksi rivi esimerkiksi, vaikka se kaikkein pisin.

edit_project_goal_task GET    /projects/:project_id/goals/:goal_id/tasks/:id/edit(.:format) tasks#edit

edit_project_goal_task on se Railsin apukomento, jota käytetään, kun halutaan päästä task-controllerin edit-toimintoon.

GET on se HTTP-verbi, jota käytetään. En tästä sen enempää vielä tiedä, mutta verbillä on merkitystä,  kun sama url voikin viedä tapauksesta riippuen eri toimintoihin.

Sitten se url-osuus. Kun tuota edit_project_goal_task -apulaista kutsutaan, sen pitää tietää mikä projekti ja mikä tavoite ja mikä tehtävä, että se tietäisi luoda oikean urlin. Sille pitää jotakin kautta antaa ne puuttuvat tiedot eli :project_id, :goal_id ja :id. (Enimmät taisteluni Railsin kanssa olen käynyt juuri noista id:istä.)

Viimeinen sarake kertoo, mistä controllerista ja mistä toiminnosta on kysymys.

Puuhastelua mallien kanssa

Loin myös vastaavat modelit. Halusin niiden riippuvan toisistaan, joten tein taskiin goal_id-kentän ja goaliin project_id-kentän. Niin voisin löytää kuhunkin tavoitteeseen liittyvät tehtävät ja kuhunkin projektiin liittyvät tavoitteet. Loin mallit komentoriviltä, ja minun piti tehdä se muutamaan kertaan.

Lisäsin myös app/model-hakemistossa oleviin tiedostoihin tiedon siitä, millaisissa suhteissa ne ovat toisiinsa. Esim. app\models\task.rb tiedostoni näytti tältä:

class Task < ActiveRecord::Base
    belongs_to :goal
end


ja app\models\project.rb

class Project < ActiveRecord::Base
    has_many :goals
end


Näillä saa ohjeiden mukaan helpotettua esimerkiksi poistoa, kun ohjelma tietää mikä liittyy mihinkin. Onhan se itsellekin selkeyttävää, kun nämä laittaa paikoilleen.

Tietokantataulujen muoto generoituu tiedostoon db\schema.rb. Sieltä näkee minkä nimisiä sarakkeita sitä onkaan tullut luotua.

Taulujen luonnit ja muutokset tehdään migraatioilla. Antaisin ennemminkin nimeksi migreeni. Tämä osa-alue on jäänyt vielä melko hämäräksi. Idea on käsittääkseni se, että kukin muodon muutos tehdään ajamalla migraatiotiedosto, jonka voi myös perua. Menin itse niin solmuun noiden tiedostojen kanssa varsinkin kun menin käpälöimään käsin jotain mitä ilmeisesti ei olisi saanut muuttaa. Tiedostojen nimessä on aikaleima, jonka perusteella migraatiot ajetaan järjestyksessä.

Joka tapauksessa tietokannan hakiessa muotoaan minulle tuli tutuksi komentosarja

rake db:drop db:create db:migrate

joka tyhjentää tietokannat, luo ne uudelleen ja ajaa migraatiot. Joskus vielä ymmärrän tämänkin paremmin ja voin kirjoittaa siitä enemmän.

Valinnan paikka. Mitä ohjelmani tekee

Halusin siis tehdä oman ohjelman. Pieni ongelma oli ensin ratkaistavana - minun piti ensin keksiä mitä ohjelma tekisi.

Pienen pohdinnan jälkeen keksin loistavan idean, jossa pääsisin hyvin alkuun edellämainitulla Get Started -ohjeella. Tekisin ohjelman, jossa tietokantaan voisi lisätä projekteja, joiden alle voisi lisätä tavoitteita, joiden alle voisi lisätä tehtäviä. Tehtävät syötettäisiin irrallisina, ja ne liitettäisiin johonkin olemassaolevaan tavoitteeseen.

Siinäpä tavoitetta! Sain kuitenkin vähän vihiä siitä, millaisia controllereita tarvitsisin. Ohjeiden mukaan loin controllerit Project, Goal ja Task sekä Temptask. (Viimeksimainitun kanssa minun piti muuttaa nimeä, koska temp_task sekä TempTask aiheuttivat minulle ongelmia Railsin omatoimisen tiedoston- ja muun tauhkan luomisen kanssa.) Controllerit tallentuvat app/controllers -hakemistoon.

Rohkaistuminen. Koodin kopiointi on tylsää

Nyt siis oli edessä ensimmäisen applikaation tekeminen. Rails on siitä hyvä systeemi, että se tekee ohjelmoijan puolesta paljon rutiinihommia ja rohkaisee hyvään ohjelmointityyliin (tai näi ainakin mainoslause sanoo). Joka tapauksessa se luo paljon hakemistoja ja tiedostoja, joiden käyttötarkoituksesta ei ole alussa hajuakaan.

Näin kävi myös kun lähdin seuraamaan http://guides.rubyonrails.org/getting_started.html ohjeita ja loin ensimmäisen controllerini. En vielä siinä vaiheessa tiennyt yhtään, mikä controller on.

Mieheni, joka on ohjelmoinut jonkin verran Djangolla, joka on samantapainen alusta kuin Rails, selitti minulle miten asia menee, ja alkoihan se jostain muustakin yhteydestä muistua mieleen.

Applikaatiossa on siis kolme kerrosta: view, controller ja model. (Ja sitten se varsinainen tietokanta pohjalla). Ne ovat toistensa kanssa tekemisissä sillä tavalla, että view näyttää nätisti tiedon, jonka controller on jollain logiikalla kursinut kokoon ja hakenut modelin kautta tietokannasta. Model on tietokannan helppokäyttöinen ohjaamo. Minulla ei ole aavistustakaan mitä nämä termit ovat suomeksi, mutta ehkä jossain vaiheessa sen opin.

Joka tapauksessa se ohjelman varsinainen äly on controllerissa. Käyttäjä pyytää ohjelmaa tekemään jotain, ja pyyntö menee selaimen osoiterivin kautta controlleriin, joka tekee jotain ja palauttaa käyttäjälle tuloksen.

Kyllästyin ohjeiden seuraamiseen ja koodin kopioimiseen varsin äkkiä ja halusin tehdä ihan oman ohjelman.

Liikkeelle mars. Ympäristön asentaminen

Aivan ensin asensin tietokoneelleni Ruby on Rails -kehitysympäristön.

Seurasin RailsGirls.com-sivuston ohjeita Windowsille:
http://guides.railsgirls.com/install/#setup-for-windows

Latasin ja asensin ensin RailsInstallerin, sitten päivitin sen annetulla komennolla ja serveri lähti kiltisti käyntiin. Ei mitään ongelmia tässä vaiheessa. Tekstieditorina minulla oli jo Notepad++, joten en asentanut uutta.

En ihan ensin saanut serverin tuottamaa nettisivua auki, koska kikkailin jonkun ohjeen antamilla kummallisilla IP-osoitteilla. http://localhost:3000 on se, jota täytyy käyttää.

Käytin asentaessa default-asetuksia ja ohjelma meni C:/Sites hakemistoon. Eri projektit menevät sitten Sites-hakemiston sisälle.

Rubiiniturbiini pyörähtää käyntiin

Sain tässä yhtenä päivänä idean elvyttää vanha Ruby on Rails -opiskeluharrastukseni. Kokeilin joskus muinoin tehdä RailsGirls-sivuilta jonkin pienen applikaation ohjeiden mukaan, mutta kun yritin vähän laajentaa sitä, en tajunnutkaan enää yhtään mitään. Into latistui ja homma jäi.

Nyt olen uusin voimin asialla. Kirjaan opiskellessani oppimani asiat tähän blogiin, niin niistä voi olla muillekin hyötyä. Tässä jo ensimmäisten askelieni aikana olen nimittäin ehtinyt huomata, että RoR-dokumentaatio ei ole ihan parasta ja selkeintä laatua. Ehkä joku toinenkin tarvitsee keskimääräistä enemmän rautalankaa.

Minulla on käsitys siitä mihin ohjelmani on menossa, mutta en halua paljastaa liikaa. Voihan olla että siitä tulee kamalan hyvä ja saan siitä paljon rahaa. Hah hah! Jos nyt ainakin omaksuisin sen avulla tärkeimpiä Ruby on Rails -asioita.