How to set authentication in Sinatra? - ruby

I need simple authentication for blog. For a single person. Just login to the website
Can't configure sinatra_warden. Write the line
require 'rubygems'
require 'sinatra'
require 'pry-byebug'
require "sinatra/activerecord"
require "carrierwave"
require "carrierwave/orm/activerecord"
require 'sinatra_warden'
require 'warden'
register Sinatra::Warden
use Rack::Session::Pool
in app.rb, but I get an error
NoMethodError: undefined method `register' for main:Object
the gem sinatra_warden has installed. as well written require "warden" & require "sinatra_warden"
sinatra_warden 0.3.2
warden 1.2.6
When I add the authorize! method in controller, I get an error
undefined method `authorize!'

Because you didn't use the sinatra/base you should add sinatra/namespace. Add to your app.rb this require require "sinatra/namespace".
Sinatra::Namespace is an extension that adds namespaces to an
application. This namespaces will allow you to share a path prefix for
the routes within the namespace, and define filters, conditions and
error handlers exclusively for them. Besides that, you can also
register helpers and extensions that will be used only within the
namespace.
Or change your application to the modular style:
require "sinatra/base"
class MyApp < Sinatra::Base
register Sinatra::Warden
# The rest of your modular application code goes here...
end

Related

Define sinatra request routes in included files

I am using Sinatra and I would like to have my project structed in a way that keeps all requests for a specific action in separated files.
The problem I'm running into is that the routes aren't registered with sinatra, and it always 404s and runs my not_found handler, even though I've included a file with the route.
Here's an example of what I'm trying to achieve; Rackup would start the Info app which requires user and post. Info only contains a error and not found handler, and the related routes go in the corresponding required file.
config.ru:
require 'rubygems'
require 'bundler'
Bundler.require
require 'rack'
require './info.rb'
run Info
info.rb:
require 'rubygems'
require 'bundler'
require 'sinatra'
class Info < Sinatra::Base
require './user.rb'
require './post.rb'
# 500 handler
error StandardError do
status 500
content_type :json
return '{"error": "Internal server error", "code": 500}'
end
not_found do
status 404
content_type :json
return '{"error": "Page not found", "code": 404}'
end
end
And user.rb (post.rb would look the same):
require 'rubygems'
require 'bundler'
require 'sinatra'
get '/1/user/:userid' do
# request stuff
end
require doesn’t work the way you seem to think it does. When you call require './user.rb', even though you do it inside the body of class Info < Sinatra::Base, its contents are not loaded as if they were inside that class. Instead they are parsed at the top level, and the routes are added to the default Sinatra::Application and not your application class.
You will have to have your user and post routes defined inside the same class body:
#info.rb
require 'sinatra/base' # Require 'sinatra/base' if you are using modular style.
class Info < Sinatra::Base
# It's a bit unusual to have require inside a class, but not
# wrong as such, and you might want to have the class defined
# before loading the other files.
require_relative 'user.rb' # require_relative is probably safer here.
require_relative 'post.rb'
# ... error handlers etc.
end
#user.rb
require 'sinatra/base'
# The routes need to be in the same class.
class Info < Sinatra::Base
get '/1/user/:userid' do
# request stuff
end
end

Monkey Patching Mongoid models contained in a Ruby gem

I have a Ruby gem which gets used across multiple projects that contains some Mongoid models.
I'm currently trying to reuse them in a project and monkey patch some extra methods. However, when I require the project and run the tests. I get a NoMethodError. Any ideas where I'm going wrong?
Here's my main project file:
require 'bundler'
Bundler.require(:default)
require 'mongoid-elasticsearch'
Mongoid::Elasticsearch.prefix = ENV["MONGOID_ENVIRONMENT"]
require 'mongoid_address_models/require_all' # This is where I include my gem
Mongoid.load!(File.join(File.dirname(__FILE__), "..", "config", "mongoid.yml"), ENV["MONGOID_ENVIRONMENT"] || :development)
# Here are my monkey patched models
require 'models/street'
require 'models/locality'
require 'models/town'
require 'models/postcode'
require 'sorting_office/address'
module SortingOffice
end
And this is an example of one of the monkey patched models
class Postcode
REGEX = /([A-PR-UWYZ01][A-Z01]?[0-9IO][0-9A-HJKMNPR-YIO]\s?[0-9IO][ABD-HJLNPQ-Z10]{2})/i
def self.calculate(address)
postcode = UKPostcode.new(address.match(REGEX)[0])
where(name: postcode.norm).first
end
end
When I call Postcode.calculate(address) (for example), I get a NoMethodError
I think I've nailed this now. Rather than putting the monkey patch inside lib/models, I moved them to lib/sorting_office/models and required them like so:
require 'sorting_office/models/street'
require 'sorting_office/models/locality'
require 'sorting_office/models/town'
require 'sorting_office/models/postcode'
I'd still be interested to know WHY this worked though

Ruby URI module oddness in modular Sinatra app

I'm having trouble using the Ruby URI module's encode_www_form method in a modular Sinatra app. For some reason, URI is interpreted as being the URI::Parser subclass, and so the method call understandably fails.
I've reduced this to a minimal test case. The Gemfile:
source 'https://rubygems.org'
ruby '1.9.3'
gem 'sinatra'
And app.rb:
require 'sinatra/base'
class Frontend < Sinatra::Base
get '/test/' do
URI.encode_www_form(:a => 1, :b => 2)
end
run! if app_file == $0
end
If I then run ruby app.rb and access /test/ I get:
NoMethodError - undefined method `encode_www_form' for #<URI::Parser:0x007fa9221ca868>:
app.rb:6:in `block in <class:Frontend>'
If I convert it to a classic-style Sinatra app, so that app.rb is like this:
require 'sinatra'
get '/test/' do
URI.encode_www_form(:a => 1, :b => 2)
end
Then call ruby app.rb and access /test/, the page shows "a=1&b=2" as desired.
So what's going wrong in the modular format that means something's up with URI?
The class Sinatra::Base redefines URI on line 856 of https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb, which is why your URI reference gets evaluated as that value.
If you want to avoid this problem, you can change your reference to ::URI.
As of Sinatra 1.4.4, the URI module is no longer overwritten.
I tried to reproduce this in irb. This may sound stupid, but require 'uri' did the trick there.

Sinatra commands do not work in modules

I have a Sinatra app which requires a module in a different file. When I use Sinatra commands in that module (e.g. redirect "http://facebook.com"), I get a NoMethodError. To illustrate the problem, I have made a simplified version:
--- mainapp.rb ---
#config
require './redirector.rb'
get '/' do
Redirector::redirect_to_stackoverflow
end
--- redirector.rb ---
module Redirector
require 'sinatra'
def self.redirect_to_stackoverflow
redirect "http://stackoverflow.com"
end
end
--- config.ru ---
require 'rubygems'
require 'sinatra'
require File.dirname(__FILE__) + "/ptt.rb"
run Sinatra::Application
What is wrong? Is there a place where I haven't required something properly?
The call to redirect inside the Redirector module is sent to the Redirector Module object, where the method does not exist. require 'sinatra' inside module Redirector is not necessary, and does not do any kind of method composition.
You probably could compose Sinatra methods into your Redirector module, but that is not normal practice. Usually it's the other way around - you write "helper" modules that are composed in to your Sinatra application in various ways.
This is a similar example application, with a more usual approach to composition:
app.rb
require 'sinatra'
require_relative 'redirect.rb'
class MyApp < Sinatra::Application
include Redirector
get '/' do
redirect_to_stackoverflow
end
end
redirect.rb
module Redirector
def redirect_to_stackoverflow
redirect "http://stackoverflow.com"
end
end
config.ru
require File.dirname(__FILE__) + "/app.rb"
run MyApp
#Neil Slater's explanation is correct, but I'd suggest you also make it an Sinatra extension, e.g.
require 'sinatra/base'
module Sinatra
module Redirector
def redirect_to_stackoverflow
redirect "http://stackoverflow.com"
end
end
helpers Redirector
end
Then (for a classic app) all you need to do is require it.
require 'sinatra/redirector'
get "/" do
redirect_to_stackoverflow
end

Sinatra Helper in External File gives LoadError

I'm trying to add a helper to connect to a mongo db to my modular Sinatra application
When I type foreman start in my console I get:
/home/sunny/Programs/landing_pages/app.rb:17:in `block in <class:LandingPages>': undefined local variable or method `connect' for LandingPages:Class (NameError)
My app.rb file looks like this:
require 'sinatra/base'
require 'sinatra/partial'
require 'sinatra/db_helper'
require 'bundler/setup'
require 'mongo'
class LandingPages < Sinatra::Base
helpers Sinatra::DbHelper
configure do
$collection = connect
end
end
My ./lib/sinatra/db_helper.rb looks like this:
require 'sinatra/base'
module Sinatra
module DbHelper
def connect
conn = Mongo::Connection.new("localhost")
db = conn.db("leads")
db.collection("laws")
end
end
helpers DbHelper
end
My config.ru looks like this:
require './app'
run LandingPages
I thought I was following the instructions correctly on:
http://www.sinatrarb.com/extensions.html
but I'm not totally sure. I'm not making a gem but just a sinatra app so maybe my directory hierarchy isn't correct. I don't have a rake file or a gem spec. Do I need them?
Some googling also found this:
sinatra helper in external file
Dave Sag answers my question perfectly but I can't get it work.
This comes about because of the scope of methods created through the helpers is on the sinatra application instance, since it calls ruby's include under the hood. So this would work:
get '/some/route' do
db = connect
# do something else ...
end
But the configure block has a class scope, so it can be used for configuring the application as a whole. So to make this work, you can define the method as:
module Sinatra
module DbHelper
def self.connect
conn = Mongo::Connection.new("localhost")
db = conn.db("leads")
db.collection("laws")
end
end
end
which could then be called via: $collection = Sinatra::DbHelper.connect or perhaps more favoured, you could call register instead of helpers. register calls extend under the hood, so you end up with class level methods (if you extend a class, anyway). You could then make the configure block as so:
configure do |app|
$collection = app.connect
end
You could also do all of this in an registered method on the DbHelpers module. See the example in the documentation for how this might work.

Resources