如何在没有数据库的情况下使用json / javascript在sinatra中存储状态

时间:2016-03-31 20:30:12

标签: javascript sinatra

应用程序的html视图包含一个默认设置为20的变量。然后,当在浏览器中运行应用程序时,使用向上/向下按钮增加或减少此温度。但是,如果浏览器或页面被刷新(或重定向),则温度不会保留,而是始终重置为20。

以下是观点:

<!DOCTYPE html> <link href='https://fonts.googleapis.com/css?family=Lato' rel='stylesheet' type='text/css'> <html>   <head>
    <link rel="stylesheet" type="text/css" href="style.css">   </head>   <body>
    <section class="display">
      <h1>Thermostat</h1>
      <input id='city' type='text' placeholder="city name">
      <button id='submit'>Submit</button>
      <p id='weather'></p>
      <h1 id="temperature"></h1>
      <h4 id="psm"></h4>
      <form action='/temperature' method='post'>
        <button class="icon icon-up" id="up" name='temp'></button>
        <button class="icon icon-down"id="down" name='temp'></button>
        <button id="reset" name='temp'>reset</button>
        <button id="switchpowersaving">PSM</button>
      </form>
    </section>
    <script src="jquery.js"></script>
    <script src="thermostat.js"></script>
    <script src="interface.js"></script>
    <script src="weatherAPI.js"></script>   </body> </html>

当我们访问该页面时,我们将被定向到索引。然后我们在这里增加/减少温度。每次温度变化时,都会发布一个&#39; POST&#39;方法被发送到我们的/温度页面。然后,这将使用JSON,会话和参数创建哈希。这在interface.js文件中有一个ajax GET函数,它将这个新温度存储为data.temp。然后,每次重新加载页面时,应将thermostat.temperature设置为存储的data.temp。但是它会不断重置为20。

这是控制器:

require 'sinatra'
require 'json'

enable :sessions

  get '/' do
    send_file 'views/index.html'
  end

  post '/temperature' do
    p params[:temp]
    session[:temp] = params[:temp].to_i
    redirect '/temperature'
  end

  get '/temperature' do
    p session[:temp]
    if session[:temp]
      JSON.generate({temp: session[:temp]})
    else
      JSON.generate({temp: 20})
    end
    redirect '/'
  end

这是interface.js文件:

$(document).ready(function() {

  var thermostat = new Thermostat();
  var temp = thermostat.temperature;

  $.ajax({
    type: 'GET',
    url: 'http://localhost:4567/temperature',
    success: function(data){
      temp = data.temp;
    },
    error: function(){
      alert('Error loading temp');
    }
  });

  updateTemperature();

  $('#up').click(function() {
    thermostat.increaseTemperature();
    updateTemperature();
  });

  $('#down').click(function() {
    thermostat.decreaseTemperature();
    updateTemperature();
  });

  $('#reset').click(function() {
      thermostat.tempReset();
      updateTemperature();
    });

  $('#switchpowersaving').click(function() {
    thermostat.switchModePowerSaving();
    updateTemperature();
  });

    function updateTemperature() {
    $('#temperature').text(thermostat.currentTemperature() + "\xB0C");
    $('#up').attr('value', thermostat.currentTemperature());
    $('#down').attr('value', thermostat.currentTemperature());
    $('#reset').attr('value', thermostat.currentTemperature());
    $('.display').css('background-color', thermostat.displayColor());
    $('#psm').text(thermostat.displayPowerSaveMode());
  }
});

这是thermostat.js:

function Thermostat(){
  this.temperature = 20;
  this.MINTEMP = 10;
  this.isPowerSaving = true;
  this.thermostatDisplay = 'yellow';
}

Thermostat.prototype.currentTemperature = function(){
  return this.temperature;
};

Thermostat.prototype.increaseTemperature = function(){
  if ( this.currentTemperature() >= this.maxTemp()) {
    throw 'Max. temp reached';
}
  this.temperature ++;
};

Thermostat.prototype.decreaseTemperature = function(){
  if ( this.currentTemperature() <= this.MINTEMP ) {
    throw 'Min. temp reached';
  }
  this.temperature --;
};

Thermostat.prototype.maxTemp = function(){
  if(this.isPowerSaving === true) {return 25;}
    else
      {return 32;}
};

Thermostat.prototype.switchModePowerSaving = function() {
  if (this.isPowerSaving === true)
    {this.isPowerSaving=false;}
  else
    {this.isPowerSaving=true;}
};

Thermostat.prototype.tempReset = function() {
    this.temperature = 20;
};

Thermostat.prototype.displayColor = function() {
  if(this.temperature <= 18) {return 'green';}
  if(this.temperature <= 25) {return 'yellow';}
  if(this.temperature > 25) {return 'red';}
};

Thermostat.prototype.displayPowerSaveMode = function(){
  if(this.isPowerSaving === true) {return 'Power Save Mode: ON';}
  else {return 'Power Save Mode: OFF';}
};

increaseTemperature / decreaseTemperature函数只是将thermostat.temperature增加和减少+ 1 / -1。

当直接访问&#39; /温度&#39;时,可以访问按下按钮时的新温度。但是在浏览器中重定向到&#39; /&#39;新的thermostat.temperature未设置为新温度,并始终重置为默认温度(20)。

如何在不使用数据库的情况下将其存储在状态中。 (存储新的温度,以便刷新页面时新的温度保持不变,而不是重置为20。

1 个答案:

答案 0 :(得分:0)

这里有几个问题:

send_file不是使用Sinatra加载HTML文件的首选方式。替代方法是将index.html重命名为index.erb,然后使用以下作为路由描述符:

get '/' do
  erb :index
end

ERB是HTML的超集,并添加了ruby插值标记,可用于从Sinatra传递变量或只是在视图中运行ruby命令。如果您熟悉这些标记,则这些标记类似于JSP的<%%>或PHP的<?php ?>。在ERB中,<%%>将运行ruby命令,<%= %>可用于将ruby命令的结果打印到视图上。

在设计路线时,预先确定请求/响应的数据类型非常重要。例如,当interface.js加载时,它会通过jQuery向GET端点发出'/temperature请求。由于您尚未指定数据类型,因此响应将为字符串,data.temp将为null。因此,在ajax调用中,您需要添加dataType: 'json'设置:

$.ajax({
  type: 'GET',
  url: 'http://localhost:4567/temperature',
  dataType: 'json',
  success: function(data){
  // same as earlier
});

另一个好处是不要在sinatra中混合和匹配AJAX调用和redirect调用。这是一个问题,尤其是在这种情况下,因为当您重定向到索引页面时,虽然会话数据存在,但它不会被加载/显示在任何地方。理想情况下,在Sinatra中,您必须将值分配给实例变量并在视图中将其打印出来:

# app.rb
get '/' do
  @temp = session[:temp] || 20
  erb :index
end

# views/index.erb
# truncating common code
<h1 id="temperature"><%= @temp %></h1>

这样,当get '/'路线加载时,显示初始温度。 $.ajax GET请求可以完全删除。

单击按钮时,默认情况下会发生表单提交,这将完全重新加载。这可能会搞乱你正在做的任何基于JS的渲染(我现在无法完全理解这部分)。因此,不是进行整页重定向,而是将AJAX帖子(如评论中指出的)改为“/ temperature”路径。请注意,您必须禁用按钮单击的默认操作。所以:

  $('#up').click(function() {
    thermostat.increaseTemperature();
    updateTemperature();
   });

和其他点击处理程序应更改为:

  $('#up').click(function(event) {
    event.preventDefault();
    event.stopPropagation();
    thermostat.increaseTemperature();
    updateTemperature();
   });

这将确保在您单击按钮时不会发生默认的HTML表单提交。 updateTemperature()将进行ajax POST调用。我在这里提出了一个示例:https://gist.github.com/kgrz/9320d1682e682a9930c30e34c979a306