I am looking at this boot.rb file:
http://github.com/bestbuyremix/BBYIDX/blob/master/config/boot.rb
And after trying to understand it, it is as if I have learned nothing so far.
Can someone detail what is going on here?
I have no idea how someone could even come up with this?
# Don't change this file!
# Configure your app in config/environment.rb and config/environments/*.rb
RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
module Rails
class << self
def boot!
unless booted?
preinitialize
pick_boot.run
end
end
def booted?
defined? Rails::Initializer
end
def pick_boot
(vendor_rails? ? VendorBoot : GemBoot).new
end
def vendor_rails?
File.exist?("#{RAILS_ROOT}/vendor/rails")
end
def preinitialize
load(preinitializer_path) if File.exist?(preinitializer_path)
end
def preinitializer_path
"#{RAILS_ROOT}/config/preinitializer.rb"
end
end
class Boot
def run
load_initializer
Rails::Initializer.run(:set_load_path)
end
end
class VendorBoot < Boot
def load_initializer
require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
Rails::Initializer.run(:install_gem_spec_stubs)
end
end
class GemBoot < Boot
def load_initializer
self.class.load_rubygems
load_rails_gem
require 'initializer'
end
def load_rails_gem
if version = self.class.gem_version
gem 'rails', version
else
gem 'rails'
end
rescue Gem::LoadError => load_error
$stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
exit 1
end
class << self
def rubygems_version
Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion
end
def gem_version
if defined? RAILS_GEM_VERSION
RAILS_GEM_VERSION
elsif ENV.include?('RAILS_GEM_VERSION')
ENV['RAILS_GEM_VERSION']
else
parse_gem_version(read_environment_rb)
end
end
def load_rubygems
require 'rubygems'
min_version = '1.1.1'
unless rubygems_version >= min_version
$stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)
exit 1
end
rescue LoadError
$stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org)
exit 1
end
def parse_gem_version(text)
$1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/
end
private
def read_environment_rb
File.read("#{RAILS_ROOT}/config/environment.rb")
end
end
end
end
# All that for this:
Rails.boot!
If you are learning Rails, this is not the place to do it. Perhaps you have the thought that in order to use it, you need to understand how the code flows from the beginning? Don't do that. :)
If you're learning rails, use any of the many guides and tutorials to build a basic site.
As for this bit of code, some concepts that it employs involve ruby's iconic class << self Here is a critical read on meta classes: http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/
The Rails.boot! at the bottom leads you to the conclusion "the method boot! is called on the object Rails ... going back up to the top, you see
module Rails
class << self
def boot!
unless booted?
preinitialize
pick_boot.run
end
end
...
Here you can see the magic behind class << self ... it created the boot! method on the module itself. from there you can trace the method call throughout the file, as it checks for the existence of a preinitializer file...
pick_boot returns an object, either VendorBoot or GemBoot depending on the result of vendor_rails? and then call the run method on it.
From there you have some standard class inheritance of the Boot classes, as it sets up the rest of the libraries. Hopefully that gets you started. :)
This is actually very good OO style... small methods and classes that all do a simple task. There's also OO inheritance and several common ruby idioms. All in all, a very good bit of ruby code. :)
Update
Here's a rough estimate of how it would look if coded in a more procedural style:
RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
unless defined? Rails::Initializer
preinitializer_path = "#{RAILS_ROOT}/config/preinitializer.rb"
load() if File.exist?(preinitializer_path)
if File.exist?("#{RAILS_ROOT}/vendor/rails")
require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
Rails::Initializer.run(:install_gem_spec_stubs)
Rails::Initializer.run(:set_load_path)
else
begin
require 'rubygems'
min_version = '1.1.1'
rubygems_version = Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion
unless rubygems_version >= min_version
$stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)
exit 1
end
rescue LoadError
$stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org)
exit 1
end
begin
if defined? RAILS_GEM_VERSION
version = RAILS_GEM_VERSION
elsif ENV.include?('RAILS_GEM_VERSION')
version = ENV['RAILS_GEM_VERSION']
else
version = $1 if (File.read("#{RAILS_ROOT}/config/environment.rb")) =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~=]*\s*[\d.]+)["']/
end
if version
gem 'rails', version
else
gem 'rails'
end
rescue Gem::LoadError => load_error
$stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
exit 1
end
require 'initializer'
end
end
What this is really doing is a bunch of fancy footwork to determine where the rails source code is.
You have the ability to 'freeze' your current rails gem source code into the vendor directory. This is useful when you might have more than one version of rails installed and want to make sure that your application is developed and run with that version only.
This code is checking to see if a version of rails has been frozen into the vendor directory, and if so, use that. If a frozen version isn't available it tries to use the local gems, but first makes sure they meet a minimum version requirement.
For more information on 'freezing' your gems, look at the descriptions of the rake tasks availble to your project with "rake -T".
Related
As a personal project, I decided to write a minified-version of Ruby on Rails and upload it as a gem using Bundle called railz_lite.
Inside of my project, I was hoping to implement a Generator similar to rails new, which would create the necessary folders for a web app i.e. controllers/, views/, models/, etc.
To do so, I included Thor as a dependency, then created the following files:
require 'thor/group'
module RailzLite
module Generators
class Project < Thor::Group
include Thor::Actions
def self.source_root
File.dirname(__FILE__) + "/templates"
end
def add_controllers
empty_directory("controllers")
end
def add_models
empty_directory("models")
end
def add_server
template("server.rb", "config/server.rb")
end
def add_views
empty_directory("views")
end
def add_public
empty_directory("public")
end
end
end
end
Inside the gem project's root folder, when I run bundle exec railz_lite new, the generator works just fine and the necessary files are created.
However, if I create a new project, puts my gem (railz_lite) in the Gemfile, run bundle install, then execute bundle exec rails_lite new, I am greeted with the following error:
.rbenv/versions/2.5.1/lib/ruby/2.5.0/fileutils.rb:232:in `mkdir':
: Read-only file system # dir_s_mkdir - /controllers (Errno::EROFS)
I suspect the error is because the empty_directory command is not referring to the root directory of the project I just created. I am hoping that there is a simple way to fix this.
For further reference, the CLI script and class look as follows:
railz_lite
#!/usr/bin/env ruby
require 'railz_lite/cli'
RailzLite::CLI.start
cli.rb
require 'thor'
require 'railz_lite'
require 'railz_lite/generators/project'
module RailzLite
class CLI < Thor
desc 'new', 'Generates a new RailzLite project'
def new
RailzLite::Generators::Project.start([])
end
end
end
Any solutions would be greatly appreciated!
Note: I am running this on macOS Catalina.
So I found a solution after searching extensively through gem forums and looking at the Rails source code.
Inside of the generation I have to manually set the destination_root to the working directory of the project. The working directory can be found with Dir.pwd
require 'thor/group'
module RailzLite
module Generators
class Project < Thor::Group
include Thor::Actions
def self.source_root
File.dirname(__FILE__) + "/templates"
end
def self.destination_root # this method fixes the problem!
Dir.pwd # get the current project directory
end
def add_controllers
empty_directory("controllers")
end
def add_models
empty_directory("models")
end
def add_server
template("server.rb", "config/server.rb")
end
def add_views
empty_directory("views")
end
def add_public
empty_directory("public")
end
end
end
end
It's possible, for example, to use ActiveRecord inline in a Ruby script. I like this a lot to report bugs, test features and share gists.
I'm wondering if the same could be done for a Rails webservice? (I'm mainly interested in getting the controller layer to work, the rest should be easy to add on demand.) Something along these lines:
begin
require "bundler/inline"
rescue LoadError => e
$stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler"
raise e
end
gemfile(true) do
source "https://rubygems.org"
gem 'rails', '~> 6.0.0'
end
require 'rails/commands'
APP_PATH = File.expand_path('config/application', __dir__)
Rails::Command.invoke('server')
When toying around with this it did seem that an external entry point (APP_PATH) is required. So alternatively, an acceptable approach would be to cram all config into the single entry point. I couldn't get this to work so far.
The Rails Initialization Process is the best resource I found about this so far.
I produced a minimal Rails app to get started as follows:
rails new min-rails --skip-keeps --skip-action-mailer --skip-action-mailbox --skip-action-text --skip-active-record --skip-active-storage --skip-puma --skip-action-cable --skip-sprockets --skip-spring --skip-listen --skip-javascript --skip-turbolinks --skip-test --skip-system-test --skip-bootsnap --api
cd min-rails
rm -rf app/jobs app/models config/initializers config/locales lib log public tmp vendor config/environments/test.rb config/environments/production.rb config/credentials.yml.enc config/master.key bin/rake bin/setup bin/bundle
I ended up with the following script:
inline-rails.rb
begin
require "bundler/inline"
rescue LoadError => e
$stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler"
raise e
end
gemfile(true) do
source "https://rubygems.org"
gem 'rails', '~> 6.0.0'
end
require "action_controller/railtie"
class App < Rails::Application
routes.append do
get "/hello/world" => "hello#world"
end
config.consider_all_requests_local = true # display errors
end
class HelloController < ActionController::API
def world
render json: {hello: :world}
end
end
App.initialize!
Rack::Server.new(app: App, Port: 3000).start
Run it as:
ruby inline-rails.rb
I'm writing an upgrade generator for my gem and I want it to check if my gem is installed. That's not a problem, but if the gem is not installed I want to terminate the rest of the methods.
Here is my code so far:
module Baco
module Generators
class UpgradeGenerator < Rails::Generators::Base
def check_installation
unless File.exists?( File.join( destination_root, "config", "initializers", "baco.rb" ) )
p "Baco not yet installed. Please run 'rails generate baco:install' to install"
# Here the generator needs to stop everything!
end
end
def next_method
# We don't want this if the gem is not installed!
end
end
end
end
Anybody can point me to the right method to use?
I believe you can raise an Error, and that should stop the generator.
Im trying to test my rails applications javascript using jruby 1.3.1,celerity and culerity.
The application itself runs under ruby 1.8.7 + phusion passenger (and runs fine, sans test :))
Everything installation-wise works fine but my app uses some_enumerable.each_slice(10) to split a larger array into smaller subarray with 10 elelents each.
Celerity need jruby and jruby is only ruby 1.8.6 compatible and therefor doesnt support a blockless each_slice.
So I'm thinking about defining an initalizer which adds this functionality if RUBY_PLATFORM == "java " (or RUBY_VERSION < 1.8.7)
This far I got (defunct code of cause):
if true #ruby 1.8.6
module Enumerable
alias_method :original_each_slice, :each_slice
def each_slice(count, &block)
# call original method in 1.8.6
if block_given?
original_each_slice(count, block)
else
self.enum_for(:original_each_slice, count).to_a
end
end
end
end
This code obviously is not working and I would really appreciate someone pointing me to a solution.
Thanks!
Update:
Solution thanks to sepp2k for pointing me to my errors:
if RUBY_VERSION < "1.8.7"
require 'enumerator'
module Enumerable
alias_method :original_each_slice, :each_slice
def each_slice(count, &block)
if block_given?
# call original method when used with block
original_each_slice(count, &block)
else
# no block -> emulate
self.enum_for(:original_each_slice, count)
end
end
end
end
original_each_slice(count, block) should be original_each_slice(count, &block).
Also if you leave out the to_a, you'll be closer to the behaviour of 1.8.7+, which returns an enumerator, not an array.
(Don't forget to require 'enumerator' btw)
checkout the 'backports' gem :)
Ok, so I have a Rails app set up on DreamHost and I had it working a while ago and now it's broken. I don't know a lot about deployment environments or anything like that so please forgive my ignorance. Anyway, it looks like the app is crashing at this line in config/environment.rb:
require File.join(File.dirname(__FILE__), 'boot')
config/boot.rb is pretty much normal, but I'll include it here anyway.
# Don't change this file!
# Configure your app in config/environment.rb and config/environments/*.rb
RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
module Rails
class << self
def boot!
unless booted?
preinitialize
pick_boot.run
end
end
def booted?
defined? Rails::Initializer
end
def pick_boot
(vendor_rails? ? VendorBoot : GemBoot).new
end
def vendor_rails?
File.exist?("#{RAILS_ROOT}/vendor/rails")
end
def preinitialize
load(preinitializer_path) if File.exist?(preinitializer_path)
end
def preinitializer_path
"#{RAILS_ROOT}/config/preinitializer.rb"
end
end
class Boot
def run
load_initializer
Rails::Initializer.run(:set_load_path)
end
end
class VendorBoot < Boot
def load_initializer
require "#{RAILS_ROOT}/vendor/rails/railties/lib/initializer"
Rails::Initializer.run(:install_gem_spec_stubs)
end
end
class GemBoot < Boot
def load_initializer
self.class.load_rubygems
load_rails_gem
require 'initializer'
end
def load_rails_gem
if version = self.class.gem_version
gem 'rails', version
else
gem 'rails'
end
rescue Gem::LoadError => load_error
$stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
exit 1
end
class << self
def rubygems_version
Gem::RubyGemsVersion if defined? Gem::RubyGemsVersion
end
def gem_version
if defined? RAILS_GEM_VERSION
RAILS_GEM_VERSION
elsif ENV.include?('RAILS_GEM_VERSION')
ENV['RAILS_GEM_VERSION']
else
parse_gem_version(read_environment_rb)
end
end
def load_rubygems
require 'rubygems'
min_version = '1.1.1'
unless rubygems_version >= min_version
$stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)
exit 1
end
rescue LoadError
$stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org)
exit 1
end
def parse_gem_version(text)
$1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/
end
private
def read_environment_rb
File.read("#{RAILS_ROOT}/config/environment.rb")
end
end
end
end
# All that for this:
Rails.boot!
Does anyone have any ideas? I am not getting any errors in the log or on the page.
-fREW
I had the same problem on DreamHost. Freezing rails and unpacking all gems got me past it.
rake rails:freeze:gems
rake gems:unpack:dependencies
My guess would be that you're breaking because of a newer version of the Rails gems on Dreamhost. At least, that's been my issue when things have blown up in something like boot.rb.
Try freezing the gems from your development environment into your vendor/rails directory.
Ya - the problem is not really in boot.rb - it's just that boot.rb is where rails is actually loaded.
So you'll get an error like this if you've specified a version of Rails that just doesn't exist on your dreamhost slice. This can happen if you either upgrade your project, start a new project (and forget that you upgraded rails in the meanwhile) or if you're still using an old version of rails and it's now been removed from the dreamhost server that you're on.
To figure out which is is, look in config/environment.rb for the line that'll read something like:
RAILS_GEM_VERSION = '2.3.4' unless defined? RAILS_GEM_VERSION
Then ssh to your dreamhost server and type gem list and see if your version is in the list.
If not, you an try several options. Lets say the version you're using is 2.3.4
To begin with, try: gem install rails -v=2.3.4 then restart. That may be all that is required.
If that doesn't work, then try freezing and unpacking the gems (as per the other answer here).
There is also another possibility - that you're actually missing a gem that rails depends on but which is failing silently - eg a dependency on a certain version of rack caught me out once. But you may also have other gem dependencies
If you run rake gems you will be able to list all the gems that your project knows about that it needs - make sure they're installed to begin with.
Then, as a sort of rough smoke-test, try running script/console - if you're missing an important rails gem, script/console won't load and should fail, giving you a notice about the gem you need.
Update:
If you're trying to run v 2.3.5, you may also be suffering from this problem:
Bypassing rack version error using Rails 2.3.5
In which case you'll need to follow the instructions there.