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"
Related
I've got a simple rails gem (created using bundler) and I'd like to extend it by adding some CSS and javascript functionality. However, I'm unsure how to go about this and where to add the files. In particular, I need need more information on how it all fits together with the asset pipeline once it gets included in another project.
Can anyone give me the lowdown on how this works and either provide some simple examples or link to a tutorial? Literally 1 css and 1 js file is all I'm looking to include. Thanks.
You could write the gem as an engine. This allows you to have an app folder in the gem just as any Rails application would have. You can add models, views, controllers, assets etc.
Once you have it set up it's quite intuitive and it's a familiar way to create a gem if you're used to creating Rails apps.
This should get you started:
http://coding.smashingmagazine.com/2011/06/23/a-guide-to-starting-your-own-rails-engine-gem/
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'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.
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.