can I serve assets from inside of a gem - ruby-on-rails

I would like to package some common assets like css, js, and icon images into a gem for my personal use.
Can I use the assets from inside of the gem directly, or do I have to have a generator move them into the main app?

What you need to do is:
Make a railtie:
module MyGemName
module Rails
class Engine < ::Rails::Engine
end
end
end
Put them in a directory that would otherwise be a proper asset path, like lib/assets/stylesheets.
Use sprockets to include javascripts:
//= require "foobar"
Use sass to include stylesheets:
#import "foobar";
Use the sass function image-url if you refer to images inside your stylesheets:
.widget {
background-image: image-url("widget-icon.png");
}
The assets directory should behave exactly the same as if it was inside your own application.
You can find an example in formalize-rails, which has stylesheets, javascripts and images.

With Rails 3.2 you can create an engine and put the assets in the assets directory where they'll be automatically picked up. Beware though if you create a mountable engine using the generator, it'll create namespaced directories under javascripts, images, and stylesheets. Don't put your stuff in those subdirectories or the parent app won't find them. Just put them directly in javascripts, images, or stylesheets.

Related

How can I have assets compiled into image, stylesheet, and javascript directories?

The asset pipeline puts everything into the same directory. Images, stylesheets, and javascripts all go into /public/assets (although subdirectories are respected).
Is there a way to have them copied into /public/assets/images, public/assets/stylesheets, and public/assets/javascripts?
Adding to the confusion is this line in the rails guide:
http://guides.rubyonrails.org/asset_pipeline.html#coding-links-to-assets
In regular views you can access images in the public/assets/images directory like this:
But rails doesn't use or make a public/assets/images directory.
Solution #1:
Create a new subdirectory within the app/assets/ like all and move the
current asset directories into that the new folder; e.g.
mkdir -p app/assets/all
mv app/assets/{javascripts,images,stylesheets} app/assets/all/
Then when precompiling assets with RAILS_ENV=production rails assets:precompile
it should create those javascripts, images and stylesheets directories
underneath the public/assets directory;
public/assets/javascripts
public/assets/images
public/assets/stylesheets
Solution #2:
You can create a new directory somewhere else in your project; like assets,
instead of app/assets; and add that the new directory to the current Rails
asset paths configuration within the assets.rb initializer
# app/config/initializers/assets.rb
Rails.application.config.assets.paths << Rails.application.root.join("assets")
Then precompiling assets should have the same effect as Solution #1.
Solution #3
So, as part of the Sprocket-Rails Engine it preloads the app/assets
subdirectories with this following block of code:
# ~/ruby/gems/2.3.0/gems/sprockets-rails-3.2.0/lib/sprockets/railtie.rb:54
module Rails
# [...]
class Engine < Railtie
# Skip defining append_assets_path on Rails <= 4.2
unless initializers.find { |init| init.name == :append_assets_path }
initializer :append_assets_path, :group => :all do |app|
app.config.assets.paths.unshift(*paths["vendor/assets"].existent_directories)
app.config.assets.paths.unshift(*paths["lib/assets"].existent_directories)
app.config.assets.paths.unshift(*paths["app/assets"].existent_directories)
end
end
end
end
The line of interest is the
app.config.assets.paths.unshift(*paths["app/assets"].existent_directories)
It call to existent_directories off the *paths["app/assets"] is returning
all the subdirectories within the assets folder, hence why there are no
subdirectories in the public/assets folder when Sprocket computes its digested
assets.
In order to add those sub-directories back in, we have to modify the current
Rails configured environment for Sprockets; i.e.
Rails.application.config.configure. However, the Sprockets::Paths that is
included in the Sprockets::Configuration that
Rails.application.config.configure yields to does not allow public access to
its internal #paths variable, nor does it have an method to remove paths like
it does to add paths via its append_paths. Instead we have to duplicate the
current paths already included by the above Railtie initializer block, remove
the old "app/assets" subdirectories paths that we do not want, add in just the
"app/assets" directory we do want and then append them back into the configured
Sprockets environment; which looks something like this in a Rails initializer:
# app/config/initializers/assets.rb
Rails.application.config.assets.configure do |env|
old_paths = env.paths.dup
new_paths = old_paths - Rails.application.paths["app/assets"].existent_directories
new_paths << Rails.application.root.join("app", "assets")
env.clear_paths
new_paths.each { |path| env.append_path(path) }
end
Closing Comments
Using any of these solution should also mean that you will need to specify the subdirectory in all your
asset_path method calls within your view templates in order to find the
compiled asset; e.g.
<%= asset_path "images/example.png" %>
<%= asset_path "javascripts/application.js" %>
<%= asset_path "stylesheets/application.css" %>
/assets/images/example-ca63e56ac855bdfb187479a35a7476cd65c539727f84fea19e1ad258cf3d23f5.png
/assets/javascripts/application-a4f3e75c7f7aa6d6cbc2ebcbb436b12aca442553219883805baebdd2eecd5471.js
/assets/stylesheets/application-539757f75200b6ea43399bf5e25cbc2819c1e6a610f94d5c9beaf91fec89384e.css
I hope one these solutions help.

Devise apply css file style to the login form

i'm using devise for authenticate the users in my rails app, i've exported the views by using the comand
rails generate devise:views
i see that the files have a 'blank style' so how i can do for apply to them a mine custom file css?
Add gem in your Gemfile
gem "twitter-bootstrap-rails"
visit link for reference
https://github.com/seyhunak/twitter-bootstrap-rails
http://getbootstrap.com
You can find the generated devise view files in app/views/devise.
Just add needed html elements/css classes the same way you would to other view files.
Keep in mind that this will use your default(application.html.erb) layout.
Probably not the best way, but it works and it's not too messy:
devise uses the global application.scss styles by default.
So I just create a login.scss, signup.scss, etc. in my route assets/stylesheets directory and the add #import "login.scss" at the end of application.scss.
Just make sure these page are imported after whatever global styles you want to make sure they inherit.
Note:
As my application expands I usually end up abstracting everything into distinct stylesheets so my application.scss ends up being a list of imports anyway.
I'm sure there are better ways to do this, but this was the "I'm just a designer and need this to work without overcomplicating things" way,
Installation
Add this line to your application's Gemfile:
gem 'devise-bootstrap-views'
And then execute:
$ bundle
Add some minor css fix to your rails asset pipeline manifest
SASS
*= require devise_bootstrap_views
LESS
*= require devise_bootstrap_views_less
rails g devise:views:bootstrap_templates
If you want to go through in detail , you can refer this link : https://github.com/hisea/devise-bootstrap-views

Yeoman & Rails app: using grunt-rev task to revision shared assets

I have a Rails app which is not using the asset pipeline. The assets are managed by Yeoman (http://yeoman.io/) and Grunt tasks. We recently introduced a browser cache busting task called grunt-rev to revision the assets before deploying. This task re-names the assets with some uniqueness, then flow passes on to another task called grunt-usemin which updates the html and css files with the new asset names before copying them to the public folder.
For example, main.css in index.html looks like:
<link rel="stylesheet" href="styles/main.css">
And will be re-witten to:
<link rel="stylesheet" href="styles/f43ce6bf.main.css">
The Rails app works fine with local development as the assets are dynamically generated by Yeoman. But once deployed, the assets public folder contains all the revved assets and the Rails views (written in haml) cannot find them. Links like the one below are now dead...
%link{:href => "/styles/main.css", :media => "screen,print", :rel => "stylesheet"}
So I've come up with a few ideas I think might work.
Symlink main.css -> f43ce6bf.main.css
Add a view helper to find the assets
Inline the javascript & css into the view as it is not too big
Fork grunt-usemin to add haml support, then run it against the views within Rails
But am not sure whats best? or am I missing a much easier solution?
UPDATE: I'm now using the helper like below
module ApplicationHelper
def busted_css
#busted_css ||= begin
if Rails.env != "development"
File.join("/styles",
File.basename(Dir["public/styles/*main.css"].sort_by {|f| File.mtime(f)}.reverse[0])
)
else
"/styles/main.css"
end
end
end
end

Add folder to asset pipeline path?

We have a rails app that I recently updated from Rails 3.0 to Rails 3.2. This app services multiple clients. To customize it for each client, we have the directory app/themes. In there are submodules. Each submodule contains things like locales/en.yml, views/layouts, views/controller_name, etc. We use the prepend_view_path to add the theme views, and the I18n.load_path to add in the locales. We're looking at using the asset pipeline so we can keep all the mix of client material out of the public directory, and keep it contained in each theme.
Is there a way i can dynamically tell rails to load which theme/theme-name/assets folder i want? We use settings logic to set which theme is active. So if i have the theme set to "google", the ApplicationController then loads files from the path:
app/themes/google/locales/*.yml
app/themes/google/views
What I'd like to be able to do is have the manifest file,
app/themes/google/assets/stylesheets/application.css
easily accessible to the layout, much like you would in an app/views/layouts file:
= stylesheet_link_tag "application"
Is there a way i can do this? or do we need to manually move the assets into the actual assets directory?
Was able to do it in the application.rb:
require "#{Rails.root}/app/models/settings.rb"
config.assets.paths << "#{Rails.root}/app/themes/#{Settings.theme}/assets/stylesheets"
config.assets.paths << "#{Rails.root}/app/themes/#{Settings.theme}/assets/images"
config.assets.paths << "#{Rails.root}/app/themes/#{Settings.theme}/assets/javascripts"

Asset Pipeline Cacheing CSS?

I am working on a Rails 3.1 app. I have created an application.css.scss.erb file. The .erb is in the end because I want to load a variable from the config file as the color variable in the css:
$highlight1: #<%= COLOR.highlight1 %>;
$highlight2: #<%= COLOR.highlight2 %>;
Everything works fine, but the problem I am having is that whenever I change a value inside COLOR.highlight1, it doesn't reflect the change until I go in to my css file and change something (i usually add some spaces and save it). Thats when I see the change. Clearly rails is looking to see if the file was changed in order to update the change.
Is there any way that at least during development, this can be turned off and I can see the changes without having to also modify the css file?
Any critique/opinions on my technique are also welcome
The Sprockets depend_on directive is used to declare these kinds of dependencies. So at the top of your css.scss.erb file, with the other directives (require and friends), put something like:
//= depend_on "/path/to/colors.rb"
Then when the file /path/to/colors.rb changes, it will force the css to update too.
Unfortunately, I have never gotten this to work with a relative path to a file outside of one of the asset directories (javascripts/stylesheets/images) so there may be something in the way Sprockets resolves paths that prevents this, or else I'm missing something. That leaves you with the options of specifying an absolute path, which will almost certainly not work in across all your app environments, or putting the constants file into your asset directories (app/assets/stylesheets/colors.rb, for example).
For reference, here's the doc for the depend_on directive from the Sprockets (2.0.3) source, in sprockets/directive_processor.rb
# Allows you to state a dependency on a file without
# including it.
#
# This is used for caching purposes. Any changes made to
# the dependency file will invalidate the cache of the
# source file.
#
# This is useful if you are using ERB and File.read to pull
# in contents from another file.
#
# //= depend_on "foo.png"
#
If anyone does know a way to specify relative paths to other places like config/initializers or something, please let me know!
In addition to David Faber's answer. I needed to use relative paths too.
I wanted to generate a js file with the locale dictionary, which would update if the locale files were changed:
//= depend_on "../../../config/locales/en.yml"
//= depend_on "../../../config/locales/ja.yml"
var locales = <%= locales.to_json %>;
Turns out that currently (Rails 3.2.3) relative paths only work if the relative path is also in the assets path!
So the ugly solution is to add the path in config/application.rb:
config.assets.paths.unshift Rails.root.join("config", "locales").to_s
http://guides.rubyonrails.org/configuring.html
config.assets.compile is a boolean that can be used to turn on live Sprockets compilation in production.
might want to try that, I'm not sure if its getting compiled real time though, at least it should disable the caching.
maybe try:
config.assets.digest = true
in your development config file
I try this, it work
in application.rb
config.autoload_paths += %W(#{config.root}/lib/assets_variables)
config.assets.paths << File.join(Rails.root, 'lib', 'assets_variables')
in lib/assets_variables/color.rb
module Color
def self.default
'blue'
end
end
in app/assets/stylesheets/color.css.scss.erb
//= depend_on "color.rb"
$default_color: <%= Color::default %>;
.content {
color: $default_color;
}

Resources