Keksin että voisin Muokkaa ja Poista -tekstien sijaan näyttää sopivan Unicode-merkin. Niillä on omat koodit, jotka toimivat hienosti HTML:n seassa.
<th>✎</th>
<th>❌</th>
Sitten ajattelin, että haluaisin myös jonkin merkin yläreunan navipalkkiin erottamaan sanoja toisistaan.
Alkuperäinen linkki:
<%= link_to 'Projektit', controller: 'projects' %>
Ei toimi:
<%= link_to '✨ Projektit', controller: 'projects' %>
Rails-koodin sisällä oleva & muuttui & -iksi.
Vähän googlailtuani löysin ohjeen käyttää raw-apulaista. Se olikin avulias:
<%= link_to raw('✨ Projektit'), controller: 'projects' %>
tiistai 29. syyskuuta 2015
Rails meets jQuery: Popup-laatikko
Olen opetellut vähän jQueryn alkeita ja koittanut keksiä, miten voisin kokeilla sitä applikaatiossani. Keksinkin sitten, että sen sijaan että projektilistauksessa (index-sivulla) yhtenä sarakkeena on "kuvaus", kuvausteksti voisi tulla näkyviin, kun käyttäjä laittaa hiiren projektin nimen päälle.
Sen sain aikaan näin:
projects.js
$( document ).ready(function() {
$(this).on('mouseover', '.table-link', function () {
var shortDescBox = $(this).closest('.projecttitle').find('#shortdesc-box');
shortDescBox.text($(this).data('shortdesc'));
shortDescBox.slideDown();
});
$(this).on('mouseleave', '.table-link', function () {
$(this).closest('.projecttitle').find('#shortdesc-box').slideUp();
});
});
index.html.erb
...
<% @projects.each do |project| %>
<tr>
<td class="projecttitle"><%= link_to project.title, project_path(project), :class => "table-link", :'data-shortdesc' => project.description %><div id="shortdesc-box"></div></td>
<td><%= project.goals.count %></td>
...
main.css
#shortdesc-box {
background-color: white;
border: 1px solid black;
position: absolute;
top: 2px;
right: 5px;
font-size: 0.9em;
max-width: 200px;
padding: 10px;
display: none;
z-index: 1;
-moz-border-radius-bottomright: 30px;
-webkit-border-bottom-right-radius: 30px;
border-bottom-right-radius: 30px;
}
Itse jQueryn otin appikseen mukaan näin:
application.html.erb
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
Sen sain aikaan näin:
projects.js
$( document ).ready(function() {
$(this).on('mouseover', '.table-link', function () {
var shortDescBox = $(this).closest('.projecttitle').find('#shortdesc-box');
shortDescBox.text($(this).data('shortdesc'));
shortDescBox.slideDown();
});
$(this).on('mouseleave', '.table-link', function () {
$(this).closest('.projecttitle').find('#shortdesc-box').slideUp();
});
});
index.html.erb
...
<% @projects.each do |project| %>
<tr>
<td class="projecttitle"><%= link_to project.title, project_path(project), :class => "table-link", :'data-shortdesc' => project.description %><div id="shortdesc-box"></div></td>
<td><%= project.goals.count %></td>
...
main.css
#shortdesc-box {
background-color: white;
border: 1px solid black;
position: absolute;
top: 2px;
right: 5px;
font-size: 0.9em;
max-width: 200px;
padding: 10px;
display: none;
z-index: 1;
-moz-border-radius-bottomright: 30px;
-webkit-border-bottom-right-radius: 30px;
border-bottom-right-radius: 30px;
}
Itse jQueryn otin appikseen mukaan näin:
application.html.erb
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
torstai 24. syyskuuta 2015
Kuivaksi puristusta: before_action
Olen palannut näin vuoden tauon jälkeen appiksen pariin. Aloin käydä läpi Rails for Zombies -tutorialia, josta opin heti neljännellä oppitunnilla uuden asian ja aloin soveltaa sitä omaan sovellukseeni.
Model-sivulla olevissa toiminnoissa show, edit jne joudutaan usein tekemään sama asia aluksi, esimerkiksi hakemaan tietokannasta käsiteltävänä oleva asia. Sitä on turha tehdä monta kertaa, vaan Railsissa on rakenne märän koodin kuivaamiseksi (D.R.Y. = Don't Repeat Yourself) eli toiston poistamiseksi.
class TemptasksController < ApplicationController
before_action :get_temptask, only: [:show, :edit, :update, :destroy]
def get_temptask
@temptask = Temptask.find(params[:id])
end
def new
def create
Kaikkien tarvitseman osuuden voi siirtää uuden deffin alle, olen antanut tässä sille nimeksi get_temptask koska se hakee id:n perusteella temptaskin tietokannasta. before_action osaa ajaa tämän ennen joko kaikkia toimintoja tai pelkästään ennen tiettyjä toimintoja kuten tässä.
Model-sivulla olevissa toiminnoissa show, edit jne joudutaan usein tekemään sama asia aluksi, esimerkiksi hakemaan tietokannasta käsiteltävänä oleva asia. Sitä on turha tehdä monta kertaa, vaan Railsissa on rakenne märän koodin kuivaamiseksi (D.R.Y. = Don't Repeat Yourself) eli toiston poistamiseksi.
class TemptasksController < ApplicationController
before_action :get_temptask, only: [:show, :edit, :update, :destroy]
def get_temptask
@temptask = Temptask.find(params[:id])
end
def new
def create
Kaikkien tarvitseman osuuden voi siirtää uuden deffin alle, olen antanut tässä sille nimeksi get_temptask koska se hakee id:n perusteella temptaskin tietokannasta. before_action osaa ajaa tämän ennen joko kaikkia toimintoja tai pelkästään ennen tiettyjä toimintoja kuten tässä.
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.
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/
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
*/
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.
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.
Tilaa:
Blogitekstit (Atom)


