I have an app file that looks like this ws_app.rb:
require 'rubygems'
require 'sinatra'
require 'sinatra/respond_to'
require 'dm-core'
require 'dm-migrations'
require 'dm-timestamps'
require 'json'
require 'csv'
load 'models/Battery.rb'
Sinatra::Application.register Sinatra::RespondTo
DataMapper::setup(:default,"sqlite3://#{Dir.pwd}/mpt_hmi.sqlite3")
class MPTHMI < Sinatra::Base
load 'controller/BatteryController.rb'
end
The modules/Battery.rb looks like this:
class Battery
include DataMapper::Resource
property :id, Serial
property :i_battery_manager_id, Integer
property :c_battery_number, String
property :c_battery_state, String
property :c_voltage_byte, String
property :i_voltage_int, Integer
property :i_temperature, Integer
property :i_resistance, Integer
property :i_capacity, Integer
property :i_cell_balancing_duration, Integer
property :i_total_cell_balancing_duration, Integer
property :i_age, Integer
property :i_time_to_service, Integer
property :created_at, DateTime
property :updated_at, DateTime
def to_my_json
{
:i_battery_manager_id => self.i_battery_manager_id,
:c_battery_number => self.c_battery_number,
:c_battery_state => self.c_battery_state,
:c_voltage_byte => self.c_voltage_byte,
:i_voltage_int => self.i_voltage_int,
:i_temperature => self.i_temperature,
:i_resistance => self.i_resistance,
:i_capacity => self.i_capacity,
:i_cell_balancing_duration => self.i_cell_balancing_duration,
:i_total_cell_balancing_duration => self.i_total_cell_balancing_duration,
:i_age => self.i_age,
:i_time_to_service => self.i_time_to_service
}
end
end
The controller/BatteryController.rb file looks like this:
get '/battery/:id' do
@battery = Battery.get(params[:id])
respond_to do |wants|
wants.html { erb :battery } # html
wants.json { @battery.to_my_json.to_s } # json
end
end
get '/batteries' do
@batteries = Battery.all
respond_to do |wants|
wants.html { erb :batteries } # html
wants.json {
@batteries.all.inject({}) { |hsh, obj|
hsh[obj.id] = obj.to_my_json
hsh
}.to_json
}
end
end
This works perfectly when I run Sinatra normally, like so:
$ ruby ws_app.rb
== Sinatra/1.3.2 has taken the stage on 4567 for development with backup from Thin
>> Thin web server (v1.3.1 codename Triple Espresso)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop
Then go here:
http://0.0.0.0:4567/battery/5.json
I get the JSON I'm expecting:
{:i_battery_manager_id=>1, :c_battery_number=>"5", :c_battery_state=>"3", :c_voltage_byte=>"145", :i_voltage_int=>191, :i_temperature=>107, :i_resistance=>81, :i_capacity=>228, :i_cell_balancing_duration=>127, :i_total_cell_balancing_duration=>37, :i_age=>111, :i_time_to_service=>211}
but I need to deploy this on a Cherokee web server, so I want to make a rack config.ru file for this...
So I have a file mpthmiws.rb which contains
load 'ws_app.rb'
MPTHMI.run
And a config.ru file which contains
load 'mpthmiws.rb'
run MPTHMI.new
When I run
$ rackup config.ru
>> Thin web server (v1.3.1 codename Triple Espresso)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:9292, CTRL+C to stop
and go here:
http://0.0.0.0:9292/battery/1.json
but then I get the famous, "Sinatra doesn't know this ditty - try get '/battery/1.json' do "Hello World" end
If I take the first route from the controller/BatteryController.rb file and put it inside HMIMPT class in the ws_app.rb file like this:
require 'rubygems'
require 'sinatra'
require 'sinatra/respond_to'
require 'dm-core'
require 'dm-migrations'
require 'dm-timestamps'
require 'json'
require 'csv'
load 'models/Battery.rb'
Sinatra::Application.register Sinatra::RespondTo
DataMapper::setup(:default,"sqlite3://#{Dir.pwd}/mpt_hmi.sqlite3")
class MPTHMI < Sinatra::Base
get '/battery/:id' do
@battery = Battery.get(params[:id])
respond_to do |wants|
wants.html { erb :battery } # html
wants.json { @battery.to_my_json.to_s } # json
end
end
end
I get this error:
undefined method `respond_to' for #<MPTHMI:0x00000001240a80>
How can I resolve this? Thanks
First of all, that thing with mpthmiws.rb and config.ru is overly complicated. Delete mpthmiws.rb and use this config.ru for use with
rackup config.ru:If you want to run the App with plain old
ruby ws_app.rb, use this run.rb file:Which brings us to the next point: NEVER EVER USE
load! It executes the code in the loaded file, but it does not bring over any defined variables, functions etc. Userequireinstead! Here you must prefix the path with./or add./to$LOAD_PATH, but in turn you can omit the.rbextension.Next is your BatteryController.rb file. It should look like this: require 'sinatra/respond_to'
And this is also the point where you
registeryour extensions — in the class where you need it.Now that we understand how
loadworks, you may already have noticed that you were not actually loading thegetblocks into theMPTHMIclass, but rather executing them outside of the class. That is the only reason why your app worked anyway with plain oldruby ws_app.rb!You can properly include your controller into a class with
use:You can also leave off the
registerin here. Feel free to comment if you have further questions!And here's the full diff: