I know this is probably an easy question but I am stumped here.
The application I am working on houses assets like so:
app
--assets
----fonts
----images
----javascripts
I like to organize assets efficiently to avoid a mess down the road so I am trying to break up images like so:
app
--assets
----fonts
----images
------icons
------views
--------home
--------admin
Ideally I would like to reference images like image.png without having to add the folder path in front of the asset like views/home/image.png which I believe has to be possible although not setup like that out of the box.
It's possible if you manually add all paths underneath app/assets/images to the Rails asset paths in your application.rb:
Dir.glob("#{Rails.root}/app/assets/images/**/").each do |path|
config.assets.paths << path
end
In Rails 4+ any changes to asset paths should be made in:
config/initializers/assets.rb
To add all subdirectories in app/assets/images to the path, add the following:
Dir.glob("#{Rails.root}/app/assets/images/**/").each do |path|
Rails.application.config.assets.paths << path
end
Afterwards, you can verify the asset paths in the rails console with the following:
Rails.application.config.assets.paths.each do |p|
puts p
end
Related
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.
I have a rails app in production with apache2 and passenger. But some of my images didn't appeared so i changed the path inside the 'image_tag' like this:
<%= link_to image_tag("/assets/#{product.image_url}", {:title => "Push it into cart!"}), line_items_path(product_id: product), method: :post %>
After this all work fine in production. But when i try in development, i got this error:
Sprockets::Rails::Helper::AbsoluteAssetPathError in Store#index
Asset names passed to helpers should not include the "/assets/" prefix. Instead of "/assets/cs.jpg", use "cs.jpg"
What i should do to make it work in both enviroments?
image_tag works without using /assets/ path as long as you have the asset pipeline enabled (which is the default) and your image is in app/assets/images/ folder. If your image is outside that folder it won't get precompiled so you'll have to add it to the asset precompilation, in your config/environments/production.rb add
config.assets.precompile += ['image.jpg']
I think that for your problem you shouldn't store the images of your products in the assets folder as this is used for the application images not for you content (models) images, those should be stored in the public folder public/uploads is commonly used for that by gems like paperclip
You should never use /assets/ prefix, it's possible that you just need to precompile assets for production.
rake assets:precompile RAILS_ENV=production
It also depends on where are you using the said asset, for example, when using it in stylesheet you should use image-url('image.jpg') rails css helper. When using it inline in the view, you use the image_tag helper, as you have.
My Rails app doesn't serve images at all.
image_url('picture.jpg')
# will result in url(http://localhost:3000/images/picture.jpg)
# but should be url(http://localhost:3000/assets/picture.jpg)
image_tag 'picture.jpg'
asset_url 'picture.jpg'
# will result in the same url / path as image_url()
Neither http://localhost:3000/images/picture.jpg nor http://localhost:3000/assets/picture.jpg exists, while http://localhost:3000/assets/images/picture.jpg does.
Here is a gist of my application.rb and development.rb: https://gist.github.com/maximski/1ccb75f6f89c02932239
I am in development environment and I don't want to precompile files manually. The app is pretty much much newly generated so the configuration is almost completely set on default.
This problem appear if images doesn't exists in app/assets/images directory. Check that app/assets/images/picture.jpg file is exists.
I use Rails 4. I can use URL helpers in my views to reference assets without thinking where the resources are located in the filesystem.
Is it easy to find location in the filesystem by providing only the asset name? I suppose that it should be possible as Rails do it somehow when serving assets.
For instance, if I use some gem and it has assets I'd like to have such a function:
f("chartkick.js") # => "/Users/username/.rvm/gems/ruby-2.0.0-p451/gems/chartkick-1.3.2/app/assets/javascripts/chartkick.js"
It was simple. Just went thru asset paths and checked the first existing file:
Rails.application.config.assets.paths.map {|x| x.to_s + "/chartkick.js" }.find { |x| File.exists?(x) }
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"