Loading parts of a Rails 3 application - ruby-on-rails

I am developing a gem for Rails 3 that consists of two main components. The first is a rails generator that adds some new files/folders to a rails project. The second is a runtime environment that loads all the aforementioned files (some ruby classes that use my DSL) as well as a portion of the default Rails stack. Essentially it's everything you'd expect to be able to access in rails c, sans routing, controllers, helpers and views. What is the proper way to load a Rails environment, except for specific portions?
Sidenote: I'd love to see any good articles regarding requiring Rails applications.

I am not entirely clear what you mean, or if this will help, but it sounds similar to something I do in a utility I wrote.
My utility loads the environment like so:
#!/usr/bin/env ruby
require File.expand_path('../../config/environment', __FILE__)
The require of the ../../config/boot will cause the gems defined in your Gemfile to load. So if you needed only part of the Rails stack then you would only require that part of the stack in your Gemfile.
This gives me my rails context, access to models and other resources.
(UPDATE)
To skip parts of the rails stack - take a look at how its been done to swap out ActiveRecord:
http://www.mongodb.org/display/DOCS/Rails+3+-+Getting+Started
Hope that helps.

Maybe you need Rails::Initializable?
You can do like that:
initializer "active_support.initialize_whiny_nils" do |app|
require 'active_support/whiny_nil' if app.config.whiny_nils
end

Related

When to load Gem code when depending on rails

I'm developing a Gem that is to be used exclusively in Rails projects. It has been developed inside of a Rails application's lib directory and is now to be extracted in a separate Gem.
Some of the classes depend on the Rails framework to be loaded though. Two examples:
class OurGem::Hookup
CONFIG_PATH = 'config/hookup.rb'.freeze
[...]
end
class OurGem::RoutingContainer
include Rails.application.routes.url_helpers
[...]
end
Normally, I load the Gem code in the Gem's main module file using require. But as this is loaded by bundler, Rails is not ready and things like Rails.application and Rails.root cannot be used. The first example could be worked around by not evaluating the path at load time, but the second one seems kind of tricky to me.
What is the proper way of doing this? Register an initializer using a railtie and require the "delicate" files there?
This is a strange setup, because your gem depends on your rails app and your rails app depends on your gem.
This looks far too coupled to me. Have you considered creating a self-contained rails engine that your main app mounts, instead?
You might be able to get away with doing this, though:
# Gemfile
gem 'our_gem', require: false
# config/initializers/our_gem.rb
require 'our_gem'
OurGem::Hookup.config_path = '...'
This ensures that your gem is only being loaded after the rails application initialises - so things like Rails.application.routes.url_helpers will be defined.

Include views in a Rails plugin

I'm building a Rails plugin that currently provides controllers and models to an app. However I get a missing template error when it comes to views. I have the following:
%w{ models controllers views }.each do |dir|
path = File.join(File.dirname(__FILE__), 'app', dir)
$LOAD_PATH << path
ActiveSupport::Dependencies.autoload_paths << path
ActiveSupport::Dependencies.autoload_once_paths.delete(path)
end
The controllers and models are loaded but not views. The Rails guide says it can be done but doesn't have an example. Is there a way to include them (or a similar alternative)?
You didn't include the version you're working with ... reason that's important is after rails 4 came out - you're not supposed to be doing plugins anymore ... Gem Vs Plugin Vs Engine in Ruby on Rails.
If you're not supporting a legacy app, would highly recommend going with a 'rails engine', the Devise Gem is one great example...it's a self-encapsulated app, with it's own view files & sounds exactly like what you're trying to do. Additionally, it shows you can even use generators to move your default views/controllers out of the engine & change the basic routing if someone needs to customize your work further.

Require multiple rails sites from script

I want to access the databases used by two completely separate Rails sites from an external Ruby script. I know that I can require the environment of a Rails app, like this:
#!/usr/bin/env ruby
require "/path/to/rails/app/config/environment"
I can then use all the models defined in the Rails app to read and write data and it will use the database settings defined for the site.
But now I want to do this for two sites at the same time, e.g.:
#!/usr/bin/env ruby
require "/path/to/first/rails/app/config/environment"
require "/path/to/second/rails/app/config/environment"
Clearly, that will not work as the application can not be initialised twice. Is there any way to avoid the collision?

Creating a common style gem

We are creating several applications (new development) at our company. To try and establish a common look and feel between these apps I would like to create a gem that:
Incorporates specific versions of gems like bootstrap-sass
Declares several common CSS styles, using mixins from bootstrap where appropriate
Provides other assets as well.
I want the applications that we develop to merely have to include my common-ui gem, they should not include things like bootstrap directly.
The pattern for exposing scss from a gem is pretty straight forward (just take a look at the bootstrap-sass project); where things get interesting is when my scss needs to access bootstrap. When an application includes my scss, the pipeline complains that it cannot locate bootstrap and everything comes to a halt.
What is the best approach to creating a gem that does what I have described?
============================================================================
To better follow SO's format, I am going to answer my question with what I came up with (and why I think it works). I am somewhat new to rails, so my answer is by no means authoritative. Feel free to comment or propose a better way of doing things.
============================================================================
See caveat in the question, this may be a spectacularly bad way to solve this problem
Here's what's working so far. For a gem to expose assets to an application's asset pipeline, it must be initialized as an engine. The problem with one gem using another's assets is that the other gem's engine may not have been initialized and therefore the pipeline doesn't know about the other gems assets.
To work around this, just require the root file from the other gem in your root file. So in lib/company-common-ui.rb, I have the following:
require "company-common-ui/version"
module Company
module Common
module Ui
# We don't really need anything here
end
end
end
require "company-common-ui/engine"
require "bootstrap-sass"

Best practices when including Rails models in another application

I'm developing a ruby application that uses the models and data from another Ruby on Rails web application as its main data source.
The Rails models were included in this application by including the environment.rb file in the main file like this:
# Require Rails
require_relative "../../RailsApp/config/environment.rb"
This works but there are uninitialized dependencies when loading models that use gems that are defined in the Rails Gemfile. (For example, acts_as_taggable_on, rack-pjax, devise, etc)
This ruby application dependencies are also managed through Bundler, so at the moment the only way to get the application working is to copy and paste the contents from the Rails' Gemfile into the ruby app's Gemfile.
Obviously this approach is not optimal as the gem requirements are duplicated.
Is there a better way to include Rails and the dependencies that its models require in another application? Is there a way to include a Gemfile into another?
Here are some options, in order of simplicity
Just keep everything in one app, a lot of stuff is easier this way
Use plugins to share common code
Use web services to share data
You could extract the models and code out from RailsAppA into a Gem. RailsAppA then includes that Gem and uses it.
The gem can remain in a private repository and does not need published.
Both apps would then do something like:
gem "yourapp-modelage", git: "http://github.com/you/yourapp-modelage.git"
Then, App2 would also use that Gem... How much goes into the Gem will depends on how much you need to re-use.

Resources