Ruby gem dependency loading - ruby

I'm putting some shared models for a rails app inside it's own gem. It's just models, so I'm not using an engine. Getting it set up seemed to work fine until I added the "acts_as_list" gem.
# gem - domain.gemspec
spec.add_dependency "acts_as_list"
# gem - lib/domain.rb
require "acts_as_list"
# gem - lib/domain/models/page.rb
acts_as_list scope: [:ancestry]
This works fine in the console for my gem, I can run methods specific to acts_as_list as usual. However, when I add my gem to another project, it gives me an error.
# project - Gemfile
gem "www_domain", path: "../www_domain"
Bundler::GemRequireError: There was an error while trying to load the gem 'domain'.
NoMethodError: undefined method `acts_as_list' for #<Class:0x0055da70121ab0>
/home/shaun/sites/demo/domain/lib/domain/models/page.rb:32:in `<class:Page>'
Is there something special I have to do in this case to access the acts_as_list method because my model is inside a gem?
Update: Here is my complete lib/domain.rb file for the gem:
require "yaml"
require "active_record"
require "acts_as_list"
require "ancestry"
# rbfiles = File.join(File.dirname(__FILE__), "lib", "**", "*.rb")
# Dir.glob(rbfiles).each do |file|
# require file.gsub("lib/", "")
# end
module Domain
# Your code goes here...
def self.root
File.dirname(__dir__)
end
def self.db_config
YAML.load_file("#{Domain.root}/db/config.yml")["development"]
end
end
require "domain/version"
require "domain/models/page"
require "domain/models/menu"
require "domain/models/article"
require "domain/models/page_part"
I can use acts_as_list and ancestry methods in the console of my gem (running bin/console from the gem directory). But the project console (running bundle exec rails console from the project directory) will not start because of the gem error I mentioned.

This might result from a load order issue if the model being required before the require :acts_as_list statement. Check to see if the gem specifies the load order. If not, you could try something like:
# gem - lib/domain.rb
require "acts_as_list"
require "models/page"
If the load order is unclear, I find it helpful to simply add a
puts __FILE__
at the top of the relevant source files.

Related

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"

Unable to require pry via Bundler.setup for a Ruby application that uses a Gemfile

I'm writing a simple ruby application(basically using PORO's). I've added a Gemfile to it and I'm trying to require the pry gem(which is useful for adding breakpoints while debugging, as the application grows) via the Gemfile but I'm unable to require that gem using Bundler.setup, things work fine with Bundler.require.
I'm trying to avoid the use of Bundler.require for reasons stated in this blog for instance.
In the Employee.rb file, I have the below code -
# require 'bundler'
# require 'bundler/setup'
# Bundler.setup(:default, :test, :development)
Bundler.require(:default, :development, :test)
def total_score(scores)
binding.pry #added on purpose , just to see if the app stops at this breakpoint
scores.inject(:+)
end
When I use Bundler.setup(uncommenting the lines commented above), instead of Bundler.require, I get the below error for the command rspec spec . given from my apps root directory-
Failure/Error: expect(total_score(scores)).to eq(16)
NoMethodError:
undefined method `pry' for #<Binding:0x007fbda22b79d0>
# ./Employee.rb:9:in `total_score'
# ./spec/employee_spec.rb:5:in `block (3 levels) in <top (required)>'
Also, just one more note, as per the bundler docs, I tried even doing a require rubygems, but even that doesn't help. Ideally, I would want to avoid using require rubygems for reasons mentioned in this link.
How do I get my app to require the pry gem using Bundler.setup, without doing a require rubygems alongside and also without using Bunder.require ?
Bundler.setup will simply add the gems to the load path, whereas Bundler.require will do both the adding to the load path and the require.
I recommend using Bundler.setup so that your code boots faster. Then when you need to require pry, do this:
require 'pry'

Ruby 1.8.7: Can't load module from custom gem

After creating a custom gem I'd like to reference functions defined in a module it contains.
Custom gem is dsi_core and the module lib/cuke.rb contains simply:
module DsiCore
module Cuke
def self.Features(*args)
puts "Hello world!"
end
end
end
I've installed the gem and can see /var/lib/gems/1.8/gems/dsi_core-0.1.0/lib/cuke.rb exists as it should.
In another gem dsi_fabric there is the code dsi_fabric/lib/dsi_fabric:
require 'dsi_core'
# ...
DsiCore::Cuke.Features(*ARGV)
Trying to run this from the lib/ directory of dsi_fabric gem:
ruby -rubygems ./dsi_fabric.rb arg1 arg2
..results in:
./dsi_fabric.rb:7: uninitialized constant DsiCore::Cuke (NameError)
This refers to the Cuke.Features line in dsi_fabric.rb.
What am I doing wrong?
You're requiring 'dsi_core' instead of 'cuke'. Try changing require 'dsi_core' to require 'cuke'.
If you are testing in existing namespace problem can be namespace, so try with root namespace reference.
::DsiCore::Cuke.Features(*ARGS)
also like I mentioned in comment you need to put
def self.Features(*args)
# ...
end
Hehe I do not like that capital method name annotation but to each his own :)
EDIT
Also try
require 'rubygems'
require 'dsi_core'
I was miscomprehending how Gem imports work.
If you create a gem and add other gem dependencies to it in the gemspec, those dependencies are automagically imported already.
Therefore what I have above is wrong - to import the cuke.rb file from gem dsi_core in gem dsi_fabric you would use:
require 'cuke'
i.e. the require dsi_core is implicit by nature of the Gem specification and gemspec.
Then to reference in the code would be
DsiCore::Cuke
..as I originally posted.
I was confused because mny public gems indicate you should use require with the form:
require `gem-name/module-or-class`.
However this is misleading: the gem name isn't being used at all, but rather a directory named after the gem:
require 'dir-name/module-or-class'
In this example the gem gem-name has the following directory structure:
lib/gem-name/module-or-class.rb
i.e. they've made a folder in the gem's lib/ directory named after the gem itself.

Strange require statement errors in Ruby?

I've got a wrapper for my Gem, socks, inside socks.rb. The entire file is made up of require statements, and a module declaration:
# lib/socks.rb
require 'socks/version'
require 'socks/base_controller'
require 'socks/templates'
require 'socks/tasks'
require 'socks/rake_tasks'
module Socks
end
However, require 'socks/tasks' and socks/rake_tasks is giving me a LoadError: no such file to load -- socks/tasks / rake_tasks error.
Is this a problem with the alignment of the require statements, or just the code?
Code is on Github: https://github.com/Beakr/socks
EDIT: require './socks/tasks' is now working, however require './socks/rake_tasks' is not.
Ruby load files using its $LOAD_PATH. This global array is changed by e.g. rubygems and bundler to allow to find libraries in various locations. In your sock.gemspec you have defined
gem.require_paths = ["lib"]
which means that rubygems will add the lib directory of your gem to ruby's $LOAD_PATH. But it odes so only if you have installed the gem and the gemspec is thus evaluated. If you don't want to install your gem, you can test your gem using
bundle exec irb
in your gem directory, or alternatively by first adapting your $LOAD_PATH in your irb session like so:
$LOAD_PATH.push "/path/to/your/gem/lib"
require 'socks'

Ruby: What does 'require: false' in Gemfile mean?

Does this:
gem 'whenever', require: false
mean that the gem needs to be installed, or does it mean it is not required?
This means install the gem, but do not call require when you start Bundler. So you will need to manually call
require "whenever"
if you want to use the library.
If you were to do
gem "whenever", require: "whereever"
then bundler would download the gem named whenever, but would call
require "whereever"
This is often used if the name of library to require is different than the name of the gem.
You use :require => false when you want the gem to be installed but not "required".
So in the example you gave:
gem 'whenever', :require => false
when someone runs bundle install the whenever gem would be installed as with gem install whenever. Whenever is used to create cron jobs by running a rake task but isn't usually used from within the rails (or other framework if not rails) application.
So you can use :require => false for anything that you need to run from the command line but don't need within your code.
require: false tells Bundler.require not to require that specific gem: the gem must be required explicitly via require 'gem'.
This option does not affect:
bundle install: the gem will get installed regardless
the require search path setup by bundler.
Bundler adds things to the path when you do either of:
Bundle.setup
which is called by require bundler/setup
which is called by bundle exec
Example
Gemfile
source 'https://rubygems.org'
gem 'haml'
gem 'faker', require: false
main.rb
# Fail because we haven't done Bundler.require yet.
# bundle exec does not automatically require anything for us,
# it only puts them in the require path.
begin Haml; rescue NameError; else raise; end
begin Faker; rescue NameError; else raise; end
# The Bundler object is automatically required on `bundle exec`.
Bundler.require
Haml
# Not required because of the require: false on the Gemfile.
# THIS is what `require: false` does.
begin Faker; rescue NameError; else raise; end
# Faker is in the path because Bundle.setup is done automatically
# when we use `bundle exec`. This is not affected by `require: false`.
require 'faker'
Faker
Then the following won't raise exceptions:
bundle install --path=.bundle
bundle exec ruby main.rb
On GitHub for you to play with it.
Rails usage
As explained in the initialization tutorial, the default Rails template runs on startup:
config/boot.rb
config/application.rb
config/boot.rb contains:
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
which does the require 'bundler/setup' and sets up the require path.
config/application.rb does:
Bundler.require(:default, Rails.env)
which actually requires the gems.
Whenever you specify a Gem in your Gemfile and run bundle install, bundler will go and install specified gem and load code for that Gem in you app by putting require 'whenever' this way bundler will load code for all of your Gems in your Rails app, and you can call any method from any Gem without any pain, like you do most of the time.
but Gems like whenever, faker or capistrano are something which you do not need in your app code you need whenever code in your schedule.rb file to manage crons and capistrano code in deploy.rb file to customize deployment recipe so you need not to load code for these gems in your app code
and wherever you want to call any method from these Gems you can manually require thsese gems by yourself by putting require "whenever" . so you put :require => false in your Gemfile for these Gems, this way bundler will install that Gem but not load code for that Gem itself, you can do it whenever you want by simply putting like require 'whenever' in your case.
Analogy to Explain
## Gemfile
gem "university_degree", require: false
gem "dealing_with_boss"
"dealing_with_boss" - loaded into memory and ready to go.
degree gem - not "needed"....you need to manually require it, in order to use it.
In order to require gems in your Gemfile, you will need to call Bundler.require.
You can prevent bundler from requiring the gem with require: false, but it will still install and maintain the gem. Check this out for a more detailed explanation.

Resources