I always dread creating a new project due to the amount of setup it sometimes requires. I have a number of Gems that I always use, some of which require additional configuration.
Now, I've done some research on the subject, and I can't seem to find anything about it, which, I think, is odd, since it would benefit the flow of starting a new Rails Project.
I suspect maybe that this has some broader Rails term that I haven't discovered yet.
So, is there a way to keep your favorite Gems (or any Gems) already installed and ready to go when you run the command:
rails new YourProject
Update
Rails Appliaction Templates was exactly what I was looking for.
I have no a favorite gem or something like that, but I have a template for the project creation process Rails Application Templates, railsrc.rb:
gem 'awesome_print', require: false
gem_group :development do
gem 'puma'
gem 'pry-rails', '~> 0.3.2'
gem 'zeus'
end
gem_group :test do
gem 'minitest-rails'
gem 'letter_opener'
gem 'ffaker', require: false
end
run "bundle install --path vendor/bundle"
#install minitest test_helper
generate 'mini_test:install'
environment "config.generators do |g|\n g.test_framework :mini_test, spec: true, fixture: true\n end"
# Add pride to minitest config
run "sed -i '' '4 s#^#require \"minitest/pride\"#' test/test_helper.rb"
#create postgres DB for postgress.app
#development and test
run "psql -c 'CREATE DATABASE #{app_path}_development;'"
run "psql -c 'CREATE DATABASE #{app_path}_test;'"
# add database yml
run "sed -i '' '4 s#^#require \"minitest/pride\"#' test/test_helper.rb"
#Add minitest features to Rake task
run %q^echo 'MiniTest::Rails::Testing.default_tasks << "features"' >> Rakefile^
#Fix README.md
run "rm README.rdoc"
run "touch README.md"
#Initialize local Git repository and Initial Commit
git :init
git add: "."
git commit: "-a -m 'Initial commit :pray:'"
Then I run rails new my_awesome_app -m ~/railsrc.rb, it build a brand new project with my requirements from railsrc.rb
Bundler
Bundler is the project you're looking for.
I'm not even sure how you can use Rails without it.
Once you have a Gemfile you like, it should take no more than 30 seconds to use the exact same gems for a new Rails project.
Alternatives
Your question isn't clear, and you don't provide any example so it's hard to know what you're looking for. If you have a common base for all your Rails projects, you might consider Engines, git branches or even whole virtual machines.
Related
Question: Using Rails 5 & Minitest-Rails is there a way to default new Rails apps to default to Spec-style testing?
I teach TDD and it's annoying to have to have the students convert each time we make a new app.
You could create a template.rb file with following configuration:
gem_group :development, :test do
gem "rspec-rails"
end
after_bundle do
`rails g rspec:install`
end
And then build a new Rails project using the following command
rails new my_app -T -m /path/to/template.rb
It will build a new Rails application, add Rails RSpec gem to its Gemfile and execute the install step for RSpec.
Otherwise you could provide a pre-built Rails Git repository and build on top of that.
References:
Rails Application Templates — Ruby on Rails Guides
rspec/rspec-rails: RSpec for Rails-3+
Looks like you've already done the hard work of answering your question. Though if you're teaching a class with an opinionated group of test gems, and a modified test_helper.rb and a modified application.rb, you may wish to consider writing your own gem that your students can add to their Gemfile. The gem could have the test gems you want as dependencies, and then they can install everything else they need with something like:
bin/rails generate <gem_name>:install
Here's a gem I wrote that you can fork or modify or just use as inspiration.
https://github.com/schadenfred/testable
I actually stole your config code for the above gem, which you can see expressed in inside a generator that lives here:
lib/generators/installer/install_generator.rb
It looks like in config/application.rb you just have to add:
config.generators do |g|
g.test_framework :minitest, spec: true
end
However there's not an automatic way to make Minitest-Rails default to spec style testing.
I could go to rspec, but would rather stay with Minitest for the moment as we teach our students Minitest from the beginning.
Ok so #sonna had 90% of what I was looking for.
I ended up with help creating a .railsrc file with
-d postgresql
-m ~/.template.rb
And a template with:
# .template.rb
# Gems we've talked about in class, but which have absolutely nothing to do
# with setting up spec-style testing.
# Included here for convenience.
gem_group :development do
# Improve the error message you get in the browser
gem 'better_errors'
# Use pry for rails console
gem 'pry-rails'
end
# Add some extra minitest support
gem_group :test do
gem 'minitest-rails'
gem 'minitest-reporters'
end
# Add some code to some files to support spec-style testing
# For these injections, indentation matters!
inject_into_file 'config/application.rb', after: "class Application < Rails::Application\n" do
<<-'RUBY'
# Force new test files to be generated in the minitest-spec style
config.generators do |g|
g.test_framework :minitest, spec: true
end
RUBY
end
# Things to do after all the gems have been installed
after_bundle do
# Run rails generate minitest:install
generate "minitest:install", "--force"
# Add minitest reporters support. This must be run after
# rails generate minitest:install, because that command
# changes test/test_helper.rb
inject_into_file 'test/test_helper.rb', after: 'require "minitest/rails"' do
<<-'RUBY'
require "minitest/reporters" # for Colorized output
# For colorful output!
Minitest::Reporters.use!(
Minitest::Reporters::SpecReporter.new,
ENV,
Minitest.backtrace_filter
)
RUBY
end
end
This sets up my project with postgres for DB, and Minitest-rails using spec-style tests and includes minitest-reporters.
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.
for a Ruby standalone script what Rails like deployment features such as Gemfile / "bundle install" etc
that is assuming you are developing a Ruby script that you want to test and then deployment, and perhaps ship to others, what Rails like deployment approach would you use for say:
a) GEM - marking GEM requirements & having them installed as required - e.g. Rails "Gemfile" where you mark what gems you need and then "bundle install" to install them
b) File Require - automatically loading *.rb files if they are in your script directory (I'm thinking of in Rails where if you put a class file in the apps/model directory Rails automatically load/require's the file for you)
depends on whether it's a tool you expect people to use on every host they find it on or not. also depends on whether the tool can be shared with pubic repos.
if it just has to work, without worrying about whether you've installed the gems via bundler already or not, you can use something like the following from within your standalone script to install gems if not already present (be mindful of system vs. user ruby):
#!/usr/bin/env ruby
require 'rubygems'
def install_gem(name, version=Gem::Requirement.default)
begin
gem name, version
rescue LoadError
print "ruby gem '#{name}' not found, " <<
"would you like to install it (y/N)? : "
answer = gets
if answer[0].downcase.include? "y"
Gem.install name, version
else
exit(1)
end
end
end
# any of the following will work...
install_gem 'activesupport'
install_gem 'activesupport', '= 4.2.5'
install_gem 'activesupport', '~> 4.2.5'
require 'active_support/all'
...
In my humble opinion, a gem is the way to go. Bundler makes it easy to get started; it starts a skeleton for you when you run the command…
bundle gem <GEM_NAME>
Take a look. As long as you specify your dependencies in your gem's .gemspec file, and somebody installs your packaged gem (they won't need bundler, just RubyGems' gem command), the dependencies will be installed as gems along with it.
In the rails project I'm working on I inserted support for rspec, cucumber and autotest with this Gemfile (partial)
gem 'rspec-rails'
gem 'cucumber-rails'
gem 'autotest-standalone'
gem 'autotest-rails-pure'
gem 'zentest-without-autotest'
however in order to run tests with autotest i need to execute bundle exec autotest otherwise it fails with this message
$ autotest
loading autotest/cucumber_rails_rspec_rspec2
Error loading Autotest style autotest/cucumber_rails_rspec_rspec2 (no such file to load -- autotest/cucumber_rails_rspec_rspec2). Aborting.
Now I'm developing on a Mac and I'd like to enable autotest-growl and autotest-fsevents gem, but if I insert those lines in my ~/.autotest
require 'autotest/growl'
require 'autotest/fsevent'
then I need to insert the corresponding gems in the Gemfile and everything works, but it breaks builds on my CI server (which is on Linux)
How to solve this without maintaining a different Gemfile for local and CI environments?
EDIT:
For the moment I solved with these lines in Gemfile
if RUBY_PLATFORM.downcase.include?("darwin") # I'm on Mac
gem 'autotest-fsevent'
gem 'autotest-growl'
end
It works both locally and on the CI server, I don't know if it mess something, for the moment it seems to work flawlessly.
Any cleaner way to do that is still welcome.
EDIT2:
I switched to groups solutions. While the previous monkeypatch works pretty well both in development and for continuous integration, it will gives you an error in production if you use capistrano bundler tasks for deployments or if you use bundle install --deployment option (which is advised in production)
When using the if RUBY_PLATFORM.downcase.include?("darwin") line you'll get this error on deploy.
# bundle install --deployment --without development test
You are trying to install in deployment mode after changing
your Gemfile. Run `bundle install` elsewhere and add the
updated Gemfile.lock to version control.
You have deleted from the Gemfile:
* autotest-fsevent
* autotest-growl
So my final solution to this problem is to include platform specific gems in a given group, say osx, and then in production and on CI server exclude it using bundle.
If you use capistrano to deploy put this in your config.rb
set :bundle_without, [:development, :test, :osx]
# capistrano bundler task
require "bundler/capistrano"
You might want to use groups in your gemfile, something like:
group :development do
gem "autotest-growl"
gem "autotest-fsevents"
end
and on the server you use: $ bundle install --without development
You can handle this by taking advantage of the different Gemfile environments (testing, development, production).
Your local box can be development while the CI server is your "production" environment.
With this in mind you can edit your Gemfile to use the appropriate gems depending on the environment.
Edit: Sorry, I think I scanned your post too quickly. But you can add your ~/.autotest to .gitignore so it wont be included on your CI server.
I'm trying to unpack all the system gems to end up with a standalone Rails directory including all the rails gems and all the system gems.
I'm starting with a bare rails setup; just did a jruby -S rails and a 'generate jdbc'. I then add a config.gem 'jdbc-mysql' to environment.rb and do the jruby -S rake gems:unpack:dependencies.
After unpacking, if I do a rake I get:
no such file to load -- jdbc-mysql
Is there something else you need to do to get the jdbc gem unpacked?
I'm using jruby 1.4.0 (and moving to 1.5 is on my todo list) and rails 2.3.8.
Here is what I do:
1) Install gems to a local repository
2) Set my load environment to use a gemrc.yml file from inside the local repository
To instal gems locally do this from your project folder:
gem install {gemname} -i gems
(the "-i gems" tells rubygems to install the gem in the folder gems and the {gemname} is a placeholder for the name of the gem you want to install.)
To set your gemrc.yml make a file in the newly created gems folder called gemrc.yml with something like the following content:
http://gist.github.com/430339
Then you need to tell your app to use your local gems at startup by adding the following to your config/boot.rb
http://gist.github.com/430343
Good luck... and for extra credit you could setup the ability to install a gem if it is needed. I did this through a method called dependency which is a helper method for the require command... This function receives a name and options... This way I simply say something like: (dependency 'extlib') and it does this if it cannot require the gem.
puts gem install --config-file gems/gemrc.yml #{'-v "'+options[:version].gsub(' ','')+'"' if options[:version]} #{options[:gem] || name}