Get routes of Rails app without running rake routes - ruby-on-rails

My understand of rake routes is that it bootstraps the Rails application and then pulls the routes from it. If I want to simply look at the text (no loading of a rails application) and be able to output something similar to what rake routes outputs, how would I do it? I know rake routes actually runs Ruby code and I am worried about doing so as I do not trust these applications.
I am weary to load the Rails application as I do not trust these Rails applications, but if there is a way to sandbox the running of rake routes or some related method, I would be open to that as well.

If you have a complex routes file with lots of engines you'd probably be better off using Vagrant to run the app in a sandbox. If it's simple though, this method might work for you.
Rails will generate routes from routes.rb without the underlying application. Create a new dummy app making sure you match the rails version to the version of the app you want to inspect.
> rails new dummy_app
…
> cd dummy_app
> cp /path/to/untrusted/app/config/routes.rb ./config/
Edit the app name at the top of the route file to match the name of the dummy app, in this case it would be DummyApp.Application.routes.draw do. Then run
> rake routes
Some caveats: If there are any engines or gem speficic routes in there you'll need to add those to the Gemfile or comment out those routes. For example, if the pap uses active_admin you'll need to add that to the gemfile as well as generate the AdminUser class. And then you'll want to recopy over the routes files as the generator adds lines to the routes file. If you run into issues with uninitialized contents you may need an initializer to require certain classes. For example, if you mount Resque::Server, you need an initializer with these two lines:
# config/initializers/dummy_init.rb
require 'resque'
require 'resque/server'

Related

Are Rails engines supposed to come with an environment.rb?

I recently created my first Rails engine. The only thing in /config is routes.rb - no environment.rb or application.rb or anything like that.
When I installed the rspec-rails gem and tried to run my specs, I got an error saying it couldn't find environment.rb, which is not surprising, since environment.rb doesn't exist.
The confusing thing to me is that the evidence I have tells me one of two things must be the case:
1) Rails engines don't come with an environment.rb and you're expected to create environment.rb, application.rb, etc. by hand. This seems unlikely.
2) Rails engines do come with an environment.rb, but my engine happens to be missing it for whatever reason. This also seems unlikely. I am confused, though, by this answer that refers to environment.rb in an engine: Testing Rails 3.1 mountable engine with Rspec
So my question is: Are Rails engines supposed to come with an environment.rb, and if not, how are you supposed to create one if you want/need one?
Use the dummy app's environment.rb file.
To setup RSpec:
Add the below to your spec_helper.rb file.
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../test/dummy/config/environment", __FILE__)
...
It's also helpful to add the engine root.
ENGINE_RAILS_ROOT = File.join(File.dirname(__FILE__), '../')
If you want access to the engine's routing helpers, add the below in the RSpec.configure block.
# This will include the routing helpers in the specs so that we can use
# <engine>_path, etc., to get to the routes.
config.include <RailsEngine>::Engine.routes.url_helpers
Hope that helps.
Rails engines may have environment files, but they don't need them. I would recommend against them, because your application is probably going to get mounted (as a gem) inside of another application, making it very difficult to configure your engine from within the main rails application.
It's more advisable that you use a yml file that can be configured from within the primary rails app, and allow that rails app to implement environment specific configurations. That doesn't mean you can't have some defaults that are based on environment environment files inside of your rails engine, but rather, that it usually makes life easier to allow external configuration.

regenerating rspec files

how can I generate rspec on-demand?
the thing was my rspec files were already automatically generated by the "rails generate controller" command. Then I manually deleted those files in hope that there should be a command which I can use to regenerate those files.
What do I do to regenerate those deleted rspec files without firing "rails generate controller" again?
I have tried some command I was suggested by some blog:
$ rails generate rspec_controller pages --skip-migration --skip-fixture --skip
Could not find generator rspec_controller.
but it didn't work for me.
any advice would be really appreciated!
In the root folder of your app:
rails generate controller -h
It will show you the usage instructions.
rspec_controller is deprecated in favour of the standard controller generator in Rails. It works now by you including rspec-rails within your Gemfile like this:
group :development, :test do
gem 'rspec-rails'
end
This then will load this file, which customizes what tools the Rails controller generator uses with these two lines.
This is a bad idea, for two reasons:
You normally shouldn't be autogenerating your spec files: you need to think about exactly what you want to specify.
Controller specs should normally not be written at all. Use Cucumber scenarios instead -- they're much less painful and much better at testing behavior (controller specs are too dependent on implementation).

How to universally skip database touches when precompiling assets on Heroku

I'm deploying a Rails 3.1 app to Heroku's Cedar stack. With Heroku Cedar and Rails 3.1, you can compile the assets yourself locally, let Heroku compile them when you push (during "slug compilation"), or have them be compiled just-in-time while the app is running. I want to do the middle option, letting Heroku precompile the assets.
When Heroku runs the assets:precompile task, it errors with "could not connect to server" because the app is trying to connect to the database but no database is available at that stage of slug compilation. The lack of database connection is expected and unavoidable at this point. I'm looking for a way to move past it, because a database connection isn't crucial to asset precompilation.
The part of my app that's trying to connect to the database is Devise. There's a devise_for :users line in routes.rb that wants to look at the User model.
I could just write a rake task that stubs out devise_for and make it a prereq of assets:precompile. I think that would solve my problem, but I'm looking for a more universal solution that I could use on any Rails 3.1 app with this problem on Heroku.
Is there anything out there, or can you conceive of anything that silences database connection errors while still running the app enough to have route and asset path generation?
Obviously if an app needs to read/write data during startup, we can't stub that, but can we fake every ActiveRecord model automatically?
add this to config/application.rb
config.assets.initialize_on_precompile=false
took me a while to hunt this down... adding it to config/environments/*.rb did NOT work
UPDATE: It doesn't work with rails 4
Heroku now makes a labs flag available that'll make the runtime environment available during compilation time, which means your app will be able to successfully connect to your DATABASE_URL database.
First you need to install the labs plugin:
$ heroku plugins:install http://github.com/heroku/heroku-labs.git
then enable the user-env-compile labs feature:
$ heroku labs:enable user-env-compile --app your-app-name
For me the problem is activerecord calling instantiate_observer in lib/active_record/railtie.rb:92. This will load the observers and the respective models. has_and_belongs_to_many then connects to the db.
I think I'll override this method when ENV["RAILS_ASSETS_PRECOMPILE"] is present, which is used by devise in the fix Bradley linked to.
EDIT: So this snippet fixed it for me:
namespace :assets do
# Prepend the assets:precompile_prepare task to assets:precompile.
task :precompile => :precompile_prepare
# This task will be called before assets:precompile to optimize the
# compilation, i.e. to prevent any DB calls.
task 'precompile_prepare' do
# Without this assets:precompile will call itself again with this var set.
# This basically speeds things up.
ENV['RAILS_GROUPS'] = 'assets'
# Devise uses this flag to prevent connecting to the db.
ENV['RAILS_ASSETS_PRECOMPILE'] = 'true'
# Prevent loading observers which will load the models which in turn may hit
# the DB.
module ActiveModel::Observing::ClassMethods
def instantiate_observers; end
end
# Prevent route drawing because certain gems might get called which will hit
# the DB.
class ActionDispatch::Routing::RouteSet
def draw; end
end
end
end
Workaround for Rails (4.2 edge):
Add the following as /config/initializers/precompile.rb:
module Precompile
# Public: ignore the following block during rake assets:precompile
def self.ignore
unless ARGV.any? { |e| e == 'assets:precompile' }
yield
else
line = caller.first
puts "Ignoring line '#{line}' during precompile"
end
end
end
and use it in your routes.rb like this:
Precompile.ignore { ActiveAdmin.routes(self) }
EDIT: This answer is out of date and no longer works - See fringd's answer.
Not quite a universal stubbing but devise has added a check now to fix this particular problem . See the issue and fix on Github. By providing a RAILS_ASSETS_PRECOMPILE environment config devise should skip building the routes
I stuck this in 'lib/tasks/assets.rake' and was able to get assets:precompile to actually succeed. This should work as long as you don't actually access the database as a result of requiring your environment. It obviously won't help with ActiveRecord, but it should work for all mongoid-based apps.
task 'assets:precompile' => 'assets:stub_mongoid'
task 'assets:stub_mongoid' do
def Mongoid.load!(*args)
true
end
end
Heroku added an unofficial flag to make the environment (i.e. also the DB) accessible during precompilation. Just ask them to switch it on and DB dependencies during asset precompilations are no longer an issue. Not sure, if/when this flag is officially available though, or if it will simply be the new default.
Spork.trap_method is also an interesting solution to the problem of Devise's routes_for calling the model early in the load process. Solution can't be applied directly AFAIK, but it's solving the same sort of problem, so it might provide inspiration for somebody.
Spork.trap_method
I lack sufficient reputation to comment, so here's another answer.
It's true that #fringd's top-rated answer does not work on Rails 4. I have, however, found this technique to work:
https://iprog.com/posting/2013/07/errors-when-precompiling-assets-in-rails-4-0
Although, I rearranged the BASH variables like so:
~$ RAILS_ENV=production DATABASE_URL=postgresql://user:pass#127.0.0.1/dbname bundle exec rake assets:precompile
BTW, This is a fantastic aid if you need to build a Docker image. Put that line into your Dockerfile so your DB can live in a different container and your app containers don't need to precompile assets every time they start up!
Disable AR:
config = Rails.application.config
def config.database_configuration
{}
end
ar = ActiveRecord::Base
def ar.establish_connection
end

How to embed/mount existing Rails app into another Rails app?

I have two Rails apps (using rails 3.0.7), call them "blog" and "auth". I'd like to mount "auth" from "blog" such that I can run the "blog" app and have certain requests routed to the "auth" app.
It seems like I need to embed or perhaps create an "engine", but I'm not 100% sure which is correct.
How can I embed the "auth" app inside of the "blog" app?
You can create "rails-engine" for 'auth' app, and then mount this engine into the rails application i.e 'blog' application.
Read more about Rails::Engine at below links -
http://guides.rubyonrails.org/engines.html
http://api.rubyonrails.org/classes/Rails/Engine.html
To embed a Rails mountable engine into a Rails application, follow these general steps -
1) Open the target Rails project, where an engine should be embedded.
2) Open for editing the Gemfile, and add the following line:
gem '<engine name>', :path => "<absolute path to the Rails mountable engine project>"
3) Open for editing Config/routes.rb, and add the following line:
mount <engine name>::Engine, :at => "/<engine name>"
Rails was raising RuntimeError: You cannot have more than one Rails::Application if you attempted to have two Rails apps defined in one Ruby instance, but it has changed after this commit.
This is still unreleased in 4.0.0, but will get included in the newer versions. (> 4.1.0.beta)
Check out the discussion on PR for more info.
From what I understand, you probably don't need to have two Rails apps, though. You should probably attempt to extract functionality you need in the Rails::Engine.
Remember, Rails::Application is also a Rails::Engine.
You can find a lot of material about how to do it on the web, and I would recommend these two to get you started.
Rails3 is a rack-based application. Rackmiddleware already has a number default built-in applications. Try to run bundle exec rake middleware. You can add custom Rack applications into the stack. Use this blogpost to see how it works.
If auth app is something like a web service (for example facebook authentication), so just keep 2 apps running and make requests from one app with urls to another app.
If these apps share some logic or the same database, you can just merge the code, so two apps become one, or your can make 'auth' app something like a gem or a plugin and use it in your 'blog' app.

Generate only tests from existing model / controllers

I have a Rails3 app that is based on someone else's work. For some reason they decided not to supply the tests with the app, which I am finding frustrating.
What I want to be able to do is scaffold the tests for all the existing controllers and models so I can get a head start on creating the tests myself in test::unit. I don't want to recreate the models or controllers, just create the tests.
I am new to Rails, and have hunted about for the rake command that might do this, but all with no luck so far. Any advice / direction most appreciated.
I know it's a little old, but you can do this:
rails g scaffold Post -s
The -s makes it skip the files already created. Also, if you don't use the flag it just asks you if you want to override the file, so, no worries.
To only generate the associated test files for an existing Rails 3 app, I use "generate resource" but skip everything that I don't want:
rails g resource Post --skip --no-resource-route --no-migration --no-helper --no-assets
Other options can be found using rails generate resource --help
-s, [--skip] # Skip files that already exist
--resource-route # Indicates when to generate resource route
[--helper] # Indicates when to generate helper
[--assets] # Indicates when to generate assets
[--migration] # Indicates when to generate migration
Why not use generate scaffold? Because it might generate views that I'm not using.
There's no way to do this that I'm aware of. It would be pretty easy though to just create a temporary rails project and generate scaffolds for all of your models then copy the resulting test directory into the real project.
I.e.
rails new temporary
cd temporary
rails g scaffold Post title:string body:text
rails g scaffold Comment post:references author:string body:text
cp -r test ../real_rails_app/
etc.
This answer is now out of date. Up to date rails versions allow you to generate only the missing files with the skip option.

Resources