Sinatra and Rails - starting a submoduled app - ruby-on-rails

I've been basing an app with a blogging app (octopress) submoduled, on the following guide:
http://www.nickhammond.com/setting-octopress-jekyll-blog-rails-application/
It's a bit out of date but other than having to change around some gems seems to be working fine. The guide suggests having a folder called 'Blog' in your main parent app directory, in which the smaller app lives. Here I was told to change the config.ru file, and rename it to run.rb. The file is as follows:
/blog/run.rb
require 'bundler/setup'
require 'sinatra/base'
# The project root directory
$root = ::File.dirname(__FILE__)
class Blog < Sinatra::Base
get(/.+/) do
send_sinatra_file(request.path) {404}
end
not_found do
send_file(File.join(File.dirname(__FILE__), 'public', '404.html'), {:status => 404})
end
def send_sinatra_file(path, &missing_file_block)
file_path = File.join(File.dirname(__FILE__), 'public', path)
file_path = File.join(file_path, 'index.html') unless file_path =~ /\.[a-z]+$/i
File.exist?(file_path) ? send_file(file_path) : missing_file_block.call
end
end
My config.ru file in my parent app is as follows:
/config.ru
# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment', __FILE__)
require './blog/run'
# Action Cable requires that all classes are loaded in advance
Rails.application.eager_load!
map '/' do
run Rails.application
end
map '/blog' do
run Blog
end
When I visit localhost:3000/blog, I don't get a route not found error, however receive:
This localhost page can’t be found
No web page was found for the web address: http://localhost:3000/blog
Any help on how to properly set up my config.ru file would be greatly appreciated, thanks in advance.

Please try to move
require '/blog/run'
map '/blog' do
run Blog
end
to the routes.rb and see if this helps.
Update: (at the end it said to change your config.ru to this).
require ::File.expand_path('../config/environment', __FILE__)
require './blog/run' # Require the run.rb file that we created earlier which has the Rack setup for the blog
map '/' do # By default we want everything to hit our Rails application
run Rails::Application
end
map '/blog' do # Anything at blog/ and beyond will then hit the blog
run Blog
end
Please give this a try.

Related

undefined local variable or method for method located in lib directory file

I have some code i've inherited and am in the process of upgrading it to Rails 3.1. I'm suuuuper close to done but I got a bug.
In Rails Console I run User.first and I get this error
undefined local variable or method `acts_as_userstamp' for #<Class:0x000000046bef50>
Now acts_as_userstamp is a method located on line two inside my User model
class User < ActiveRecord::Base
#TODO /lib is not loading??? or is it??? why this method not work in browser?
acts_as_userstamp
And is defined in a file called app/lib/model_modifications.rb.
Now I recently discovered that my app/lib folder was not being autoloaded in my application.rb file and I think that's been fixed...or has it? Is this file correct? Or no?
require File.expand_path('../boot', __FILE__)
require 'rails/all'
# evil outdated soap middleware, TODO: kill it with fire
# Does this have to be loaded BEFORE the first line???
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', "vendor", "soap4r"))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', "vendor", "plugins", "soap4r-middleware", "lib"))
# evil outdated soap middleware, TODO: kill it with fire
require 'soap4r-middleware'
require File.join(File.dirname(__FILE__), '..', 'app', 'lib', 'soap.rb')
if defined?(Bundler)
# If you precompile assets before deploying to production, use this line
Bundler.require *Rails.groups(:assets => %w(development test))
# If you want your assets lazily compiled in production, use this line
# Bundler.require(:default, :assets, Rails.env)
end
module MyappDev
class Application < Rails::Application
# startup the lib directory goodies <-- IS THIS CORRECT???
# config.autoload_paths << "#{Rails.root}/lib"
# config.autoload_paths += %W( lib/ )
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = "utf-8"
# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters += [:password]
config.middleware.use MyAPIMiddleware
end
end
I'm trying to debug this file as I post this now. Here is a peak at it's internal structure...(i've just included the overall structure for the sake of brevity)
app/lib/model_modificatons.rb
class Bignum
...
end
class Fixnum
...
end
class ProcessorDaemon
...
end
module ActiveRecord
module UserMonitor
...
end
module MyLogger
...
end
end
class Object
...
end
class Struct
...
end
class String
...
end
class Fixnum
...
end
class OpenStruct
...
end
class ActiveRecord::Base
def self.visible_columns
...
end
...
def self.acts_as_userstamp
logger.info "HI fonso - acts_as_userstamp is called"
include ActiveRecord::UserMonitor
end
...
protected
def self.range_math(*ranges)
...
end
end
class Array
...
end
class DB
...
end
If you can spot a problem with the overall structure or anywhere else please let me know.
So why is this method not found? I'm trying to debug it as I'm posting this and I'm getting nothing.
I suspect the file app/lib/model_modifications.rb is not being loading. That nothing in the /lib directory is being loaded..but how do I confirm this?
Thank you for reading this far, I hope I've not rambled on too much.
autoload_path configuration does not load all the given files on the boot but defines folders where rails will be searching for defined constants.
When your application is loaded, most of the constants in your application are not there. Rails have a "clever" way of delaying loading the files by using a constant_missing method on Module. Basically, when Ruby encounters a constant in the code and fails to resolve it, it executes said method. THe sntandard implementation of this method is to raise UndefinedConstant exception, but rails overrides it to search all of its autoload_paths for a file with a name matching the missing constant, require it and then check again if the missing constant is now present.
So, in your code everything works as expected and you need to load this extension file manually. If you want to have some code that executes on the application boot, put your file within config/initializers folder.
Aside: Try avoiding monkey patching whenever possible. It might be looking clever, but adding more methods to already overpopulated classes will not make them easier to use.

Messenger bot using Rails: setup for multiple pages

I want to create a Messenger Bot used by different users for their Facebook pages. I created a rails app and use the facebook-messenger gem.
I successfully created the bot and it works when I do the set up for one page. Now, I follow the instructions to make my bot live on multiple Facebook Pages (see "Make a configuration provider" section).
I'm new to rails and I'm not sure where to put the class ExampleProvider? I put it in my config/application.rb file:
require_relative 'boot'
require 'rails/all'
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module BotletterApp
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
config.paths.add File.join('app', 'bot'), glob: File.join('**', '*.rb')
config.autoload_paths += Dir[Rails.root.join('app', 'bot', '*')]
end
class BotProvider < Facebook::Messenger::Configuration::Providers::Base
def valid_verify_token?(verify_token)
bot.exists?(verify_token: verify_token)
end
def app_secret_for()
ENV['APP_SECRET']
end
def access_token_for(page_id)
bot.find_by(user_id: page_id).page_access_token
end
private
def bot
MyApp::Bot
end
end
Facebook::Messenger.configure do |config|
config.provider = BotProvider.new
end
end
Then I have my app/bot/setup.rb file to create the bot. I don't know how to use the provider I created in place of the ENV variables?
require "facebook/messenger"
include Facebook::Messenger
Facebook::Messenger::Subscriptions.subscribe(access_token: ENV["ACCESS_TOKEN"])
Facebook::Messenger::Profile.set({
get_started: {
payload: 'GET_STARTED_PAYLOAD'
}
}, access_token: ENV['ACCESS_TOKEN'])
I searched in the Rails documentation how to make it work but unfortunately could not find anything.
UPDATE:
Now I'm able to set up the bots for different pages. Unfortunately, the following line of my ConfigProvider is getting an error:
config/initializers/config_provider.rb
def bot
Rails.application.class.parent::Bot
end
I'm getting the following error:
NameError (uninitialized constant BotletterApp::Bot):
config/initializers/config_provider.rb:17:in bot'
config/initializers/config_provider.rb:7:inapp_secret_for'
Do you know how should I name my app?
My BotModule:
module BotletterApp
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
config.paths.add File.join('app', 'listen'), glob: File.join('**', '*.rb')
config.autoload_paths += Dir[Rails.root.join('app', 'listen', '*')]
end
end
UPDATE, it works with ::Application, here is the new file:
class ConfigProvider < Facebook::Messenger::Configuration::Providers::Base
def valid_verify_token?(verify_token)
ENV['VERIFY_TOKEN']
end
def app_secret_for(page_id)
ENV['APP_SECRET']
end
def access_token_for(page_id)
CoreBot.find_by_page_id(page_id).page_access_token
end
private
def bot
BotletterApp::Application
end
end
Facebook::Messenger.configure do |config|
config.provider = ConfigProvider.new
end
The problem is I get the following error unless my db query seems working (it works in the rails console):
ActiveRecord::StatementInvalid (SQLite3::SQLException: no such column:
page_id.id: SELECT "core_bots".* FROM "core_bots" WHERE
"page_id"."id" = ? LIMIT ?):
Moving to an answer for improved readability ;)
Regarding 'plain'... Instead of
def bot
BotletterApp::Application
end
use
def bot
Bot
end
or (it looks like you named your model containing all pages CoreBot(?) (assuming you have a typical ActiveRecord model in /app/models/core_bot.rb, I was assuming Bot)
def bot
CoreBot
end
Then you should be able to use the template code from the README.md
As for your latest problem: it seems like the access_token_for-method gets called with a hash, searching with something like {id: 1}. You might want to check where that value is coming from. I would suggest to take a few steps back, and stay closer to the template code.

How to add middleware in Rails 4.2 application

I am trying to learn Middlewares and been practising how to mount it in the Rails application. I have followed the railscast
So far I have implemented these steps:
1) Created a new Rails 4.2 application called: Blog
2) Added a file in the lib folder named as response_timer.rb.
class ResponseTimer
def initialize(app)
#app = app
end
def call(env)
[200, {"Content-Type" => "text/html"}, "Hello World"]
end
end
3) Added config.middleware.use "ResponseTimer" in application.rb.
config.middleware.use "ResponseTimer"
But as i'm hitting the command rake middleware in the terminal, it is reporting this error:
rake aborted!
NameError: uninitialized constant ResponseTimer
I tried also to add the config.middleware.use "ResponseTimer" in the development.rb but again facing the same error.
What am i missing here?
Please help.
Referenced article: http://guides.rubyonrails.org/rails_on_rack.html
Middleware has to have an accompanying module / class, and needs to be loaded in the app before it can be referenced. The way to do this in Rails is with autoloading (lib files aren't autoloaded by default):
#config/application.rb
config.autoload_paths += Dir["#{config.root}/lib/**/"]
config.middleware.use "ResponseTimer"
The above should work for you.
I followed this answer: https://stackoverflow.com/a/24122424
I tried it before but maybe missed something before.
In appliation.rb
require 'rails/all'
require_relative '../lib/response_timer'
module Blog
class Application < Rails::Application
...
config.middleware.use ResponseTimer
end
end

Rack Error -- LoadError: cannot load such file

Trying to go through the tekpub rack tutorial but run into this error.
Boot Error
Something went wrong while loading app.ru
LoadError: cannot load such file -- haiku
There is a file named haiku.rb in the same directory as the app I am trying to run but I get the above error while trying to run the program. Here is the code:
class EnvironmentOutput
def initialize(app=nil)
#app = app
end
def call(env)
out = ""
unless(#app.nil?)
response = #app.call(env)[2]
out+=response
end
env.keys.each {|key| out+="<li>#{key}=#{env[key]}</li>"}
["200",{"Content-Type" => "text/html"},[out]]
end
end
require 'haml'
require 'haiku'
class MyApp
def call(env)
poem = Haiku.new.random
template = File.open("views/index.haml").read
engine = Haml::Engine.new(template)
out = engine.render(Object.new, :poem => poem)
["200",{"Content-Type" => "text/html"}, out]
end
end
use EnvironmentOutput
run MyApp.new
I'm sure its a small error as the code is the same as in the tutorial and it works for him...
Thanks
You'll want to read up on ruby load path (either $LOAD_PATH or $:). By default, ruby has a load path which includes wherever your gems are installed, which is why you can do require 'haml' without providing the full path to where your haml gem is located.
When you type require 'haiku', you're basically telling ruby to look for some file called haiku.rb somewhere in it's load path, and the LoadError comes from ruby not finding your haiku.rb file in any of the directories listed in $LOAD_PATH (or $:, which is just shorthand for $LOAD_PATH).
You can solve this in one of (at least) two ways:
change require 'haiku' to require File.dirname(__FILE__) + '/haiku.rb' to explicitly tell ruby what file to load
add the current working directory to your load path: $:.push(File.dirname(__FILE__)). This way you can keep the require 'haiku' part.

Why is my Rails.root nil?

I'm trying to reference Rails.root in my application.rb but it is nil, why is that?
I can explain why, but I can't give you a workaround.
Rails.root is defined in rails/railties/lib/rails.rb
def root
application && application.config.root
end
In application.rb, the instance of application is not yet created, because the Application class is being defined... The application is only initialized after, in environment.rb:
# Load the rails application
require File.expand_path('../application', __FILE__)
# Initialize the rails application
Testapp::Application.initialize!
EDIT
The workaround is right before our eyes:
my_rails_root = File.expand_path('../..', __FILE__)
Are you using Rails 3.x? If not, you should be using RAILS_ROOT rather than Rails.root.
I had the same issue when I tried to use it before the module and class declaration. Try using it inside and see if that makes a difference e.g.
module MyApp
class Application < Rails::Application
puts Rails.root
end
end

Resources