"require if" in Ruby - ruby

Here is what I have in my rack app
#rb file
require 'pry'
class .....
#GemFile
group :development do
gem "pry"
gem "pry-nav"
end
Of course, in production it causes an error. How do make a kind of "require if"?

require 'pry' if ENV['RACK_ENV'] == 'development'

May be you can embed it inside a if block
according to docs Sinatra provides a environment variable
http://www.sinatrarb.com/intro#Environments
if development?
require 'pry'
end
wherever you need to use it.
this may not be the exact solution you may be looking for just a wild guess

I suggest to write such method in Object or Kernel in your app:
def require_pry
require 'pry' if ENV['RACK_ENV'] == 'development'
end
After that you can call require_pry if you need it in your code. But I have doubts why it cannot be handled by Bundler, Bundle.require will require all gems needed for environment.

Related

Sinatra app has session issues in production

I've been working on a web application in Ruby using Sinatra. While in development, I really never had a lot of issues with sessions. However, now i'm ussing passenger to actually deploy the application I have quite a lot of issues regarding that session data keeps getting 'reset'.
I've seen other stack overflow questions related to this problem but no answer has yet fixed it for me. I've tried a couple of things:
Putting 'use Rack::Session::Pool' inside config.ru as suggested here
Used Rack::Session::Pool like explained here
Tried Memcache as explained here
Tried Redis-Rack (gives me an error: Exception NoMethodError in Rack application object (undefined method `foreign_key' for nil:NilClass))
Nothing seems to be helping really... I either end up having an error or my session gets reset each request. I know that passenger probably uses multiple threads and that that is the cause for the sessions to not be working, but I cannot seem to find a solution to the problem.
Am I missing something obvious here? Any suggestions?
Gemfile
source "https://rubygems.org"
gem 'mongo', '1.8.6'
gem 'sinatra', '1.4.8'
gem 'mongo_mapper'
gem 'bson_ext'
gem 'active_model_serializers'
gem 'activemodel-serializers-xml'
gem 'sinatra-flash'
gem 'sinatra-param', require: 'sinatra/param'
gem 'rack-recaptcha2', git: 'https://github.com/nicolas-simplex/rack- recaptcha'
gem 'mail'
gem 'slugify'
gem 'biz'
gem 'bcrypt'
gem 'redis-rack'
group :development do
gem 'mailcatcher', '~> 0.6.4'
end
config.ru
It had different forms depending on if I used just Rack::Session::Pool, Memcache or Redis. This one was the one I used for redis:
require 'rubygems'
require 'sinatra'
require File.expand_path '../app.rb', __FILE__
require 'rack'
require 'rack/session/redis'
require_relative './app'
app = App.new
sessioned = use Rack::Session::Redis.new(app)
run sessioned
App.rb
require 'rubygems'
require 'bundler/setup'
require 'sinatra'
require 'slugify'
class App < Sinatra::Base
use Rack::Protection
set :bind, '0.0.0.0'
end
require_relative './config/init' # Initialize configuration files
require_relative './helpers/init' # Initialize helpers
require_relative './routes/init' # Initialize routes
require_relative './models/init' # Initialize models
require_relative './util/tokens' # Token utility
... # Some database seeding, basic setup for some data I use
TL;DR
Sinatra and Passenger together resets sessions in production, while this doesn't happen in development.
After some more researching I found the configuration option passenger_sticky_sessions. Because in my web application session storage is quite important, this works fine for me. However, the use of this is not recommended in all use cases because all the clients sends will be routed to the same originating application process.
Documentation: https://www.phusionpassenger.com/library/config/nginx/reference/#passenger_sticky_sessions
With this configuration parameter 'on' in my conf file in nginx/sites-enabled, I was able to just use the simple rack session pool:
use Rack::Session::Pool, path: '/', expire_after: 2592000

Rails 4 - Remove all traces of a previously used Active Record database [duplicate]

I want to disable ActiveRecord in Rails 4. I did the following in config/application.rb
require File.expand_path('../boot', __FILE__)
# require 'rails/all' -- commented
require "action_controller/railtie"
require "action_mailer/railtie"
#require "active_resource/railtie" no need
#require "rails/test_unit/railtie" no need
#require "sprockets/railtie" no need
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(:default, Rails.env)
module MyApp
class Application < Rails::Application
config.app_middleware.delete "ActiveRecord::ConnectionAdapters::ConnectionManagement"
end
end
By I have an error of
/home/alex/.rvm/gems/ruby-2.0.0-p247/gems/railties-4.0.0/lib/rails/railtie/configuration.rb:95:in
method_missing: undefined method active_record for #<Rails::Application::Configuration:0x00000002005c38> (NoMethodError)
If you are creating a new application, you can use -O to skip ActiveRecord:
rails new my_app -O
For existing applications:
1. Remove database adapter gems from your Gemfile (mysql2, sqlite3, etc.)
2. Change your config/application.rb
Remove require 'rails/all line and require frameworks (among those available in your rails version, the list varies, do not just copy) you want to use, for example:
require "action_controller/railtie"
require "action_mailer/railtie"
require "sprockets/railtie"
require "rails/test_unit/railtie"
Remove config.active_record.raise_in_transactional_callbacks = true from config/application.rb
3. Delete your config/database.yml file, db/schema.rb and migrations (if any)
4. Delete migration check in test/test_helper.rb
5. Delete any ActiveRecord configuration from your config/environments files (this is what is causing your error)
This is all you need to do for an empty Rails app. If you run into problems caused by your existing code, stack trace should give you sufficient information on what you need to change. You might for example have some ActiveRecord configuration in your initializers.
Hi this is what the default rails new new_app -O gives
require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
# require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_view/railtie"
require "sprockets/railtie"
require "rails/test_unit/railtie"
inside your config/application.rb
Additionally, it comes without database.yml and NO db/migrate/* and schema.rb
Since this is still the first hit when searching Google for disabling active record for Rails 5, I'll add this here:
For Rails 5
Do all the steps in #mechanicalfish answer, but also remove the line
Rails.application.config.active_record.belongs_to_required_by_default = true
from
config/initializers/new_framework_defaults.rb
For those using the rails-api gem you may encounter a similar error when using the --skip-active-record flag when doing rails-api new my_api. The current fix (until a new corrected version of the gem is released) is to edit your rails-api gem to have this commit. Use bundle open and replace the old Gemfile with the new corrected one. Rerun and you should be all set.
For disable ActiveRecord in Rails 4.2 you may create config/initializers/middleware.rb
Rails.application.middleware.tap do |middleware|
middleware.delete ActiveRecord::Migration::CheckPending
middleware.delete ActiveRecord::ConnectionAdapters::ConnectionManagement
middleware.delete ActiveRecord::QueryCache
end
See the terminal rake middleware
For Rails 5:
If you are generating a new app
Use --skip-active-record option to generate an application without a database:
rails new myApp --skip-active-record
Notice the extra hyphen '-' as opposed to previous versions of Rails.
For Rails Plugins (or gems) with a spec/dummy app
When your rails app lives in spec/dummy and you start your server from the plugin-root directory. You might still getting following error:
Cannot load `Rails.application.database_configuration`: Could not load database configuration. No such file - ["config/database.yml"]
To avoid this, remove require rails/all inside the file bin/rails and require frameworks you want to use, for example:
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
# require "active_record/railtie"
require "action_cable/engine"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_view/railtie"
require "sprockets/railtie"
require "rails/test_unit/railtie"
For Ruby On Rails version 5.1.x
require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
# require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_view/railtie"
require "action_cable/engine"
require "sprockets/railtie"
require "rails/test_unit/railtie"

how to not require certain gems/lines of code in production that I need in development

I am not writing in Rails. It is just ruby.
But I have a dev environment that has it's own development group in the Gemfile.
But I don't use them in production on Iron.io.
In particular, I use "log_buddy" and have lots of d {var} statements throughout.
And I use pry which has a require pry and require-debug statement.
These statements create errors in the case of pry and duplicate logging in the case of log_buddy when the code runs in production.
How do I make a distinction between the two environments?
I have read about dotenv and some other gem, but didn't quite understand how it would work in my scenario.
If you have just yes/no scenario for dev, dotenv family is an overkill. I would go with surrounding dev requirements with:
if ENV['DEV']
require 'pry'
...
end
and then run development scenarios as:
DEV=true bundle exec ...
Since DEV env variable is not defined on your prod server, nothing will be included there.
Init for log_buddy might look like:
LogBuddy.init(ENV['DEV'] ? {:logger => Logger.new('my_log.log')} : nil)
Not using Rails does not prevent you from using Bundler groups:
# These gems are in the :default group
gem 'nokogiri'
gem 'sinatra'
gem 'wirble', :group => :development
group :test do
gem 'faker'
gem 'rspec'
end
group :test, :development do
gem 'capybara'
gem 'rspec-rails'
end
gem 'cucumber', :group => [:cucumber, :test]
Then you have to get the environment name in any way you deem reasonable:
bundler_env = whatever # could be ENV['ENVIRONMENT'], for instance
bundler_env ||= :production # Specify a fallback if none specified
And once you're done, require the gems:
Bundler.require(:default, bundler_env)

Sinatra + Bundler?

I'm wondering how one can use Bundler with Sinatra. The idea is to use the gems that Bundler downloads inside the .gems folder.
Inside your Sinatra app, you just have to require the bundler setup:
require "bundler/setup"
require "sinatra"
get "/" do
"Hello world!"
end
Alternatively, if you don't want to add the additional require "bundler/setup" at the top of your app, you can instead invoke sinatra via bundle exec (e.g. bundle exec ruby myapp.rb)
This assumes that you have a Gemfile in the root of your application. It might look like this:
source "http://rubygems.org"
gem "sinatra"
This also assumes that you've already installed bundler (gem install bundler) and that you ran bundle install to install all the gem dependencies.
I believe the best way is described here on EngineYard blog:
# This makes sure the bundled gems are in our $LOAD_PATH
require File.expand_path(File.join(File.dirname(__FILE__), 'vendor', 'gems', 'environment'))
# This actually requires the bundled gems
Bundler.require_env
class MyApp < Sinatra::Base
# stuff
end
As my original answer was quite old but there seems to be still attention to this topic here's the latest version of bundler/sinatra setup which will cover most of the use case:
A minimal config.ru
require './my_sinatra_app'
run MySinatraApp
An environment env.rb file that requires all the bundled gems (also supports loading the current environment's group):
require 'bundler/setup'
APP_ENV = ENV["RACK_ENV"] || "development"
Bundler.require :default, APP_ENV.to_sym
Then your app file (requiring the environment) with your sinatra app (Sinatra::Base):
require_relative 'env'
class MyApp < Sinatra::Base
get "/" do
"hello world"
end
end
Start your development server with rackup, and Sinatra will be loaded via Bundler, your app will be accessible from http://localhost:9292.
$ rackup
or bundle exec rackup if needed
Make sure you have a Gemfile like the following one and you run the bundle command before starting the app
source "https://rubygems.org"
gem "sinatra"
gem "puma" # a better rack server than the default webrick
+1 for the guide on the bundler website, but if you have a simple app and use Sinatra's dsl at the top level, then you need to do the following:
in your Gemfile (tell bundler not require sinatra):
gem 'sinatra', :require => false
and in the app's file (explicitly require sinatra):
require 'rubygems'
require 'bundler'
Bundler.require
require 'sinatra'
get '/' do
'hello world'
end
To use bundler with a Sinatra application, you only need to do two things. First, create a Gemfile.
gem 'sinatra'
Then, set up your config.ru file to load the bundle before it loads your Sinatra app.
require 'rubygems'
require 'bundler'
Bundler.require
require './my_sinatra_app'
run MySinatraApp
Start your development server with rackup, and Sinatra will be loaded via Bundler.
rackup
source bundler docs

Deploying Sinatra app on Dreamhost/Passenger with custom gems

I've got a Sinatra app that I'm trying to run on Dreamhost that makes use of pony to send email. In order to get the application up and running at the very beginning (before adding pony), I had to gem unpack rack and gem unpack sinatra into the vendor/ directory, so this was my config.ru:
require 'vendor/rack/lib/rack'
require 'vendor/sinatra/lib/sinatra'
set :run, false
set :environment, :production
set :views, "views"
require 'public/myapp.rb'
run Sinatra::Application
I have already done gem install pony and gem unpack pony (into vendor/). Afterwards, I tried adding require 'vendor/sinatra/lib/pony' to config.ru only to have Passenger complain about pony's dependencies (mime-types, tmail) not being found either!
There has to be a better way to use other gems and tone down those long, ugly, redundant requires. Any thoughts?
I'd recommend creating your own gem path "somewhere" then adding it in your config.ru
like:
ENV['GEM_PATH'] = xxx
Gem.clear_paths
then install your gems into that
Install Ruby gems on dreamhost
https://c.kat.pe/installing-ruby-gems-on-dreamhost
Change config.ru (works for Sinatra 1.0)
require 'rubygems'
require 'vendor/sinatra/lib/sinatra.rb'
ENV['GEM_HOME'] = '/home/username/.gems'
ENV['GEM_PATH'] = '$GEM_HOME:/usr/lib/ruby/gems/1.8'
require 'rubygems'
Gem.clear_paths
disable :run, :reload
set :environment, :production
require 'yourapp'
run Sinatra::Application
Hope it helps someone.
I am using pony and a lot of other gems for my Sinatra. It should work well for you too. It's just those two lines (GEM_HOME and GEM_PATH) you have to add on your config.
It took me ages to find that you can simply use "gem install sinatra" and gem will figure out (because the system directories are read-only) that you will need to use a local gem install directory. As of now, there seems to be no need to set any special environment at all. It figures out to use $HOME/.gem as the local gem path and everything just works. No need for require 'vendor/stuff' at all. I did find I had to add $HOME/.gem/ruby/1.8/bin to my path in order to execute binaries installed by gems.
Here's my config.ru (for Dreamhost)
## Passenger should set RACK_ENV for Sinatra
require 'test'
set :environment, :development
run Sinatra::Application
Later edit: This is all well and fine, but there remains the issue that Passenger can't find my gems when the job initially starts up.
My config.ru is just simple as:
require 'rubygems'
require 'vendor/sinatra/lib/sinatra.rb'
require 'app.rb'
and app.rb head:
require 'yaml'
require 'haml'
require 'ostruct'
require 'date'
require 'pp'
module FlytoFB
log = File.new("sinatra.log", "a")
STDOUT.reopen(log)
STDERR.reopen(log)
configure do
enable :logging, :dump_errors
set :app_file, __FILE__
set :reload, true
set :root, File.dirname(__FILE__)
set :environment, :production
set :env, :production
set :run, false
set :raise_errors, true
set :public, 'public'
error do
e = request.env['sinatra.error']
puts e.to_s
puts e.backtrace.join("\n")
"Application Error!"
end
not_found do
"Page not found!"
end

Resources