rails engine gemfile.lock not being included rails engine - ruby-on-rails

I am trying to build a rails engine and I have some gems that I want to isolate and bundle only in the rails engine Gemfile. I put these gems in my Gemfile:
source 'https://rubygems.org'
gemspec
gem "pg", "0.15"
In my insurance.gemspec:
$:.push File.expand_path("../lib", __FILE__)
# Maintain your gem's version:
require "insurance/version"
# Describe your gem and declare its dependencies:
Gem::Specification.new do |spec|
spec.name = "insurance"
spec.version = Insurance::VERSION
spec.authors = ["Engine Sample"]
spec.email = ["engine#engine.com"]
spec.homepage = "https://github.com/engine/engine_plugin"
spec.summary = "Engine Sample."
spec.description = "Engine Sample."
spec.license = "MIT"
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
# to allow pushing to a single host or delete this section to allow pushing to any host.
if spec.respond_to?(:metadata)
spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
else
raise "RubyGems 2.0 or newer is required to protect against " \
"public gem pushes."
end
spec.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"]
spec.add_dependency "rails", "~> 5.0.1"
spec.add_development_dependency "route_translator"
end
Then I go to my engine on terminal and run bundle install which generates a Gemfile.lock in my engine folder.
I then go to main application and add in main application Gemfile this:
gem 'insurance', path: '/home/Documents/Projects/insurance'
I also created some routes in my engine folder config/routes.rb
but when I run my application, I get this error
Gem::LoadError - pg is not part of the bundle. Add it to your Gemfile.:

Rails engines are actually gems, they are supposed to rely on parent app's Gemfile.lock and only specify dependencies in their gemspec.
If you want some gem to be a dependency of the engine - then add it to gemspec, and if you want to lock exact version - do so in dependency declaration (but in fact, it's better to specify a more loose version):
spec.add_dependency "pg", "0.15" # better use something like "~>0.15" here

Related

gemspec error on creating new rails engine

I am trying to create rails engine using the below link:
http://guides.rubyonrails.org/engines.html
I have received below errors
You have one or more invalid gemspecs that need to be fixed.
The gemspec at /home/shariq/Documents/plugin/blorgh/blorgh.gemspec is not valid. Please fix this gemspec.
The validation error was '"FIXME" or "TODO" is not a description'
I already tried bundle update and bundle install
Here is all myworking
log
shariq#SDEV-MACHINE:~/Documents/plugin$ ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-linux]
shariq#SDEV-MACHINE:~/Documents/plugin$ rails -v
Rails 5.0.0.1
shariq#SDEV-MACHINE:~/Documents/plugin$ mysql --version
mysql Ver 14.14 Distrib 5.7.15, for Linux (x86_64) using EditLine wrapper
shariq#SDEV-MACHINE:~/Documents/plugin$ rails plugin new blorgh --mountable -d mysql
create
create README.md
create Rakefile
create blorgh.gemspec
create MIT-LICENSE
create .gitignore
create Gemfile
create app
create app/controllers/blorgh/application_controller.rb
create app/helpers/blorgh/application_helper.rb
create app/jobs/blorgh/application_job.rb
create app/mailers/blorgh/application_mailer.rb
create app/models/blorgh/application_record.rb
create app/views/layouts/blorgh/application.html.erb
create app/assets/images/blorgh
create app/assets/images/blorgh/.keep
create config/routes.rb
create lib/blorgh.rb
create lib/tasks/blorgh_tasks.rake
create lib/blorgh/version.rb
create lib/blorgh/engine.rb
create app/assets/config/blorgh_manifest.js
create app/assets/stylesheets/blorgh/application.css
create app/assets/javascripts/blorgh/application.js
create bin/rails
create test/test_helper.rb
create test/blorgh_test.rb
append Rakefile
create test/integration/navigation_test.rb
vendor_app test/dummy
run bundle install
You have one or more invalid gemspecs that need to be fixed.
The gemspec at /home/shariq/Documents/plugin/blorgh/blorgh.gemspec is not valid. Please fix this gemspec.
The validation error was '"FIXME" or "TODO" is not a description'
shariq#SDEV-MACHINE:~/Documents/plugin$
here is gemspec file:
##### log #######
$:.push File.expand_path("../lib", __FILE__)
require "blorgh/version"
Gem::Specification.new do |s|
s.name = "blorgh"
s.version = Blorgh::VERSION
s.authors = ["Shariq"]
s.email = ["gr8shariq#live.com"]
s.homepage = "TODO"
s.summary = "TODO: Summary of Blorgh."
s.description = "TODO: Description of Blorgh."
s.license = "MIT"
s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"]
s.add_dependency "rails", "~> 5.0.0", ">= 5.0.0.1"
end
The error is self-explanatory. You have to replace the "TODO" strings in the gemspec with some "actual" descriptions.
There is an already closed issue #26474 in rails repository:
rails plugin new does not complete properly since bundler 1.12
Ruby on Rails team member vipulnsward said:
We don't bundle install now - fbd1e98
fbd1e98's commit message explains:
Do not run bundle install when generating a new plugin.
Since bundler 1.12.0, the gemspec is validated so the bundle install
command will fail just after the gem is created causing confusion to the
users. This change was a bug fix to correctly validate gemspecs.
Add an option -B to skip bundle install:
rails plugin new NAME -B
If you need to run the bundler, you can remove every occurrence of TODO and FIXME from your .gemspec file and then run bundle install.
I met the issue today. Here is what I did(git diff) make me survive.
## -9,15 +9,15 ## Gem::Specification.new do |spec|
spec.version = Blorgh::VERSION
spec.authors = ["Torvalds Du"]
spec.email = ["torvalds#ekohe.com"]
- spec.homepage = "TODO"
- spec.summary = "TODO: Summary of Blorgh."
- spec.description = "TODO: Description of Blorgh."
+ spec.homepage = ""
+ spec.summary = "Summary of Blorgh."
+ spec.description = "Description of Blorgh."
spec.license = "MIT"
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
# to allow pushing to a single host or delete this section to allow pushing to any host.
if spec.respond_to?(:metadata)
- spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
+ spec.metadata["allowed_push_host"] = "http://mygemserver.com"
else
raise "RubyGems 2.0 or newer is required to protect against " \
"public gem pushes."
therefore, you have to remove all the text TODO from gem_name.gemspec.
Good luck.
Put this instead.
Gem::Specification.new do |spec|
...
spec.homepage = "https://example.com"
spec.summary = "Summary of App."
spec.description = "Description of App."
spec.metadata["allowed_push_host"] = spec.homepage
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
spec.metadata["changelog_uri"] = spec.homepage
...
end

"https://rubygems.org" is not allowed by the gemspec, which only allows "'http://rubygems.org'"

I'm trying to compile my first gem and push it to rubygems.org. It keeps throwing an error saying I can't push to https://rubygems.org:
gem build simplesms.gemspec
WARNING: licenses is empty, but is recommended. Use a license identifier from
http://spdx.org/licenses or 'Nonstandard' for a nonstandard license.
WARNING: no homepage specified
WARNING: See http://guides.rubygems.org/specification-reference/ for help
Successfully built RubyGem
Name: simplesms
Version: 0.1.0
File: simplesms-0.1.0.gem
Toms-MacBook-Pro-2:simplesms t$ gem push simplesms-0.1.0.gem
Pushing gem to https://rubygems.org...
ERROR: "https://rubygems.org" is not allowed by the gemspec, which only allows "'http://rubygems.org'"
But in my spec:
# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'simplesms/version'
Gem::Specification.new do |spec|
spec.name = "simplesms"
spec.version = Simplesms::VERSION
spec.authors = ["Tom"]
spec.email = ["tom#example.com"]
spec.summary = %q{Easily add sms to your project by integrating the Simple SMS Heroku Addon into your app.}
spec.homepage = ""
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
# to allow pushing to a single host or delete this section to allow pushing to any host.
if spec.respond_to?(:metadata)
spec.metadata['allowed_push_host'] = "'http://rubygems.org'"
else
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
end
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
spec.add_development_dependency "bundler", "~> 1.12"
spec.add_development_dependency "rake", "~> 10.0"
end
In the gemfile:
source 'http://rubygems.org'
# Specify your gem's dependencies in simplesms.gemspec
gemspec
Just for kicks I also tried setting them to 'https://rubygems.org', however it still throws the same error.
Any idea what I need to do to get this to push to rubygems.org? I already signed in with my email/password and confirmed the credentials are in ~/.gem/credentials
This line:
spec.metadata['allowed_push_host'] = "'http://rubygems.org'"
You're setting allowed_push_host to 'http://rubygems.org'. It should just be http://rubygems.org (without the single quotes). Change it to:
spec.metadata['allowed_push_host'] = "http://rubygems.org"
It should be safe (and preferred) to allow https://rubygems.org instead, too.

Rails: Chaining Ruby gem dependencies?

I'm creating a Rails web application which uses a shared library of models (as a Rails Engine), stored in a subrepository (Git subtree.) This shared library contains dependencies on other Ruby gems (in my case, HTTParty and Dalli), of which I want to be automatically referenced by the parent project that includes this shared library.
However, my gem's dependencies don't appear to be resolving in the parent project, and when I start my web application, it has missing references to those gem dependencies in the shared library. (i.e. NameError: uninitialized constant ApiClient::HTTParty) If I explicitly add those references to my web app's Gemfile (as in uncomment the Gemfile lines below), everything works fine.
How do I get these dependencies to 'chain', and have the parent project automatically resolve these references?
Here's what my project looks like:
[MyRailsApp]
-- ...
-- [app]
-- [config]
-- [lib]
-- [MyLib]
-- ...
-- [app]
-- [config]
-- [lib]
-- [MyLib]
-- version.rb
-- engine.rb
-- MyLib.gemspec
-- Gemfile
-- Gemfile
MyRailsApp/Gemfile:
source 'https://rubygems.org'
gem 'activesupport', '3.2.13', :require => 'active_support'
gem 'actionpack', '3.2.13', :require => 'action_pack'
gem 'actionmailer', '3.2.13', :require => 'action_mailer'
gem 'railties', '3.2.13', :require => 'rails'
...
# gem 'dalli'
# gem 'httparty'
gem 'MyLib', :path => 'lib/MyLib'
MyLib/MyLib.gemspec:
$:.push File.expand_path("../lib", __FILE__)
# Maintain your gem's version:
require "mylib/version"
# Describe your gem and declare its dependencies:
Gem::Specification.new do |s|
s.name = "MyLib"
s.version = MyLib::VERSION
s.authors = ["David"]
s.email = ["ops#myemail.com"]
s.homepage = "http://www.mysite.com"
s.summary = "Shared Library"
s.description = "Shared Library"
s.files = Dir["{app,config,db,lib}/**/*"] + ["MIT-LICENSE", "Rakefile", "README.rdoc"]
s.add_dependency "rails", "~> 3.2.13"
s.add_dependency "dalli", ">= 2.6.4"
s.add_dependency "httparty", ">= 0.11.0"
end
Figured it out. I had the wrong line of thinking... I thought Gemspecs, used for installing gem dependencies (which was working just fine), would also be used by Rails to determine what dependencies need to be loaded into memory when the application starts. This is not the case, at least, not when using Rails engines.
For the average gem, it appears that a typical Rails web app has a line in the boot.rb file which loads all gems and dependencies in the application Gemfile. However, this autoloading does not appear to extend to Rails engines listed in the Gemfile. In this case, you must load your dependencies into application memory manually, by finding the engine.rb file (in your Rails engine) and adding require 'yourgem' at the beginning of the file. This will load the dependency when the engine loads.
A friend found and linked me this relevant question/answer, if this explanation isn't sufficient:
https://stackoverflow.com/a/5850503
If you want rubygems to understand your dependencies, package each of them with a proper .gemspec file. You don't have to publish your gem, it can be private and referenced via a git:// type URL.
The thing is, generally your .gemspec needs to be at the root level. You can't bury it in your project as Rubygems does not go out of its way to look for these.
In your use case, MyLib should be a separate thing.

How to run a Rails application within a gem?

I'm not sure if this sort of thing is very common, but I keep finding myself trying to create gems that are just wrappers around a Rails application.
My gem will have a generator to create a config.ru but the Rails application will live inside the gem's lib directory. I need to know how to "embed" a Rails application and configure it so that it can be run inside the gem.
For example:
$ mygem new project
mygem created a directory called "project" with the following files:
project/config.ru
project/widgets/
project/foobars/
My gem will also generate some directories that will need to be added to Rails somehow so that I can access the code in those directories from the Rails app living inside the Gem.
Any help or advice you can give me would be appreciated.
To clarify, I'm not trying to create a Rails engine, or plugin to a Rails application. I'm trying to create a fully-fledged Rails application, but package it as a gem so that a user of my gem can run the gem (the rails app) without needing to know that it's using Rails behind the scenes.
Update: Okay, I've got a little bit working now. I've created the gem and generated the rails project inside the gem's lib directory.
$ bundle gem my_gem && cd my_gem/lib
$ rails new my_gem --skip-bundle
Which leaves me with:
my_gem/
my_gem.gemspec
bin/my_gem
lib/
my_gem.rb
my_gem/
version.rb # generated by bundler
# the rails app:
app/
config/
Gemfile
...etc
Since this gem requires Rails, I started adding the gems defined in the Rails Gemfile as dependencies in the gem's Gemspec, but I'm a little confused as to how to handle the assets group in the Gemfile.
# Rails Gemfile
group :assets do
gem 'sass-rails', '~> 3.2.3'
gem 'coffee-rails', '~> 3.2.1'
gem 'therubyracer', :platforms => :ruby
gem 'uglifier', '>= 1.0.3'
end
# gemspec
Gem::Specification.new do |gem|
gem.name = "my_gem"
# ...
gem.add_dependency 'rails', '3.2.8'
gem.add_dependency 'sqlite3'
gem.add_dependency 'jquery-rails'
# how to add the assets group gems?
end
Try this and see if it helps you make progress.
Gems are just directories of files, and you can put whatever files you want into a gem.
Create:
Create a blank gem full-blown Rails project:
$ bundle gem my_gem
Then a Rails app:
$ rails new my_app --skip-bundle
Copy the Rails files into the gem:
$ cp -R my_app/* my_gem
Bundle everything into your Rails app:
$ cd my_gem
$ bundle install --binstubs --path vendor/bundle
$ cd -
Make the Rakefile have the gem tasks and the Rails setup:
#!/usr/bin/env rake
require "bundler/gem_tasks"
require File.expand_path('../config/application', __FILE__)
MyApp::Application.load_tasks
Verify that it starts:
$ rails server
Load Path:
To control where Rails looks for files, such as "external" configuration files, you can use the file config/application.rb with any directory paths like this:
# Add additional load paths for your own custom dirs
# config.load_paths += %W( #{config.root}/../customdir )
Note the ".." which means go above the Rails directory. This gives you a path relative to the gem.
If you prefer you can specify an absolute path, for example if you know the user will always keep his external files in "~/myfiles/". You can also choose to use ENV vars to send in whatever directory you want.
If you read about load path capabilties, look for lines that are shorthand for adding a directory to the front of the load path because you may want to put your external diretories first:
$:.unshift File.dirname(__FILE__)
Gem Build:
Edit my_gem.gemspec to add your own description, homepage, summary, etc. then build:
$ gem build my_gem.gemspec
Successfully built RubyGem
Name: my_gem
Version: 0.0.1
File: my_gem-0.0.1.gem
Now your Rails app is packaged as a gem.
The config.ru should be a typical Rails one. No special changes AFAIK.
When your user wants to install your app:
$ gem install my_gem
The gem will install in the user's typical gem directory. If you want to adjust this, see this page on rubygems: http://docs.rubygems.org/read/chapter/3
Crate:
You may also want to investigate the Crate project:
Crate: Packaging Standalone Ruby Applications
http://www.slideshare.net/copiousfreetime/crate-packaging-standalone-ruby-applications
Rack:
To use config.ru here is the typical Rails setup:
# Rails.root/config.ru
require "config/environment"
use Rails::Rack::LogTailer
use ActionDispatch::Static
run ActionController::Dispatcher.new
For your project, you want to require some files before Rails. You'll want to learn about the Ruby "require" and how it finds files using LOAD_PATH.
The easy way:
# Rails.root/config.ru
require_relative 'filename'
require "config/environment"
Or to put the user's custom directory up couple directory levels:
require './../../filename' # not the best for security
Or to use an absolute path, read about File.expand_path:
File.expand_path(__FILE__)
Or to use the current directory and put it on the load path:
$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'filename'
Lots of choices for you to consider. Hope this helps!
What about the question, "How am I going to run the Rails application inside the gem?".
A Rails application has controllers and views to run a web server. What you need are actions to create, list, update, and destroy. Exposing these actions without a web server is essentially having such methods in a class. That's a normal standard type of gem in the first place.
So maybe your questions is really, how do I write a gem where I have ActiveRecord, and the other Rails stuff.
First, you need to make your gem dependent on the Rails gems you need. You do this in the gemspec file for your gem.
Then it really is just a matter of your gem code doing a require of the right Rails gems you need.
I'm not sure if this will help, as I read through everything and I couldn't find the motivation behind why you were doing this. One of the reasons I came up with was making something that can be used on a desktop environment. In that case you could try using something like Bowline. If you just want to provide an application that others can download and use and install themselves, then you can probably assume they can follow at least basic developer kind of instructions and you could just provide the whole app on github or as a zip file. See an example of someone else doing something similar over on Fat Free CRM's github page.

How to require the forked gem lib file ? Name conflicts?

I had to fork the gem Thor, coz my cli has one command run which is reserved in the Thor lib itself, changed its name to millisami-thor just in the .gemspec as follows:
Gem::Specification.new do |s|
...
s.name = 'millisami-thor'
...
end
and to use it, I pushed the gem under the name millisami-thor to rubygems.org and in the Gemfile of my cli project, I put gem 'millisami-thor', :require => 'thor'
Now while testing bundle exec cucumber features or to try out the executable, just did ./bin/executable --params and it worked out.
Now, I build the gem with gem build gemname.gemspec that generates gemname.gem and installed with gem install gemname.gem and it gets installed as well as the binary too. Fine, till here.
Now, when I use the binary cmd like executable --params, it looks for the original thor library instead of the forked one.
I figured out that this was due to the require ... in the executable.
require 'thor'
require 'fileutils'
require 'gemname/cli'
Cf::CLI.start
coz in there I explicitly required the original thor.
Now, when I change it to require 'millisami-thor, it cannot find and says:
...
custom_require.rb:36:in `require': no such file to load -- millisami-thor (LoadError)
...
In the Gemfile, I could have done gem 'millisami-thor, :require => 'thor' so that it loads the forked gem.
But how can I do the same if its just the require 'millisami-thor' ?
The only option I can think of is to change all the class names to 'MillisamiThor' instead of 'Thor' and the file names too. But this will be too messy and ugly.
I could have spotted this if I had installed my gem and test it before. But I did just in the test environment, in which the bundler requires the millisami-thor's thor file, so I didn't have this problem till today.
Is there any other way out to achieve this without any messy hacks?
You can keep the original gem setup and point Bundler to your git repository fork:
gem 'thor', :git => 'git://github.com/yourname/thor.git', :require => 'thor'
or even a local path
gem 'thor', :path => '/path/to/thor.git', :require => 'thor'

Resources