Sinatra App JSON and Routes - ruby

Scenario
I have a Sinatra App
I have a route that fetches articles based on a certain named path
# Get Articles for a certain time period
get '/frontpage/:type' do
case params[:type]
when "today"
#news = Article.find(...)
when "yesterday"
#news = Article.find(...)
when "week-ago"
#news = Article.find(...)
when "month-ago"
#news = Article.find(...)
else
not_found
end
erb :frontpage
end
Question
Is it possible to keep this route "/frontpage/:type" and show a .json page if for example someone ask for "/frontpage/:today.json" instead of "/frontpage/:type" ?
OR
Is it better to create a separate route specifically for requests for JSON ?

You will have to create a new route.
Though, you can factor your code like that:
get '/frontpage/:type' do
#news = get_articles(params[:type])
erb :frontpage
end
get '/frontpage/:type.json' do
get_articles(params[:type]).json
end
def get_articles(type)
case
when "today"
Article.find(...)
when "yesterday"
Article.find(...)
when "week-ago"
Article.find(...)
when "month-ago"
Article.find(...)
else
raise "Unsupported type #{type}. Supported types are: today, yesterday, week-ago and month-ago."
end
end

This can actually be done with a single route:
require 'rubygems'
require 'sinatra'
get %r{/frontpage/([^\.]+)\.?(.+)?} do |type, ext|
'the type is: ' + type + ' and the extension is: ' + "#{ext}"
end
You can the use the ext var to return your json content if it's non-nill, and has the value 'json'.

The route order matters.
Compare this app, .json first
require "sinatra"
require "sinatra/contrib/all"
get "/greet/:name.json" do |name|
json ({"greeting" => greeting(name)})
end
get "/greet/:name" do |name|
greeting name
end
def greeting(name)
"Hello #{name}"
end
with this app, .json last
require "sinatra"
require "sinatra/contrib/all"
get "/greet/:name" do |name|
greeting name
end
get "/greet/:name.json" do |name|
json ({"greeting" => greeting(name)})
end
def greeting(name)
"Hello #{name}"
end
With the first:
$ curl localhost:4567/greet/frank
Hello frank
$ curl localhost:4567/greet/frank.json
{"greeting": "Hello frank"}
But with the second,
$ curl localhost:4567/greet/frank
Hello frank
$ curl localhost:4567/greet/frank.json
Hello frank.json

Related

Getting all unique URL's using nokogiri

I've been working for a while to try to use the .uniq method to generate a unique list of URL's from a website (within the /informatics path). No matter what I try I get a method error when trying to generate the list. I'm sure it's a syntax issue, and I was hoping someone could point me in the right direction.
Once I get the list I'm going to need to store these to a database via ActiveRecord, but I need the unique list before I get start to wrap my head around that.
require 'nokogiri'
require 'open-uri'
require 'active_record'
ARGV[0]="https://www.nku.edu/academics/informatics.html"
ARGV.each do |arg|
open(arg) do |f|
# Display connection data
puts "#"*25 + "\nConnection: '#{arg}'\n" + "#"*25
[:base_uri, :meta, :status, :charset, :content_encoding,
:content_type, :last_modified].each do |method|
puts "#{method.to_s}: #{f.send(method)}" if f.respond_to? method
end
# Display the href links
base_url = /^(.*\.nku\.edu)\//.match(f.base_uri.to_s)[1]
puts "base_url: #{base_url}"
Nokogiri::HTML(f).css('a').each do |anchor|
href = anchor['href']
# Make Unique
if href =~ /.*informatics/
puts href
#store stuff to active record
end
end
end
end
Replace the Nokogiri::HTML part to select only those href attributes that matches with /*.informatics/ and then you can use uniq, as it's already an array:
require 'nokogiri'
require 'open-uri'
require 'active_record'
ARGV[0] = 'https://www.nku.edu/academics/informatics.html'
ARGV.each do |arg|
open(arg) do |f|
puts "#{'#' * 25} \nConnection: '#{arg}'\n #{'#' * 25}"
%i[base_uri meta status charset content_encoding, content_type last_modified].each do |method|
puts "#{method.to_s}: #{f.send(method)}" if f.respond_to? method
end
puts "base_url: #{/^(.*\.nku\.edu)\//.match(f.base_uri.to_s)[1]}"
anchors = Nokogiri::HTML(f).css('a').select { |anchor| anchor['href'] =~ /.*informatics/ }
puts anchors.map { |anchor| anchor['href'] }.uniq
end
end
See output.

Ruby script sending received email as sms

I have a simple ruby script meant to send all received messages as sms messages. However, somehow for some reason it does not execute.
Here is the sample code;
/etc/aliases
motor: "|/home/motorcare/sms_script.rb"
sms_script.rb
#!/usr/bin/env ruby
require "json"
require "httparty"
require 'net/http'
require 'uri'
require "cgi"
require "mail"
# Reading files
mail = Mail.read(ARGV[0])
destination = mail.subject
message = mail.body.decoded
#first_line = lines[0].strip
if destination =~ /^(256)/
send(destination, message)
else
destination = "256#{destination.gsub(/^0+/,"")}"
send(destination, message)
end
# Sending message
def send(destination, message)
url = "http://xxxxxxxxxx.com/messages?token=c19ae2574be1875f0fa09df13b0dde0b&to=#{phone_number}&from=xxxxxx&message=#{CGI.escape(message)}"
5.times do |i|
response = HTTParty.get(url)
body = JSON.parse(response.body)
if body["status"] == "Success"
break
end
end
end
Anyone with a similar script to assist with this one?
You have 2 errors.
1st error is that send is already defined in Ruby. See this SO post What does send() do in Ruby?
see this code
$ cat send.rb
#!/usr/bin/env ruby
puts defined? send
puts send :class
$ ./send.rb
method
Object
2nd error is that you call the method before it's even defined. See this sample code (calling welcome before def welcome)
$ cat welcome.rb
#!/usr/bin/env ruby
welcome('hello from welcome')
def welcome(msg)
puts msg
end
$ ./welcome.rb
./welcome.rb:3:in `<main>': undefined method `welcome' for main:Object (NoMethodError)
Change the method name from send to something else, e.g. send_sms, and put the definition before calling the method
So this should be sth like:
#!/usr/bin/env ruby
require "json"
require "httparty"
require 'net/http'
require 'uri'
require "cgi"
require "mail"
# Sending message
def send_sms(destination, message)
url = "http://xxxxxxxxxx.com/messages?token=c19ae2574be1875f0fa09df13b0dde0b&to=#{phone_number}&from=xxxxxx&message=#{CGI.escape(message)}"
5.times do |i|
response = HTTParty.get(url)
body = JSON.parse(response.body)
if body["status"] == "Success"
break
end
end
end
# Reading files
mail = Mail.read(ARGV[0])
destination = mail.subject
message = mail.body.decoded
#first_line = lines[0].strip
if destination =~ /^(256)/
send_sms(destination, message)
else
destination = "256#{destination.gsub(/^0+/,"")}"
send_sms(destination, message)
end
And also adding logging to the script would give you info about what's going in inside when it's run and pipped. So you can easily debug the beaviour. Logging is the easies approach to DEBUG.

Ruby - Getting page content even if it doesn't exist

I am trying to put together a series of custom 404 pages.
require 'uri'
def open(url)
page_content = Net::HTTP.get(URI.parse(url))
puts page_content.content
end
open('http://somesite.com/1ygjah1761')
the following code exits the program with an error. How can I get the page content from a website, regardless of it being 404 or not.
You need to rescue from the error
def open(url)
require 'net/http'
page_content = ""
begin
page_content = Net::HTTP.get(URI.parse(url))
puts page_content
rescue Net::HTTPNotFound
puts "THIS IS 404" + page_content
end
end
You can find more information on something like this here: http://tammersaleh.com/posts/rescuing-net-http-exceptions/
Net::HTTP.get returns the page content directly as a string, so there is no need to call .content on the results:
page_content = Net::HTTP.get(URI.parse(url))
puts page_content

Read parameters via POST with Ruby + Sinatra + MongoDB

I'm creating a simple API with Sinatra + Ruby + MongoDB, working via GET not have problems, but via POST yes... I try to receive params but this come in empty, I don't know if I'm doing thing not good. I am not working with view html, just request and response JSON. I use POSTMAN for pass parameters via POST, but nothing.
Code: app.rb
require 'rubygems'
require 'sinatra'
require 'mongo'
require 'json/ext'
require './config/Database'
require_relative 'routes/Estudiantes'
require_relative 'routes/OtherRoute
Code Estudiantes.rb
# Rest Collection Student
collection = settings.mongo_db['estudiantes']
# Finding
get '/estudiantes/?' do
content_type :json
collection.find.to_a.to_json
end
# find a document by its ID
get '/estudiante/:id/?' do
content_type :json
collection.find_one(:_id => params[:id].to_i).to_json
end
# Inserting
post '/new_estudiante/?' do
content_type :json
student = params # HERE
puts 'Parameters: ' + student
new_id = collection.insert student
document_by_id(new_id)
end
# Updating
post '/update_name/:id/?' do
content_type :json
id = BSON::ObjectId.from_string(params[:id].to_s)
puts 'ID: ' + params[:id].to_s
name = params[:name].to_s # HERE
age = params[:age].to_i # HERE
puts 'Name and Age: ' + name + age.to_s
collection.update({:_id => id}, {'$set' => {:name => name, :age => age} })
document_by_id(id)
end
post '/post/?' do
puts params[:name].to_json # HERE
end
Thanks
Solution:
You should apply a JSON.parse and then read parameter
code
post '/post/?' do
params = JSON.parse request.body.read
puts params['name']
end

Sinatra Mongoid String not valid UTF-8

I wrote this little application :
require 'rubygems'
require 'sinatra'
require 'bson'
require 'mongoid'
Mongoid.configure do |config|
name = "articles"
host = "localhost"
config.master = Mongo::Connection.new.db(name)
config.persist_in_safe_mode = false
end
class Article
include Mongoid::Document
field :title
field :content
end
get '/' do
#articles = Article.all
end
get '/show/:id' do
#article = Article.find(params[:id])
end
get '/new' do
haml :new
end
post '/create' do
#article = Article.new(params['article'])
if #article.save
redirect '/'
else
redirect '/new'
end
end
The following error occur when i post an article with a content "Test d'un article en français"
BSON::InvalidStringEncoding at /create String not valid UTF-8
How i can fix this error ?
Thanks
This is a known issue with Ruby 1.9 and Sinatra. Wait for Sinatra 1.1 to be released or use Sinatra edge version from github.

Resources