Configure Redis connection on initialize - ruby-on-rails

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.

Related

Rails: patch ActionCable (add new adapter)

Question refers to this pull request: https://github.com/rails/rails/pull/23211
Since it has not been merged yet, I want to monkey patch this into my application.
I put this subscription adapter to lib/core_extenstions/subsctiption_adapter/test.rb
Now, in initialize monkey_patch.rb I try:
#require 'lib/action_cable/test.rb'
#autoload ActionCable::SubscriptionAdapter::Test
module ActionCable
module SubscriptionAdapter
puts Rails.root.join('lib/core_extensions/action_cable/test.rb').inspect
autoload :Test, Rails.root.join('lib/core_extensions/action_cable/test.rb')
puts Test.inspect
end
end
Then:
MacBook-Pro-Vaceslav:mvp_c slava$ bundle exec rails c test
Running via Spring preloader in process 93788
Loading test environment (Rails 5.0.2)
irb: warn: can't alias context from irb_context.
irb(main):001:0> server = ActionCable.server
=> #<ActionCable::Server::Base:0x007f890e812628 #mutex=#<Monitor:0x007f890e812600 #mon_owner=nil, #mon_count=0, #mon_mutex=#<Thread::Mutex:0x007f890e8125b0>>, #pubsub=nil, #worker_pool=nil, #event_loop=nil, #remote_connections=nil>
irb(main):002:0> server.pubsub
LoadError: Could not load 'action_cable/subscription_adapter/test'. Make sure that the adapter in config/cable.yml is valid. If you use an adapter other than 'postgresql' or 'redis' add the necessary adapter gem to the Gemfile.
So source of issue is here:
https://github.com/rails/rails/blob/master/actioncable/lib/action_cable/server/configuration.rb
def pubsub_adapter
adapter = (cable.fetch("adapter") { "redis" })
path_to_adapter = "action_cable/subscription_adapter/#{adapter}"
begin
require path_to_adapter
rescue Gem::LoadError => e
raise Gem::LoadError, "Specified '#{adapter}' for Action Cable pubsub adapter, but the gem is not loaded. Add `gem '#{e.name}'` to your Gemfile (and ensure its version is at the minimum required by Action Cable)."
rescue LoadError => e
raise LoadError, "Could not load '#{path_to_adapter}'. Make sure that the adapter in config/cable.yml is valid. If you use an adapter other than 'postgresql' or 'redis' add the necessary adapter gem to the Gemfile.", e.backtrace
end
adapter = adapter.camelize
adapter = "PostgreSQL" if adapter == "Postgresql"
"ActionCable::SubscriptionAdapter::#{adapter}".constantize
end
Not sure how to workaround this.
This is quite bad I suppose, but don't see any other way with this implementation other than:
module ActionCable
module Server
class Configuration
def pubsub_adapter
if Rails.env == 'test'
require Rails.root.join('lib/core_extensions/action_cable/test.rb')
ActionCable::SubscriptionAdapter::Test
else
super
end
end
end
end
end
Any improvements are welcome.
EDIT
possibly much better way is to stub it needed test suits:
before do
ActionCable.server.instance_variable_set(:#pubsub, ActionCable::SubscriptionAdapter::Test)
end

How to use eventmachine, rails, and websockets?

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.

Update activerecords in faye event listeners

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.

Thin with SSL support and ruby-debug

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.

Database.yml configuration options

I would like to know where I can read about valid configuration options for database.yml for ActiveRecord. I know the basic ones like adapter, database, username, password, etc., but I would like to have the full list for each adapter. Where would I find that?
I found a gist of database.yml examples using mysql, postgres, and sqlite3, and the Rails 3.2 source code for connection adapters provides good insight as well.
Looks to me that the following are the most widely used options:
adapter
encoding
database
pool
username
password
socket
host
port
timeout
The Rails 3.2 connection_specification.rb file looks like it simply merges any options you include, so I'd say what options you include are dependant on the database adapter you choose to use (lines 58-74):
def connection_url_to_hash(url) # :nodoc:
config = URI.parse url
adapter = config.scheme
adapter = "postgresql" if adapter == "postgres"
spec = { :adapter => adapter,
:username => config.user,
:password => config.password,
:port => config.port,
:database => config.path.sub(%r{^/},""),
:host => config.host }
spec.reject!{ |_,value| !value }
if config.query
options = Hash[config.query.split("&").map{ |pair| pair.split("=") }].symbolize_keys
spec.merge!(options)
end
spec
end

Resources