Ruby Sinatra Session Management Available in Class Methods? - ruby

Just wondering if the scope of a session is manageable inside a custom object. I'm getting the following error while trying to set a session variable inside a method for a user:
undefined local variable or method `session' for #<User:0x007fd6f4117ba0>
file: user.rb location: log_in line: 315
Would be nice to be able to toss session management inside methods instead of the routes. Using Sinatra's sessions:
enable :sessions

Maybe you should enable sessions first in your class service.
enable :sessions
set :session_secret
....

Related

Passing headers (or other settings) from Sinatra through Puma

I am trying to learn how to develop a simple web app using pure Ruby. I have a simple backend service which I created as a Sinatra app. While developing it, I noticed the frontend (a simple HTML/JS static site) would not communicate with it because of CORS policies. So I looked into how to pass headers from Sinatra.
I came across sinatra-cors. I set it up as instructed and my app looks like this (abbreviated):
require 'sinatra'
require 'sinatra/cors'
set :allow_origin, '*'
set :allow_methods, 'GET,HEAD,POST'
set :allow_headers, 'content-type,if-modified-since,access-control-allow-methods,access-control-allow-origin'
set :expose_headers, 'content-disposition'
set :allow_credentials, true
post '/' do
[...]
end
When I run it with ruby app.rb, it works perfectly. Frontend can communicate and CORS policies are observed.
Now, I want to set up the service for a production environment. For that, I want to use Puma. So with Puma, I have a config.ru which looks like this:
require File.expand_path('app', File.dirname(__FILE__))
run WebApp
and I modified my app.rb to look like this (again abbreviated):
require 'sinatra'
require 'sinatra/cors'
class WebApp < Sinatra::Application
set :allow_origin, '*'
set :allow_methods, 'GET,HEAD,POST'
set :allow_headers, 'content-type,if-modified-since,access-control-allow-methods,access-control-allow-origin'
set :expose_headers, 'content-disposition'
set :allow_credentials, true
post '/' do
[...]
end
end
basically, wrapped the app in a class, and call it from the config.ru. When I run this by running puma in the directory, the service comes up, but headers are no longer passed back. Whenever I try to hit the backend, I get:
Access to XMLHttpRequest at 'http://localhost:4567/' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
This was the error I was getting before I originally set up the headers. So it seems pretty clear to me that the set parameters are being ignored.
So, this seems like a simple matter, but I have not been able to find a proper answer: How do I make Puma respect the 'set' parameters? Or alternatively, how do I achieve the same desired result?
It seems clear to me that I am missing a very simple thing, but I cannot figure out what exactly it is.
Thanks in advance!
It looks like you are just missing register Sinatra::Cors in your class.
class WebApp < Sinatra::Application
register Sinatra::Cors # Add this line.
set :allow_origin, '*'
# etc.

Rails 4: Helper method for Devise mailer views throws undefined method exception sometimes

In order to use a custom helper method in the mailers, I had to define a module and created a method as follows,
# app/helpers/mailer_helper.rb
module MailerHelper
def format_email_template
# body..
end
end
And then I had to tell Devise to use this helper module. After some research, I found one solution that it should be mentioned as follows in the config/initializers/devise.rb file,
# config/initializers/devise.rb
# Already exists
Devise.setup do |config|
# Some configuration settings
end
# I added this
# If I don't add this, helper methods are not at all available in the mailer views
Devise::Mailer.class_eval do
helper :mailer
end
This works fine and I could use a helper method in the devise mailer views.
But the problem is that it sometimes throws an error Undefined method :format_email_template for view class. Then I had to restart my local server to make it work. This happens very frequently.
Why this is happening in development server (WEBrick)?
Note:- This works find in production box. But I am bit worried if it could appear in production also.
Undefined method :format_email_templage for view class
Maybe the problem is your typo (format_email_templage)? Please check it again in your source code!
Try using:
helper :mailer
in your custom mailer class as suggested here: https://github.com/plataformatec/devise/wiki/How-To:-Use-custom-mailer

Difference in cookie content using Sinatra session & Rack::Session::EncryptedCookie

I'm learning Sinatra framework & developing a login system. I came across two ways of using cookies.
A simple Sinatra inbuilt way:
enable :sessions
set :session_secret, 'random-key'
This approach produces following cookie content while logged in (used session.inspect to get the output):
{"session_id"=>"6be0b9a31831604ba51114d265ba952482e0b2da6ced6c54e15ebe7f212858ca",
"tracking"=>{"HTTP_USER_AGENT"=>"b8c1e8f89eeaea0b825bed0d811f0c7678e98c74",
"HTTP_ACCEPT_ENCODING"=>"a0bfc876d68fe7aea700da5ea8925abac6f2f794",
"HTTP_ACCEPT_LANGUAGE"=>"dd065ed263c67d799f943ab6c39b55c5e008cbb5"},
"csrf"=>"b480324f510e4f391d15cee8236a8fb74a5aaa5ce2f9ad38e4dbb025a823b16e",
"name"=>"john"}
Another approach is using an encrypted cookie :
require 'sinatra'
require 'encrypted_cookie'
use Rack::Session::EncryptedCookie, :secret => "random-key"
But this approach produces following cookie content while logged in (used session.inspect here too):
{:name=>"john"}
Why enable :sessions is creating such a big cookie with all that information & why is it required (especially those HTTP_... parts?) Because Rack::Session::EncryptedCookie isn't generating any of it.
Do you think that using enable :sessions should be preferred because it has csrf token & session id? Or do you think that Rack::Session::EncryptedCookie is enough since it is encrypted?
I have following versions of gems installed :
encrypted_cookie (0.0.4)
rack (1.5.2)
rack_csrf (2.4.0)
sinatra (1.4.3)
thin (1.5.1)
Please tell me if you need more information...
Because Sinatra will use rack-protection middleware when you enable :sessions. It makes cookie bigger but more secure.
Relevant snippet:
def setup_default_middleware(builder)
builder.use ExtendedRack
builder.use ShowExceptions if show_exceptions?
builder.use Rack::MethodOverride if method_override?
builder.use Rack::Head
setup_logging builder
setup_sessions builder
setup_protection builder
end
def setup_sessions(builder)
return unless sessions?
options = {}
options[:secret] = session_secret if session_secret?
options.merge! sessions.to_hash if sessions.respond_to? :to_hash
builder.use session_store, options
end
def setup_protection(builder)
return unless protection?
options = Hash === protection ? protection.dup : {}
options = {
img_src: "'self' data:",
font_src: "'self'"
}.merge options
protect_session = options.fetch(:session) { sessions? }
options[:without_session] = !protect_session
options[:reaction] ||= :drop_session
builder.use Rack::Protection, options
end
sessions? returns true if you enable :sessions
session_store is Rack::Session::Cookie by default
The difference between Rack::Session::EncryptedCookie
That is, if you want to use Rack::Session::EncryptedCookie with rack-production, it can be easily done by:
enable :sessions
set :session_store, Rack::Session::EncryptedCookie
FYI, since encrypted_cookie is lack of some features (secret rotation, custom serializer, etc) and no longer under maintenance, I made another one to replace it.
Hope it helps.
Because Rack::Session::EncryptedCookie requires that your secret be at least 16 bits long. In the README, they recommend using OpenSSL for generating the secret, like so:
ruby -ropenssl -e "puts OpenSSL::Random.random_bytes(16).inspect"
If you open your inspector, you'll see a cookie named 'rack.session', and its contents obfuscated.
As I know, when using Rack::Session::Cookie in Sinatra, and write session_secret as an environment variable, the session which has created won't destroy after the project deploy. I think this is a risk in Single Page Application.

How do I set/get session vars in a Rack app?

use Rack::Session::Pool
...
session[:msg]="Hello Rack"
EDIT: The word session doesn't seem to resolve. I included the Session pool middleware in my config.ru, and try to set a variable in an ERB file (I'm using Ruby Serve) and it complains "undefined local variable or method `session'"
Thanks!
session is a method that is part of some web frameworks, for example Sinatra and Rails both have session methods. Plain rack applications don’t have a session method, unless you add one yourself.
The session hash is stored in the rack env hash under the key rack.session, so you can access it like this (assuming you’ve named the rack environment to your app env):
env['rack.session'][:msg]="Hello Rack"
Alternatively, you could use Rack’s built in request object, like this:
request = Rack::Request.new(env)
request.session[:msg]="Hello Rack"
You need to load rack::session module next probably cookie like here
http://rack.rubyforge.org/doc/classes/Rack/Session/Cookie.html
This like explains it with example.

From Sinatra Base object. Get port of application including the base object

I have a Sinatra::Base object that I would like to include in all of my web apps. In that base class I have the configure method which is called on start-up.
I would like that configure code to 'register' that service with a centralized database. The information that needs to be sent when registering is the information on how to contact this web-service... things like host and port.
I then plan on having a monitoring service that will spin over all registered services and occasionally ping them to make sure they are still up and running.
In the configure method I am having trouble getting the port information. The 'self.settings.port' variable doesn't seem to work in this method.
a) any ideas on how to get the port? I have the host.
b) is there a sinatra plug-in that already does something like this so I don't have to write it myself? :-)
//in my Sinatra::Base code. lets call it register_me.rb
RegisterMe < Sinatra::Base
configure do
//save host and port information to database
end
get '/check_status'
//return status
end
//in my web service code
require register_me //at this point, sinatra will initialize the RegisterMe object and call configure
post ('/blah')
//example of a method for this particular web service
end
Sinatra::Application.port will return the correct port

Resources