Sinatra Mongoid String not valid UTF-8 - ruby

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.

Related

Sinatra Session data shared between browsers

I have a basic banking application running on Heroku using Sinatra.
I have tried implementing sessions to ensure each user that visits has a different version of the app. However, at the moment, if I visit it with two separate browsers, I have the same data.
There is no backend database implemented but data I add via the interface persists in every browser I visit in.
Here is my app.rb:
require 'sinatra/base'
require 'tilt/erb'
require 'require_all'
require_all 'lib'
require 'rufus-scheduler'
class BankingApp < Sinatra::Base
enable :sessions
set :session_secret, 'super secret'
get '/' do
session[:accounts] = AccountsController.instance
session[:holders] = HoldersController.instance
session[:loans] = LoansController.instance
erb :index
end
get '/holders' do
#holders = session[:holders].store
erb :holders
end
get '/holders_accounts' do
#holder = session[:holders].find(params[:id].to_i)
message = session[:accounts].get_accounts_of(params[:id].to_i)
#accounts = message.accounts
erb :holders_accounts
end
get '/new_holder' do
erb :new_holder
end
post '/new_holder' do
#message = session[:holders].create(params[:name])
#holders = session[:holders].store
erb :holders
end
get '/create_account' do
erb :create_account
end
post '/create_account' do
type = :Current
id = params[:id].to_i
#message = session[:accounts].open(type, with: id)
erb :index
end
get '/accounts' do
#accounts = session[:accounts].store
erb :accounts
end
get '/transactions' do
message = session[:accounts].get_transactions_of(params[:id].to_i)
#transactions = message.transactions
erb :transactions
end
get '/deposit' do
erb :deposit
end
post '/deposit' do
#accounts = session[:accounts].store
#message = session[:accounts].deposit(params[:amount].to_i, into: params[:id].to_i)
erb :accounts
end
get '/withdraw' do
erb :withdraw
end
post '/withdraw' do
#accounts = session[:accounts].store
#message = session[:accounts].withdraw(params[:amount].to_i, from: params[:id].to_i)
erb :accounts
end
get '/transfer' do
erb :transfer
end
post '/transfer' do
#accounts = session[:accounts].store
#message = session[:accounts].transfer(params[:amount].to_i, from: params[:donar].to_i, to: params[:recipitent].to_i)
erb :accounts
end
get '/add_holder' do
erb :add_holder
end
post '/add_holder' do
#accounts = session[:accounts].store
#message = session[:accounts].add_holder(params[:holder_id].to_i, to: params[:account_id].to_i)
erb :accounts
end
get '/enable_overdraft' do
erb :enable_overdraft
end
post '/enable_overdraft' do
#accounts = session[:accounts].store
#message = session[:accounts].activate_overdraft(params[:id].to_i, params[:amount].to_i)
erb :accounts
end
get '/disable_overdraft' do
erb :disable_overdraft
end
post '/disable_overdraft' do
#accounts = session[:accounts].store
#message = session[:accounts].deactivate_overdraft(params[:id].to_i)
erb :accounts
end
get '/loans' do
#loans = session[:loans].store
erb :loans
end
get '/loan_view' do
message = session[:loans].show(params[:id].to_i)
#transactions = message.transactions
erb :loan_view
end
get '/new_loan' do
erb :new_loan
end
post '/new_loan' do
#loans = session[:loans].store
id = params[:id].to_i
options = { borrowed: params[:amount].to_i, term: params[:term].to_i, rate: params[:rate].to_f }
#message = session[:loans].create_loan(id, options)
erb :loans
end
get '/pay_loan' do
erb :pay_loan
end
post '/pay_loan' do
#message = session[:loans].pay(params[:amount].to_i, off: params[:id].to_i)
#loans = session[:loans].store
erb :loans
end
# start the server if ruby file executed directly
run! if app_file == $0
end
I do not have a great deal of experience with Sinatra so apologies if this is an oversight on my part.
Any help greatly appreciated.
So I'm pretty sure the core of your problem is this line which you have in multiple places throughout your code. As per the ruby docs
This ensures that only one instance of Klass can be created.
You've explicitly told ruby to only ever let one copy of each class/module ever exist. I don't think that's what you want.
It's a bit hard to infer what it is you're trying to achieve exactly but I don't think using Singleton in a web app is going to be the right solution. The assumptions it imposes break down as soon as you run a 2nd instance (or dyno in Heroku parlance) of your app.
I would recommend using this
get '/logout' do
session.clear
end

Firebase global variable Ruby

https://github.com/oscardelben/firebase-ruby
How do I use firebase across methods and not locally as shown in the examples? Ex: #firebase, See the paste at --
http://bpaste.net/show/501b6a67c8d4
or --
require 'sinatra'
require 'firebase'
require 'bundler'
Bundler.require
# Configure database
configure do
#base_uri = 'https://veriyo.firebaseio.com/'
#firebase = Firebase::Client.new(#base_uri)
end
# Display homepage
get '/' do
erb :index
end
post '/search' do
#username = params["username"]
redirect to("/user/#{#username}")
end
get '/user/:username' do
response = #firebase.push("todos", { :name => #username })
'hello'
end
The #firebase variable's attributes aren't accessible there -- #<NoMethodError: undefined methodpush' for nil:NilClass>`
Set them as constants:
FB_Base_uri = 'https://veriyo.firebaseio.com/'
FB_Firebase = Firebase::Client.new(FB_Base_uri)

store and output formatted array contents with sinatra

Environment: Ruby 1.9.2
I am new to Ruby/Sinatra and am creating a proof of concept web application. The purpose is fairly simple: A user inputs a list of domains and the script first checks their mx records, and if they meet the condition, pulls out the domain contact information. I am fairly sure that I am not going about storing the data appropriately and am looking for a more elegant solution that will enable me to style the results such that domain, email, and name are grouped together.
#!/usr/bin/env ruby
require "sinatra/base"
require 'rubygems'
require 'haml'
require 'sinatra'
require 'whois'
get '/' do
haml :index
end
post '/' do
#host = params[:host]
#host.split('\n')
#email = Array.new
#name = Array.new
#domain = Array.new
#host.each_line {|i|
if %x[dig -t mx #{i.chomp.gsub('www.', '')} | grep -i mx | grep -i google].empty?
puts "empty"
else
#domain << i.chomp.gsub('www.','')
#email << (Whois.whois(i.chomp.gsub('www.',''))).technical_contact.email
#name << (Whois.whois(i.chomp.gsub('www.',''))).technical_contact.name
end
}
haml :index
end
__END__
## layout
%html
%head
%title Gcrawl
%body
#header
%h1 Gcrawl
#content
=yield
%footer
## index
%p
Welcome to Gcrawl
%form(action='/' method='POST')
%textarea{:rows => '12', :cols => '40', :name => 'host'}
%input(type='submit')
- if defined?(#email)
%h3= #domain
%h3= #email
%h3= #name
Create a class Record which will contain #name, #domain and #email for a particular entry.
So, each instance of Record will have it's own name, domain and email.
Replace the array implementation with a Class. If you need to store the records in a database, use ActiveRecord.
It's good that you started with Sinatra, but if you are in a hurry, you can get your app running on Rails in an hour.
EDIT
Tutorials/Guides for getting started with Rails:
Rails Guides - Getting Started
rubyonrailstutorials.com
railstutor.com

Receiving errors when saving Tweets to a database using Sinatra

I'm using Sinatra, EventMachine, DataMapper, SQLite3 and the Twitter Stream API to capture and save tweets. When I run the application from my command line, it seems to continually fail at tweet 50. If I'm not saving the tweets, it can run seemingly forever.
Below is the app code to capture tweets with 'oscar' in them, which provided a very quick stream. Just enter your twitter username and password and run at the command line.
require 'rubygems'
require 'sinatra'
require 'em-http'
require 'json'
require 'dm-core'
require 'dm-migrations'
USERNAME = '<your twitter username>'
PASSWORD = '<your secret password>'
STREAMING_URL = 'http://stream.twitter.com/1/statuses/filter.json'
DataMapper.setup(:default, ENV['DATABASE_URL'] || "sqlite3://#{Dir.pwd}/db/development.db")
class Tweet
include DataMapper::Resource
property :id, Serial
property :tweet_id, String
property :username, String
property :avatar_url, String
property :text, Text
end
DataMapper.auto_upgrade!
get '/' do
#tweets = Tweet.all
erb :index
end
def rip_tweet(line)
#count += 1
tweet = Tweet.new :tweet_id => line['id'],
:username => line['user']['screen_name'],
:avatar_url => line['user']['profile_image_url'],
:text => line['text']
if tweet.save
puts #count
else
puts "F"
end
end
EM.schedule do
#count = 0
http = EM::HttpRequest.new(STREAMING_URL).get({
:head => {
'Authorization' => [ USERNAME, PASSWORD]
},
:query => {
'track' => 'oscars'
}
})
buffer = ""
http.stream do |chunk|
buffer += chunk
while line = buffer.slice!(/.+\r?\n/)
rip_tweet JSON.parse(line)
end
end
end
helpers do
alias_method :h, :escape_html
end
I'm not sure you can safely mix EM and Sinatra in the same process. You might want to try splitting the Sinatra viewer and the EventMachine downloader into separate programs and processes.

Sinatra/CouchDB error?

I'm working on my first Sinatra/CouchDB project and I'm getting an error I can't explain.
Here's my rackup (config.ru) file:
require 'rubygems'
require 'couchrest'
require 'patina'
set :environment, :development
set :root, File.dirname(__FILE__)
set :run, false
FileUtils.mkdir_p 'log' unless File.exists?('log')
log = File.new("log/sinatra.log", "a")
$stdout.reopen(log)
$stderr.reopen(log)
set :db, CouchRest.database!("http://127.0.0.1:5984/test")
run Sinatra::Application
And here's the app file (patina.rb):
require 'rubygems'
require 'sinatra'
require 'couchrest'
require 'haml'
class Article < CouchRest::ExtendedDocument
use_database settings.db
property :title
timestamps!
view_by :title
end
get '/' do
#db = settings.db
haml :index
end
Without the class definition in patina.rb, the route returns a page that displays the #db property as I was expecting. However, when I add the class definition to patina.rb I get "Ruby (Rack) application could not be started" error message.
Obviously this has something to do with my class definition, but I can't figure out what the problem is and the error message doesn't seem that helpful to me.
Also, I'd actually prefer to have the class definition in a separate file (Article.rb), but I can't figure out how to do that in the context of my Sinatra app.
Any help would be greatly appreciated!
EDIT:
See my answer below.
After a lot of googling, I discovered that the 1.4 series of json.gem are known to cause a lot of problems. I uninstalled all the json gems I had and installed json-1.2.4.gem instead. I have everything working correctly now. Here's the setup I'm using:
config.ru (Rackup file):
require 'application'
set :environment, :production
set :root, File.dirname(__FILE__)
set :run, false
FileUtils.mkmdir_p 'log' unless File.exists?('log')
log = File.new('log/sinatra.log', 'a+')
$stdout.reopen(log)
$stderr.reopen(log)
run Sinatra::Application
environment.rb:
require 'rubygems'
require 'couchrest'
require 'haml'
require 'ostruct'
require 'sinatra' unless defined?(Sinatra)
configure do
SiteConfig = OpenStruct.new(
:title => 'Application Title',
:author => 'Your Name',
:url_base => 'Your URL',
:url_base_db => 'Your CouchDB Server',
:db_name => "Your DB Name"
)
# load models
$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/lib")
Dir.glob("#{File.dirname(__FILE__)}/lib/*.rb") { |lib| require File.basename(lib, '.*') }
end
lib/contact.rb (Model example, models auto-loaded in environment.rb):
class Contact < CouchRest::ExtendedDocument
include CouchRest::Validation
use_database CouchRest.database!((SiteConfig.url_base_db || '') + SiteConfig.db_name)
property :name
timestamps!
view_by :name
end
application.rb:
require 'rubygems'
require 'sinatra'
require 'environment'
configure do
set :views, "./views"
end
error do
e = request.env['sinatra.error']
Kernel.puts e.backtrace.join("\n")
'Application error'
end
helpers do
end
get '/new/?' do
haml :new
end
post '/save/?' do
#contact_name = params[:contact_name]
#contact = Contact.new
#contact.name = #contact_name
#contact.save
haml :save
end
get '/' do
haml :index
end
Hope this helps someone in the future!
try requiring 'patina' after setting :db. I think the class body of Article is executing the use_database method before the setting exists.
you should be able to put Article in article.rb (ruby naming convention is UpperCamel for classes, but under_scores for the files in which classes are defined) and then require 'article' in patina.rb.
thats the only thing that stood out for me, so let me know if that works.

Resources