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!