Using asset pipeline outside of ERB - ruby-on-rails

Is there a way to use the rails asset pipeline outside of erg? When I call stylesheet_link_tag(), I get a normal /stylesheets/ link instead of an /assets/ like I'd expect. I suspect that the stache gem just needs to register something with the asset pipeline, but I'm not sure what.
I'm using this gem: https://github.com/agoragames/stache
The code I'm using:
module Layouts
class Application < ::Stache::View
include ActionView::Helpers::AssetTagHelper::StylesheetTagHelpers
def title
'foobar'
end
def stylesheets
[
[stylesheet_link_tag('reset', :media => 'all')]
]
end
def javascripts
end
end
end
It's generating:
<link href="/stylesheets/reset.css" media="all" rel="stylesheet" type="text/css" />
It should be generating (it does this in erb templates):
<link href="/assets/reset.css?body=1" media="all" rel="stylesheet" type="text/css" />
Using rails 3.2.3.

Try
def stylesheets
[
[stylesheet_link_tag("#{ActionController::Base.helpers.asset_path('reset.css')}", :media => 'all')]
]
end
also read https://stackoverflow.com/a/9341764/643500

The proper solution is to remove the:
include ActionView::Helpers::AssetTagHelper::StylesheetTagHelpers
line at the top.

Related

Rails not rendering public/index.html file; blank page in browser

I have a problem with my Rails + React app when I deploy it to Heroku. The React client is inside a client/ directory of the Rails app. Due to using react-router, the Rails server needs to know to render the index.html from the React build. When I deploy the client on Heroku, a script copies the content from client/build/. to the Rails app's public/ dir.
Now here is the problem: when my route detects a path like example.com/about it tries to render public/index.html. Here is the method:
def fallback_index_html
render file: "public/index.html"
end
However, the contents from this file are not sent to the browser. I get a blank page. I have added a puts "hit fallback_index_html" in the method and confirmed that this method is being hit. I have also opened the file in puts each line to confirm the file has the required html (this is what appeared in the logs from that puts and what SHOULD be sent to the browser):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="/manifest.json">
<link rel="shortcut icon" href="/favicon.ico">
<title>Simple Bubble</title>
<link href="/static/css/main.65027555.css" rel="stylesheet">
</head>
<body><noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="text/javascript" src="/static/js/main.21a8553c.js"></script>
</body>
</html>
The most recent fix I tried was going into config/environments/production.rb and changing config.public_file_server.enabled to true. This did not help.
I'm using Rails API, so my ApplicationController inherits from ActionController::API instead of ActionController::Base.
From Rails API docs it says:
The default API Controller stack includes all renderers, which means you can use render :json and brothers freely in your controllers. Keep in mind that templates are not going to be rendered, so you need to ensure your controller is calling either render or redirect_to in all actions, otherwise it will return 204 No Content.
Thus Rails API only cannot render HTML! The following allowed me to render the html without including everything from ActionController::Base.
class ApplicationController < ActionController::API
include ActionController::MimeResponds
def fallback_index_html
respond_to do |format|
format.html { render body: Rails.root.join('public/index.html').read }
end
end
end
The reason I am including ActionController::MimeResponds is to have access to the respond_to method.
My Rails application now renders index.html from my public directory when a subdirectory is hit and my React client / react-router takes over from there.

Capybara RSpec with CSS and JS?

rails (5.1.4)
rspec-rails (3.7.2)
capybara (2.16.1)
I'm trying to create a RSpec Rails 3.7 System spec as in https://relishapp.com/rspec/rspec-rails/v/3-7/docs/system-specs/system-spec .
Here my simple spec:
require 'rails_helper'
RSpec.describe "testing system", type: :system do
it "tests the spec" do
visit root_path
click_link 'Home'
save_and_open_page
end
The problem is that Capybara does render neither CSS content nor JS content after save_and_open_page call (in the browser) - just a plain HTML. The header inside this HTML-file contains some links
<link rel="stylesheet" media="all" href="/assets/application-ea5a1efcc44a908543519edabe00e74132151ebedeef3c1601921690d9162b5e.css" data-turbolinks-track="reload" />
<script src="/assets/application-ff63e43aef379fef744a00f21a8aadf96dc2ae8e612f8e7974b231f946569691.js" data-turbolinks-track="reload"></script>
but they reference some empty files.
Is there some way to fix it?
I tried some recipes, but still no luck. I tried to precompile the assets, to move "capybara.html" into the "public" folder, but no effect.
Modifying stylesheet_link_tag is not a good solution, a much better solution is to specify Capybara.asset_host which will add a <base> tag to any saved pages. Generally this would be set to something like
Capybara.asset_host = "http://localhost:3000/"
which would then load the JS/CSS assets from your dev server which would have access to the test mode compiled assets in the public subdirectory. Note: that none of this means the page will actually be functional since JS requests will still fail, DB records won't exist anymore, etc. Also, since it saves element attributes (not properties) a checkbox you just checked will probably not be checked in the saved page. However it will give you a generally styled page you can inspect the structure of. If all you're looking for is a current image of the page you should be using the save_screenshot/save_and_open_screenshot functionality provided by most of Capybaras drivers instead.
It has to do something with your assets.
Clear cache and run rake assets:clobber and rake assets:precompile
Still no luck, then check if Capybara is configured correctly.
Check app/views/layouts/application.html.erb has the correct Rails tags for stylesheets and javascripts. Something like this:
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= javascript_include_tag 'application' %>
On the command line, run:
rake assets:clobber
rake assets:precompile
Ensure that public/assets/ include:
.sprockets-manifest-<xyz>.json
application-<abc>.js
application-<def>.css
Open the .sprockets-manifest... file and you should see that there are application js and css files with filenames that match the actual public/assets/ files. This .sprockets-manifest file controls what actually gets included in the HTML head links and scripts when the Rails tags are replaced.
If this is still not working, ensure that the files are accessible by your user running the test (including the manifest). Occasionally lose the .sprockets-manifest file when copying files and in source control as it can appear to be hidden.
Finally, check your file log/test.log to see if there are any obvious errors being thrown during the tests.
I found a solution. Perhaps it's not the best one, but it works with me. If anybody find a better approach - let me know, please.
Run rake assets:precompile. I didn't even set RAILS_ENV=test.
Modify the stylesheet_link_tag method:
def stylesheet_link_tag2(*sources)
options = sources.extract_options!.stringify_keys
path_options = options.extract!('protocol').symbolize_keys
sources.uniq.map { |source|
tag_options = {
"rel" => "stylesheet",
"media" => "screen",
"href" => path_to_stylesheet(source, path_options)[1..-1]
}.merge!(options)
tag(:link, tag_options)
}.join("\n").html_safe
end
The idea is to turn the rendered link from this:
<link rel="stylesheet" media="all" href="/assets/application-ea5a1efcc44a908543519edabe00e74132151ebedeef3c1601921690d9162b5e.css" data-turbolinks-track="reload" />
to this:
<link rel="stylesheet" media="all" href="assets/application-ea5a1efcc44a908543519edabe00e74132151ebedeef3c1601921690d9162b5e.css" data-turbolinks-track="reload" />
eliminating the leading slash in the href attribute value (since we don't have a server running but just a saved HTML-page).
Replace the code inside the header in \app\views\layouts\application.html.erb to:
<% if Rails.env.test? %>
<%= stylesheet_link_tag2 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<% else %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<% end %>
Write a spec like this:
require 'rails_helper'
RSpec.describe "testing system", type: :system do
it "tests..." do
visit root_path
click_link 'Home'
save_and_open_page Rails.root.join( 'public', 'capybara.html' )
end
end
Add to .gitignore:
/public/capybara.html
Do the same thing with the JS-content.
UPDATE:
If you don't like modifying \app\views\layouts\application.html.erb you can do some monkey patching:
include ActionView::Helpers::AssetTagHelper
alias_method :old_stylesheet_link_tag, :stylesheet_link_tag
def stylesheet_link_tag2(*sources)
options = sources.extract_options!.stringify_keys
path_options = options.extract!('protocol').symbolize_keys
sources.uniq.map { |source|
tag_options = {
"rel" => "stylesheet",
"media" => "screen",
"href" => path_to_stylesheet(source, path_options)[1..-1]
}.merge!(options)
tag(:link, tag_options)
}.join("\n").html_safe
end
def stylesheet_link_tag(*sources)
if Rails.env.test?
stylesheet_link_tag2(*sources)
else
old_stylesheet_link_tag(*sources)
end
end
I usually put such code into app\helpers\application_helper.rb and add include ApplicationHelper into app\controllers\application_controller.rb
UPDATE 2
Setting Capybara.asset_host = "http://localhost:3000/" as #Thomas Walpole advised doesn't work. That's right - how can it work if http://localhost:3000/ is unavailable (AFTER the spec ran)? Of course - when I call save_and_open_page the HTML-file opens with a file://.... address - with no HTTP-server serving it. The attempts to set
Capybara.asset_host = "file://#{Rails.root}/public"
failed - looks like the base HTML-tag supports only http-adresses - not file://... ones. I checked it in Chrome and Firefox.
So my next code proposal is such:
include ActionView::Helpers::AssetTagHelper
alias_method :old_stylesheet_link_tag, :stylesheet_link_tag
def stylesheet_link_tag2(*sources)
options = sources.extract_options!.stringify_keys
path_options = options.extract!('protocol').symbolize_keys
sources.uniq.map { |source|
tag_options = {
"rel" => "stylesheet",
"media" => "screen",
"href" => "file://#{Rails.root}/public" + path_to_stylesheet(source, path_options)
}.merge!(options)
tag(:link, tag_options)
}.join("\n").html_safe
end
def stylesheet_link_tag(*sources)
if Rails.env.test?
stylesheet_link_tag2(*sources)
else
old_stylesheet_link_tag(*sources)
end
end
This eliminates the need to call
save_and_open_page Rails.root.join( 'public', 'capybara.html' )
instead you can simply call
save_and_open_page

Rails: Assets properly fingerprinted but not stylesheets and javascripts

So this is strange.. On my site, the image assets are getting properly fingerprinted but not the stylesheets and javascript files.
Here's what the link looks like in my view:
<%= stylesheet_link_tag "website", media: "all",
"data-turbolinks-track" => true %>
<%= javascript_include_tag "website",
"data-turbolinks-track" => true %>
And this is what it looks like once pushed to production:
<link data-turbolinks-track="true" href="/stylesheets/website.css"
media="all" rel="stylesheet" />
<script data-turbolinks-track="true"
src="/javascripts/website.js"></script>
.. while my images are properly fingerprinted:
<img src="assets/website/white-logo-904f6978b5ecfdad3fdb8ad8d3a995b6.png">
Any ideas as to why I'm getting this strange behavior, and how I can get it fixed?
Rails v4.0.4 / Ruby 2.1.2
By convention, the Rails asset pipeline recognizes application.js and application.css as the main asset manifest files.
If you want to include separate files, then you'll need to specify them to be precompiled in the environment config or in an initializer.
Try this:
# config/production.rb
config.assets.precompile += %w( website.js website.css )

How to invoke method in a controller in a ruby file or rake script file

If I have a method in a controller,
For example, I want call the show method in a script without opening the webpages.
Is it possible to do it ?
def index
#joseph_memos = JosephMemo.all
#joseph_memo = JosephMemo.new
end
# GET /joseph_memos/1
# GET /joseph_memos/1.json
def show
binding.pry
end
This should work in Rails console, run rails c and type the following to test.
app.get('/joseph_memos/1')
output = app.html_document.root.to_s
But, if you also want to turn into rake task. Create the lib/tasks/actions.rake in your rails app. And add the following lines.
namespace :actions do
desc "test show action"
task :show, [:id] => :environment do |task, args|
app = ActionDispatch::Integration::Session.new(Rails.application)
app.get("/joseph_memos/#{args[:id]}")
puts app.html_document.root.to_s
end
end
Then run, rake actions:show[1] to see the result.
Here is the result that works (that is, bundle exec rake "actions:show[1]" on zsh)
$bundle exec rake "actions:show[1]"
<!DOCTYPE html>
<html>
<head>
<title>Hello</title>
<link data-turbolinks-track="true" href="/assets/joseph_memos.css?body=1" media="all" rel="stylesheet" />
<link data-turbolinks-track="true" href="/assets/scaffolds.css?body=1" media="all" rel="stylesheet" />
<link data-turbolinks-track="true" href="/assets/application.css?body=1" media="all" rel="stylesheet" />
<script data-turbolinks-track="true" src="/assets/jquery.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery_ujs.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/turbolinks.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/joseph_memos.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/application.js?body=1"></script>
<meta content="authenticity_token" name="csrf-param" />
<meta content="lZqYRkVfhZUhMK8EQIRsdoX2l4IpTPPhHKB44DSaq7s=" name="csrf-token" />
</head>
<body>
<p id="notice"></p>
Edit |
Back
</body>
</html>
More examples: https://github.com/henrik/remit/blob/master/lib/tasks/dev_events.rake
Hope this is useful for you.
i think it's very much possible but implementing it won't be worth it. An alternative solution would be to create a service class that you can call in the show action and you should also be able to use the same class outside of the controller.
def show
MyShowActionHandler.new(params).do_something
end
class MyShowActionHandler
def initialize(params)
#params = params
end
end
Then just call MyShowActionHandler in a script and it should work as long as you load the rails environment.

How to have absolute path for stylesheets in mailer with the asset pipeline?

The view helpers in my Mailer template give me relative URLs to the stylesheet and images. Of course, this won't work if I'm viewing the email in Gmail, for example.
In apps/views/layouts/mailer.html.erb
<%= stylesheet_link_tag "application" %>
...
<%= link_to(image_tag("logo.png"), "http://mysite.com") %>
Renders as:
<link href="/assets/application-c90478153616a4165babd8cc6f4a28de.css" media="screen" rel="stylesheet" type="text/css" />
...
<img alt="Logo" src="/assets/logo-d3adbf8d0a7f7b6473e2130838635fed.png" />
How do I get Rails to give me absolute links instead? I'm on Rails 3.1, the asset pipeline is in effect.
`config.action_controller.asset_host handles the host prefix in views generated from an ActionController.
For anything generated in an email you're looking for the ActionMailer configuration options, more specifically:
ActionMailer::Base.asset_host will handle your image_tags and
ActionMailer::Base.default_url_options[:host] will look after your link_to tags.
eg:
ActionMailer::Base.asset_host = "http://blah.com"
ActionMailer::Base.default_url_options[:host] = "blah.com"
Note that you don't need to specify the http prefix for the default url host, you will for the asset host.
I have specified these inside my environment.rb after the application initializer. I would recommend setting an application configuration variable for each environments domain.
For rails 3.2 and ActionMailer use:
config.action_mailer.asset_host = "http://www.example.com"
This might be a bit of a hack, but if you specify an asset host, all helpers will take it into account when rendering links. So if you set
config.action_controller.asset_host = "http://mysite.com"
in your config, stylesheet_link_tag will include the host name.
In this thread rocketscientist and Joe asked about other ideas:
http://apidock.com/rails/ActionView/Helpers/AssetTagHelper/stylesheet_link_tag
You can generate full css as follows (if you do not care about asset hosting). However answer by David Radcliffe should work.
stylesheet_link_tag "http://www.railsapplication.com/style.css" # =>
<link href="http://www.railsapplication.com/style.css" media="screen" rel="stylesheet" type="text/css" />

Resources