i have the following sinatra code, how do i do the equivalent but for a rails app? specifically, want to start rails with thin inside the reactor loop, while also using a websocket server in there too.
require 'bundler'
Bundler.require
class App < Sinatra::Base
get '/' do
slim :index
end
end
EM.run do
EM::WebSocket.start(:host => '0.0.0.0', :port => 3001) do |ws|
# websocket stuff goes here
end
# start sinatra in a thin server instance here (but i want to start a rails app instead)
Thin::Server.start App, '0.0.0.0', 3000
end
I'd setup an initializer like config/initializers/websocket.rb with this:
EM.next_tick do
EM::WebSocket.start(:host => '0.0.0.0', :port => 3001) do |ws|
# websocket stuff goes here
end
end
Also, add gem 'thin' to the Gemfile and start the server simply with $ rails s. When the EM reactor starts, the queued next_tick block will be called and the websocket server starts running.
You could also put the websocket code in some file in lib/ and start it through an initializer, might be cleaner.
Related
I'm using Predictor gem and when I attempt to start the gem shows:
"redis not configured! - Predictor.redis = Redis.new" (RuntimeError)
So, how to configure Redis Connection on initialize?
thank's
This is how Redis is initialized in general.
Firstly, a good practice would be adding this to your config/environments/[environment_name].rb. So you can maintain different locations for Redis when you change environments.
config.redis_host = "localhost"
Then in your application's config/initializers path create redis.rb and place the code below to initialize Redis.
require 'redis'
## Added rescue condition if Redis connection is failed
begin
$redis = Redis.new(:host => Rails.configuration.redis_host, :port => 6379)
rescue Exception => e
puts e
end
Then you'll be able to use the global variable $redis within your application for Redis-related commands.
$redis.hset "my_hash", item.id, business.id
Here is a helpful article with more details.
Now in your case as this documentation suggests, here is what you should do:
In config/initializers/predictor.rb,
Predictor.redis = Redis.new(:url => ENV["PREDICTOR_REDIS"])
Or, to improve performance, add hiredis as your driver (you'll need to install the hiredis gem first)
Predictor.redis = Redis.new(:url => ENV["PREDICTOR_REDIS"], :driver => :hiredis)
Then, be sure to include include Predictor::Base in all models you want to use it,
class CourseRecommender
include Predictor::Base
...
end
Here is the code responsible for the error you getting.
I am trying to start Faye when starting my rails server. I have a faye.ru file in my app root that looks like:
require 'faye'
faye_server = Faye::RackAdapter.new(:mount => '/queue-listener', :timeout => 45)
run faye_server
And whenever I start my rails server, Faye / thin tries to open on the same port as my rails server. I can add something like:
Thread.new do
system("rackup faye.ru -s thin -E production")
end
into an initializer (found this on SO), but then thin starts on both the rails app port and then the default (9292) port. I think it fails to start on the rails port though. I am just confused about how to start up the thin / faye server on a separate port than the rails server. Any ideas?
You can do the following in development. In production I suggesting implementing it as a standalone server w/monitoring:
if Rails.env.development?
require 'eventmachine'
require 'rack'
require 'thin'
require 'faye'
Faye.logger = Logger.new(Rails.root.join('log/faye.log'))
Faye::WebSocket.load_adapter('thin')
thread = Thread.new do
EM.run {
thin = Rack::Handler.get('thin')
app = Faye::RackAdapter.new(mount: '/faye', timeout: 10)
thin.run(app, :Port => 8000) do |server|
## Set SSL if needed:
# server.ssl_options = {
# :private_key_file => 'path/to/ssl.key',
# :cert_chain_file => 'path/to/ssl.crt'
# }
# server.ssl = true
end
}
end
at_exit { thread.exit }
end
I am writing a rails app which requires to track users' status to see if they are available, busy or offline. I'm using the private_pub gem, which uses Faye underneath. When a user signs in he subscribes to a channel /user/[:user_id]. I want to update user's status to ONLINE when they subscribe using Faye's subscribe event listener. I added this code at the end of private_pub.ru file:
server = PrivatePub.faye_app
server.bind :subscribe do |client_id, channel|
if /\/user\/*/.match(channel)
m = /\/user\/(?<user_id>\d+)/.match(channel)
user_id = m[:user_id]
end
user = User.find(user_id)
user.status = 1 # 1 means online
end
run server
The problem is every time a user subscribes, thin server reports:
[ERROR] [Faye::RackAdapter] uninitialized constant User
I guess I need to require certain files to be able to use activerecords in the rackup file. But I don't know how.
Thanks for any help.
In our project we decide to use redis for similar case.
Gemfile:
gem 'redis-objects'
Faye: use redis-rb for writing status
require 'redis'
Redis.current = Redis.new(:host => '127.0.0.1', :port => 6379)
# init faye server
...
server.bind(:subscribe) do |client_id, channel|
if /\/user\/*/.match(channel)
m = /\/user\/(?<user_id>\d+)/.match(channel)
Redis.current.set("user:#{m[:user_id]}:online_status", "1")
end
end
Rails: use redis-objects gem for reading it in User's model.
class User < ActiveRecord::Base
include Redis::Objects
value :online_status
end
#user.online_status # returns "1" if channel is connected
Hope this helps.
Does anyone know of a way to run the ruby debugger and SSL at the same time with Thin?
I've been using Thin successfully with Rails 3.0.10.
I start it using rails server --debugger, and I can debug my code.
Recently, I have also needed to add SSL support to my application, and I'd like to be able to test it locally with a self-signed certificate.
Unfortunately, I have not found a way to start Thin with SSL support when using rails server.
I can successfully start Thin with SSL support by using:
thin start --ssl --ssl-verify --ssl-key-file ssllocal/server.key
--ssl-cert-file ssllocal/server.crt
However, I have not found a way to activate the debugger using thin start.
So it seems like I have the choice of running the debugger (rails server) or SSL (thin start), but not both.
It seems possible to get Webrick to run SSL using rails server by modifying the rails/script file (see here). I experimented with this approach, but I have not had success. Here's one of the attempts:
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails 3
# gems installed from the root of your application.
APP_PATH = File.expand_path('../../config/application', __FILE__)
require File.expand_path('../../config/boot', __FILE__)
# THIS IS NEW:
require "rails/commands/server"
require 'rack'
require 'thin'
module Rails
class Server
def default_options
super.merge({
:Port => 3000,
:environment => (ENV['RAILS_ENV'] || "development").dup,
:daemonize => false,
:debugger => false,
:pid => File.expand_path("tmp/pids/server.pid"),
:config => File.expand_path("config.ru"),
:SSLEnable => true
:ssl => true,
"ssl-verify" => true,
"ssl-key-file" => File.expand_path("ssllocal/server.key"),
"ssl-cert-file" => File.expand_path("ssllocal/server.crt")
})
end
end
end
require 'rails/commands'
Note: for those who might be wondering, I created an 'ssllocal' directory off my root application directory, and that's where I store the ssl keys and certs.
You could try just requiring the debugger yourself in your development environment.
In your Gemfile:
if RUBY_VERSION =~ /^1.9/
gem "ruby-debug19", :group => :development
else
gem "ruby-debug", :group => :development
end
And within the config block of your config/environments/development.rb:
require 'ruby-debug'
Debugger.start
This permits you to place the debugger statement anywhere in your code.
Here's my solution - I hacked the Thin TcpServer to load my self-signed SSL certs, only in the development environment. My script/rails looks like this:
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
APP_PATH = File.expand_path('../../config/application', __FILE__)
require File.expand_path('../../config/boot', __FILE__)
# Hack our SSL certs into Thin TcpServer, only in development environment
require 'thin'
module Thin
module Backends
TcpServer.class_eval do
def initialize_with_SSL(host, port)
if Rails.env.development?
Rails.logger.info "Loading SSL certs from ./ssl_dev..."
#ssl = true
#ssl_options = {
:private_key_file => File.expand_path("../../ssl_dev/server.key", __FILE__),
:cert_chain_file => File.expand_path("../../ssl_dev/server.crt", __FILE__),
:verify_peer => nil
}
end
initialize_without_SSL(host, port)
end
alias_method :initialize_without_SSL, :initialize
alias_method :initialize, :initialize_with_SSL
end
end
end
# Must load 'rails/commands' after Thin SSL hack
require 'rails/commands'
Here's how I got it to finally work on production using Thin:
rvmsudo thin start -p 443 --ssl --ssl-key-file ssl/server.key --ssl-cert-file ssl/server.crt
If you are having issues with your KEY file, make sure you validate the CSR by using a site like:
https://ssl-tools.verisign.com
If your CSR fails, then the certificate you receive from your signing authority will fail too.
My site would refuse to load with the SSL certs, only to find out that I abbreviated my State name to "TX" instead of "Texas" while creating my private key. That was the reason it wasn't working all along! SSL certs are a pain in the ass!
I was able to successfully get the debugging working with ssl enabled thin, using the solution suggested by nathan. Though I had to do one small change of deferring initialization of #ssl after the call of initialize_without_ssl (an alias method for the original TcpServer's initialize)
require 'thin'
module Thin
module Backends
TcpServer.class_eval do
def initialize_with_SSL(host, port)
if Rails.env.development?
Rails.logger.info "Loading SSL certs from ./ssl_dev..."
#ssl_options = {
:private_key_file => File.expand_path("../../ssl_dev/server.key", __FILE__),
:cert_chain_file => File.expand_path("../../ssl_dev/server.crt", __FILE__),
:verify_peer => nil
}
end
initialize_without_SSL(host, port)
# #ssl initialized after calling the original initialize of TcpServer
#ssl = true if Rails.env.development?
end
alias_method :initialize_without_SSL, :initialize
alias_method :initialize, :initialize_with_SSL
end
end
end
alias_method :initialize_without_SSL, :initialize
alias_method :initialize, :initialize_with_SSL
end
In the above code snippett, #ssl is set to true after calling the original initialize call of Thin::Backend::TcpServer. I had to do this since the TcpServer invokes its parent's initialize (Thin::Backend:Base) that sets the #ssl to nil
#Base initialize method. Thin gem version 1.5.0
def initialize
#connections = []
#timeout = Server::DEFAULT_TIMEOUT
#persistent_connection_count = 0
#maximum_connections = Server::DEFAULT_MAXIMUM_CONNECTIONS
#maximum_persistent_connections = Server::DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS
#no_epoll = false
#ssl = nil
#threaded = nil
end
As noted in nathan's code block, the whole solution appears to be a hack around. In my opinion, I am fine with the snippet considering the code is done within the context of env.development and most importantly it allows debugging with ssl enabled.
On my development machine, I use port 10524. So I start my server this way :
rails s -p 10524
Is there a way to change the default port to 10524 so I wouldn't have to append the port each time I start the server?
First - do not edit anything in your gem path! It will influence all projects, and you will have a lot problems later...
In your project edit script/rails this way:
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
APP_PATH = File.expand_path('../../config/application', __FILE__)
require File.expand_path('../../config/boot', __FILE__)
# THIS IS NEW:
require "rails/commands/server"
module Rails
class Server
def default_options
super.merge({
:Port => 10524,
:environment => (ENV['RAILS_ENV'] || "development").dup,
:daemonize => false,
:debugger => false,
:pid => File.expand_path("tmp/pids/server.pid"),
:config => File.expand_path("config.ru")
})
end
end
end
# END OF CHANGE
require 'rails/commands'
The principle is simple - you are monkey-patching the server runner - so it will influence just one project.
UPDATE: Yes, I know that the there is simpler solution with bash script containing:
#!/bin/bash
rails server -p 10524
but this solution has a serious drawback - it is boring as hell.
I like to append the following to config/boot.rb:
require 'rails/commands/server'
module Rails
class Server
alias :default_options_alias :default_options
def default_options
default_options_alias.merge!(:Port => 3333)
end
end
end
One more idea for you. Create a rake task that calls rails server with the -p.
task "start" => :environment do
system 'rails server -p 3001'
end
then call rake start instead of rails server
Combining two previous answers, for Rails 4.0.4 (and up, presumably), this suffices at the end of config/boot.rb:
require 'rails/commands/server'
module Rails
class Server
def default_options
super.merge({Port: 10524})
end
end
end
We're using Puma as a web server, and dotenv to set environment variables in development. This means I can set an environment variable for PORT, and reference it in the Puma config.
# .env
PORT=10524
# config/puma.rb
port ENV['PORT']
However, you'll have to start your app with foreman start instead of rails s, otherwise the puma config doesn't get read properly.
I like this approach because the configuration works the same way in development and production, you just change the value of the port if necessary.
Inspired by Radek and Spencer...
On Rails 4(.0.2 - Ruby 2.1.0 ), I was able to append this to config/boot.rb:
# config/boot.rb
# ...existing code
require 'rails/commands/server'
module Rails
# Override default development
# Server port
class Server
def default_options
super.merge(Port: 3100)
end
end
end
All other configuration in default_options are still set, and command-line switches still override defaults.
Solution for Rails 2.3 - script/server:
#!/usr/bin/env ruby
require 'rack/handler'
module Rack::Handler
class << WEBrick
alias_method :old_run, :run
end
class WEBrick
def self.run(app, options={})
options[:Port] = 3010 if options[:Port] == 3000
old_run(app, options)
end
end
end
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/server'
If you're using puma (I'm using this on Rails 6+):
To change default port for all environments:
The "{3000}" part sets the default port if undefined in ENV.
~/config/puma.rb
change:
port ENV.fetch('PORT') { 3000 }
for:
port ENV.fetch('PORT') { 10524 }
To define it depending on the environment, using Figaro gem for credentials/environment variable:
~/application.yml
local_db_username: your_user_name
local_db_password: your_password
PORT: 10524
You can adapt this to you own environment variable manager.
You could install $ gem install foreman, and use foreman to start your server as defined in your Procfile like:
web: bundle exec rails -p 10524
You can check foreman gem docs here: https://github.com/ddollar/foreman for more info
The benefit of this approach is not only can you set/change the port in the config easily and that it doesn't require much code to be added but also you can add different steps in the Procfile that foreman will run for you so you don't have to go though them each time you want to start you application something like:
bundle: bundle install
web: bundle exec rails -p 10524
...
...
Cheers
For ruby > 3 and For rails > 7
in file app/config/puma.rb, update the port number.
port ENV.fetch("PORT") { 3200 }