What's the best way to require source files when writing a gem - ruby-on-rails

I'm converting the models folder of a rails app into a gem so more rails app can use the same domain model layer.
In the initial rails app, the loading of all model files is handled by activesupport so there no require statement everywhere. But in the gem version, it has to be done manually. I had a look at the code of popular gems such as rspec, factory_girl and state_machine and it looks like they all require all necessary source files in one file, usually named after the project.
The downside of this approach is that you need to maintain one file listing all the others and that seems a bit clumsy. And even though I have hit that problem yet, I can foresee cirular dependency issues.
Another way would be to have each source file requiring the files it needs. That would work in the standalone gem as well as in the rails app. But I haven't seen examples of gems using that technique so I'm wondering if there is a downside I'm not seeing?
thanks

You're talking about model files, if so, simply adopt the same structure as a standard Rails app and make your gem inherit from Engine. Everything will be included painlessly.

Related

Include a gem's code as part of a rails project

My rails 4 project depends on Comfortable Mexican Sofa (CRM) which is loaded as a gem.
I checked out this gem as a submodule of my git repository.
Moving forward, this gem is becoming part of my project: I'm adding features to it
that depends on classes of my projects.
I would like to keep this gem as a submodule (to be able to pull changes from
the main repository) but still be able to add code that rely on my project.
What's the cleanest way to achieve that ?
(should I put the whole gem submodule into my lib folder for instance ?
should I keep it referenced as a gem ? etc...)
should I keep it referenced as a gem
Yes, you need to keep it referenced as a gem.
One of the benefits of using external libraries is that they are maintained by a group of very clever people (most of the time). It would be highly unlikely that you're going to be able to keep the submodules you include up to date as much as the gem owners etc.
What you're best doing is either overriding specific parts of the gem (EG like how many people override Devise functionality with their own controllers), or to see about creating an API for the gem, which you can populate from your app.
For me, in development, separation is always better then binding. I would recommend to leave it as gem and develop in the separate repository.

How to use googlecharts library in rails?

I want to use googlecharts in my rails App, and I decided use it directly without using wrapper library.
Currently I download jsapi file from https://www.google.com/jsapi and rename it to jsapi.js, then move the file to vendor/javascripts/google/jsqpi.js.
Then require the file in application.js.
Now I can use the library I want only to know if this is a right way to use the third party library in rails.
Is there better way than this way?
That is perfectly acceptable. vendor/assets/javascripts is the correct location for third-party javascript files.
Sometimes you can find gems that include third-party javascript libraries and integrate them into the asset pipeline for you (e.g. jquery-ui-rails gem). This is nice because it makes you not responsible for handling the actual files and is easier on your version control software (a single line in your Gemfile vs entire files). You can also update the files with bundler. However, this tends to only be practical for really popular libraries. Sometimes you can find gems for the javascript library you are looking for, but the gem hasn't been updated in ages. Of course, you could always roll your own gem that includes the libraries you want.
Have you taken a look at googlecharts gem
its full of examples

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.

Create plugins or gems for Rails 3?

I have features I would like to be portable between my own Rails applications.
I wonder if I should create a gem or a plugin for each feature I want to be portable (sharable).
They are just for Rails (for now) because they include css, html, js and image files.
But I have been wondering, the things provided with plugins could be provided with gems too but not the opposite? So maybe it's better to learn how to create gems, because then you I don't have to learn how to create both gems and plugins? And gems seem to be more popular these days.
But then, from what I can understand one gem is shared between all rails app in the OS. So that means I can not customize it for each Rails app right? In that case, maybe creating a plugin is better cause it should be allowed to customize (editing css, js etc) each feature and to have it stored inside the Rails app itself and not in the OS level.
Some advices would be appreciated!
UPDATE:
So gem works great with css, html, js and image files? In a plugin I think you can have a MVC, your own models, views and controllers. Quoted from Rails guides "Storing models, views, controllers, helpers and even other plugins in your plugins". Is this possible too in a gem? Eg. I want to add a extension that gives me a nice Shopping cart (with own migrations, mvc, asset files) that will be hooked into the current Rails app. Is this possible as gem or only as plugin?
You're right that gems offer a little more than plugins. Versioning and dependencies on other gems being the main ones for me.
One gem needn't be shared across everything using ruby. You can install multiple versions of a single gem and specify in your environment.rb that a gem requires a specific version. E.g.
config.gem 'my-gem', :version => '1.2.3'
Also you can freeze gems into your rails application so that you know you are working with a specific version.
You might want to look at the jeweler gem which makes creating your own gems easier.
UPDATE
To include CSS, javascript etc I think you'll need to make an Rails engine which can then be bundled as a plugin or a gem. I've not done this but there's some coverage here and here.
The push with Rails 3 seems to be towards gems and away from plugins as a lot of support has been added to make gems work as well or better than plugins ever did. A well constructed gem is a great thing to have and share between different applications, and also reduces the amount of testing you will have to do since you can test the gem thoroughly before integration.
For extensions to Rails that use CSS, HTML and other assets, it might be that you need to build an engine to bundle this all up and allow it to fit neatly into an application.
As of Rails 4, plugins will no longer be supported.
Gems are the way forward.

Resources