I am developing an application that consists in two parts: A ruby command line application and a Rails application for the front-end.
I've been using ActiveRecord and the Rails models in the Ruby application by including them individually the following way:
Dir[File.dirname(__FILE__) + '/../../RailsApp/app/models/*.rb'].each do |file|
filename = File.basename(file, File.extname(file))
require_relative "../../RailsApp/app/models/" + filename
end
And by manually mantaining two nearly identical Gemfile files for dependencies (an approach that I think is not the best)
Yesterday I added Devise to the Rails application, and now when the ruby app tries to include the user model, the message undefined method devise for class <xxxxx> appears.
I added the devise gem in my ruby app's Gemfile, but the error continues. If I understand correctly, Devise is a Rails Engine, which is why it's not being loaded just by requiring the gem.
I read that a better approach to include Rails models inside another application is by requiring the environment.rb file, but when I tried that, I got an error with ActionMailer:
undefined method `action_mailer' for #<Rails::Application::Configuration:0xbbb54bc>
How can I solve the issue with devise? Is there a better way to include Rails models inside another application than the one I'm currently using to avoid mantaining two gemfiles ? Thanks
Even though this architecture must change in the near future, we managed to work around this error by including devise and its initializer in the ruby application.
# FIXME: Dependency needed in Rails but not in the engine.
require 'devise'
require_relative "../../RailsApp/config/initializers/devise.rb"
#Load all the models
You could try putting require 'devise' before you call the models, but I'm not sure if that would work?
I agree that this general architecture feels wrong.
I would extract the code that is common to both applications to a separate library and then include that library in both applications. Your easiest bet to do this is to make your own library into a Gem and then include it both Gemfiles. The common gems will be specified in the shared library. Making Gems is really easy. Good instructions can be found at http://asciicasts.com/episodes/245-new-gem-with-bundler (or the associated Railscast).
Your command-line app probably shouldn't need to care about Devise. If you need a User model in both, you can just include it in the shared library and then add any extra functionality (such as Devise) in the Rails app.
Does that help?
You could move the time of loading your models into the parent app initialization step, rather than at the time your gem is loading itself.
Build a shared_code gem, as your other answer suggests.
Move your shared_code loading loop into an initializer file (such as require 'user')
List the gem dependencies (like devise) of your models in the shared_code gemspec.
In your shared_code gem, include a generator to install the initializer file into apps that use the shared_code gem.
Then to use your shared code in the parent app,
Gemfile:
gem 'shared_code'
console:
rails generate shared_code:install
This is the same pattern devise and other gems use to configure themselves at the correct time in the initialization sequence of the parent application.
If you use require_relative on the devise initializer in the user.rb file itself, within the shared_code gem, you are removing the possibility that two different parent applications that are using your shared_code might need to initialize devise (or another gem that both the app and your gem depend on) differently.
Details on the generator:
You can create the shared_code:install command by creating the generator like this:
lib/generators/shared_code/install_generator.rb
module SharedCode
class InstallGenerator < Rails::Generators::Base
source_root File.expand_path('../templates', __FILE__)
def copy_initializer_file
copy_file "shared_code.rb", "config/initializers/shared_code.rb"
end
end
end
Put your model load code into lib/generators/shared_code/templates/shared_code.rb
Related
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.
This may be a bit of a contrived question, but I'm working on a Rails API and want to keep the API middleware stack minimal, while providing an OAuth endpoint that requires a few of the more complex middlewares. My thought was to make it into an engine, and include that engine in the application.
However, I thought there would be an easier way to create a Rails Engine than generating a new engine gem and including the gem in my Gemfile. Is there a way to just... require 'lib/engines/my_engine' from application.rb or something? I shouldn't need a gemspec just to include an unbuilt engine - I can put all the dependencies in the main app's Gemfile.
Really all I'm trying to do is get a separate middleware stack for a small set of routes!
I've discovered that an engine can be included just by requiring it as per the Rails::Engine documentation:
ensure that this file is loaded at the top of your
config/application.rb (or in your Gemfile)
So I tried this, and it worked:
application.rb:
# after Bundler.require(...)
require_relative '../lib/engines/oauth_server/lib/oauth_server'
So that answers this question. And technically all that is required in this case, rather than a whole gem structure, is a file in a lib directory containing a class that inherits from Rails::Engine (it has to be in lib to ensure the adjacent app, config, vendor etc. directories will be included automatically if present). And of course a config/routes.rb file if you intend to actually use this engine for anything ;)
For instance, my engine (required above) just looks like this:
module OauthServer
class Engine < ::Rails::Engine
middleware.use ActionDispatch::Cookies
middleware.use ActionDispatch::Session::CookieStore
middleware.use ActionDispatch::Flash
end
end
However, I also discovered that a Rails engine seems to inherit the middleware from the app it is included in, so I'm back to my original question, which someone has already asked previously: Build 2 middleware stacks in Rails app
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.
I followed http://railscasts.com/episodes/245-new-gem-with-bundler to make a gem with bundler and this is great for gems where i only need a lib, is there a standard practice for gems where i need to create mini apps with assets/controllers/models/views ?
You would be looking to create an engine at that point. Reading the Engines Guides guide should give you a great start on that.
The bare-bones components you need inside your gem are a file at lib/your_gem.rb that serves the purpose of simply requiring whatever it is your gem needs. If your gem has no other dependencies, then it looks like this:
require 'your_gem/engine'
One line, so much power. The lib/your_gem/engine.rb file it requires has this code in it:
module YourGem
class Engine < Rails::Engine
end
end
By simply inheriting from Rails::Engine, this triggers an inheritance hook on Rails::Engine that notifies the framework that there is an engine at the location of your gem.
If you then create a file at app/assets/stylesheets/your_gem/beauty.css, you can then include that in your application (assuming you have the asset pipeline enabled, of course) using this line:
<%= stylesheet_link_tag "your_gem/beauty" %>
Now that I've given you the short version of it, I really, really, really recommend reading the Engines Guide top to bottom to better understand it.
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