Candy for MongoDB - ruby

I'm currently experimenting with Sinatra and MongoDB (through the Candy gem). I love the Candy coding style, but I'm having a few issues when I try to retrieve all of the Post objects. Here's my code:
require 'rubygems'
require 'sinatra'
require 'candy'
require 'haml'
Candy.db = "Miroir"
class Post
include Candy::Piece
end
class Posts
include Candy::Collection
collects :post
end
get '/' do
#posts = Posts.all
haml :index
end
When it renders index.haml, all I get is Post (4d0ac53d9b6d4202a3000001){}, and I can't retrieve any of the data. The haml is:
!!! 5
%html
%body
%strong Posts
%ul
- #posts.each do |post|
%li= post
How can I iterate the titles of the posts in the ul? Appreciate the help.

There is a bug in Candy that requires you refresh the object before it'll populate the data when you do a find using a collection.
Do it like so:
- #posts.each do |post|
post.refresh
%li= post

Related

How to display results from database in Sinatra using Sequel?

I have an SQLite3 database called sk.db with a table called Sked that displays a schedule of sports matches with a column date. I am simply trying to display today's matches. It appears as though the connection to the database is not working, though I do not get any errors.
I have tried looking through the Sequel documentation to no avail. How can I display results from an existing database in Sinatra?
.rb
require 'date'
require 'sequel'
require 'sinatra'
DB = Sequel.connect("sqlite://sk.db")
class Sked < Sequel::Model
end
schedule = DB.from(:sked)
get '/' do
todaymatches = schedule.where(:date => Date.today)
erb :games
end
.erb
<h1>Games</h1>
<p><%= #todaymatches %></p>
.where doesn't actually retrieve data, but instead returns a dataset. Add an .all to actually retrieve the data
todaymatches = schedule.where(:date => Date.today).all

How to map routes to controllers in Sinatra?

I'd like to create a simple experimental MVC framework using Sinatra.
I'd like to define resources by name "pages" for example should resolve to:
/pages (index)
/pages/new
/pages/:id/show (show)
as WELL as map to app/controllers/PagesController.rb with corresponding get('/') to be responsible for the index, post('/pages/create') be responsible for creation, etc.
Trouble is even after reading the official documentation I'm terribly confused. I imagine I need to use non-classic Sinatra model for this, but could anyone point me in the right direction?
Thank you
If you want what I think you're wanting, I do this all the time. Initially for this scheme I used the travis-api source as a reference, but essentially what you want to do is extend Sinatra::Base in a "controller" class and then mount up your individual Sinatra "controllers" in rack, something like this:
module Endpoint
def self.included(base)
base.class_eval do
set(:prefix) { "/" << name[/[^:]+$/].downcase }
end
end
end
class Users < Sinatra::Base
include Endpoint
get '/' do
#logic here
end
get '/:id' do
#logic here
end
post '/' do
#logic here
end
patch '/:id' do
#logic here
end
end
class Posts < Sinatra::Base
include Endpoint
post '/' do
#logic here
end
end
and then something like this:
class App
require "lib/endpoints/users"
require "lib/endpoints/posts"
attr_reader :app
def initialize
#app = Rack::Builder.app do
[Users, Posts].each do |e|
map(e.prefix) { run(e.new) }
end
end
end
def call(env)
app.call(env)
end
end
You can adjust this to whatever you need, but the idea is the same, you separate your app into composable Sinatra applications that each have a prefix that they are mounted under using Rack. This particular example will give you routes for:
get '/users'
get '/users/:id'
post '/users'
patch '/users/:id'
get '/posts'
I'll give you a very simple example here:
Create a file controller.rb
get '/pages' do
#pages = Pages.all
erb :pages
end
Next create a views directory in the same folder as teh controller, and create a file named pages.html.erb
This is the corresponding view to your previously created controller action.
Here, you can type something like:
<% #pages.each do |p| %>
<%= p.title %>
<% end %>
Restart your server, visit localhost:PORT/pages and you will see a list of all your page titles.
You can check out this link for a simple sinatra tutorial - http://code.tutsplus.com/tutorials/singing-with-sinatra--net-18965
You can make this as complicated or as simple as you need. For example:
Rails makes a lot of magic happen under the hood, whereas Sinatra is more flexible at the cost of requiring you to implement some of this stuff yourself.
controller_map = {
'pages' => PagesController
}
post '/:controller/new' do
c = params[:controller]
module = controller_map[c]
module.create_new()
...
end
get '/:controller/:id/show' do
c = params[:controller]
id = params[:id]
module = controller_map[c]
module.get(id)
...
end

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

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.

Call Sinatra erb from another class

I need to render a Sinatra erb template inside a class in my controller. I'm having issues calling this though. I've looked in the Sinatra rdocs and have come up with this:
Sinatra::Templates.erb :template_to_render
When I do this, I get the following error:
undefined method `erb' for Sinatra::Templates:Module
Is there a way to call this from another class?
To imitate rendering behavior of Sinatra controller in some other class (not controller) you can create module like this:
module ErbRender
include Sinatra::Templates
include Sinatra::Helpers
include Sinatra::ContentFor
def settings
#settings ||= begin
settings = Sinatra::Application.settings
settings.root = "#{ROOT}/app"
settings
end
end
def template_cache
#template_cache ||= Tilt::Cache.new
end
end
Here you may need to tune settings.root
Usage example:
class ArticleIndexingPostBody
include ErbRender
def get_body
erb :'amp/articles/show', layout: :'amp/layout'
end
end
This will properly render templates with layouts including content_for
why you don't require 'erb' and after use only erb
## You'll need to require erb in your app
require 'erb'
get '/' do
erb :index
end
You could have your class return the template name and render it in the main app.
Of course that's not exactly an answer (I don't have enough rep to add a comment with this account) and you're probably doing just that by now anyway...

Resources