Why the path to assets is added after path segment ? Rails - ruby-on-rails

When I added a path segment to my Ruby on Rails app /pricing the path to assets started to be added after it like this which causes 404:
GET http://localhost:3000/pricing/assets/bootstrap.min.css
This is the route:
get 'pricing/:level', :to => 'welcome2#pricing', as: "package_signup"
This is the controller:
class Welcome2Controller < ApplicationController
def pricing
#package_signup = params[:level]
end
end
This is the link on the index page linking to pricing/bronze:
<%= link_to 'package_signup bronze', package_signup_path('bronze') %><button class="btn btn-success">Get Started</button>
How can I keep the path to assets the same ? like this:
GET http://localhost:3000/assets/bootstrap.min.css
This is where bootstrap is included:
<link href='assets/bootstrap.min.css' rel="stylesheet">

Add a / (forward slash) before assets. It ensures that assets will be picked from root URL not from the current URL.
Like this:
<link href='/assets/bootstrap.min.css' rel="stylesheet">

Related

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

How to include a manifest.json file in rails?

I have following html code in a view whose layout is false.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<link rel="manifest" href="manifest.json">
Jquery is being loaded but not the manifest.json, when I view page source and look at them I get this error:
No route matches [GET] "/manifest.json"
Even though I have included manifest.json inside the javascripts folder inside assets folder.
I also tried
<%= javascript_include_tag "manifest.json" %>
but that didn't work either..and that get routes error
I tried
<%= manifest_link_tag "manifest" %>
Again that didn't work out, gave error :
undefined method `manifest_link_tag'
I also added the manifest.json inside initializers/assets.rb but still no luck!!
I think you need to include it like this:
<link rel="manifest" href="<%= asset_path 'manifest.json' %>">
My solution is:
= tag(:link, rel: 'manifest', href: some_path)
or
= tag(:link, rel: 'manifest', href: asset_path('manifest.json'))

Using asset pipeline outside of ERB

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.

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" />

Problems Rendering View (ActionView::MissingTemplate ... Error) in Custom Plugin

I am trying to develop a plugin for Ruby on Rails and came across problems rendering my html view. My directory structure looks like so:
File Structure
---/vendor
|---/plugins
|---/todo
|---/lib
|---/app
|---/controllers
|---todos_controller.rb
|---/models
|---todos.rb
|---/views
|---index.html.erb
|---todo_lib.rb
|---/rails
|---init.rb
In /rails/init.rb
require 'todo_lib'
In /lib/app/todo_lib.rb
%w{ models controllers views }.each do |dir|
# Include the paths:
# /Users/Me/Sites/myRailsApp/vendor/plugins/todo/lib/app/models
# /Users/Me/Sites/myRailsApp/vendor/plugins/todo/lib/app/controllers
# /Users/Me/Sites/myRailsApp/vendor/plugins/todo/lib/app/views
path = File.expand_path(File.join(File.dirname(__FILE__), 'app', dir))
# We add the above path to be included when Rails boots up
$LOAD_PATH << path
ActiveSupport::Dependencies.load_paths << path
ActiveSupport::Dependencies.load_once_paths.delete(path)
end
In todo/lib/app/controllers/todos_controller.rb
class TodosController < ActionController::Base
def index
end
end
In todo/lib/app/views/index.html.erb
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"[url]http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd[/url]">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title>Todos:</title>
</head>
<body>
<p style="color: green" id="flash_notice"><%= flash[:notice] %></p>
<h1>Listing Todos</h1>
</body>
</html>
In /myRailsApp/config/routes.rb
ActionController::Routing::Routes.draw do |map|
# The priority is based upon order of creation: first created -> highest priority.
map.resources :todos
...
The error I get is the following:
Template is missing
Missing template todos/index.erb in view path app/views
Can anyone give me a hand up and tell me what am I doing wrong here that is causing my index.html.erb file to not render? Much appreciated!
EDIT:
I have already tried the following without success:
In /todo/lib/app/controllers/todos_controller.rb
def index
respond_to do |format|
format.html # index.html.erb
end
end
EDIT:
hakunin solved this problem. Here's the solution.
He says that I'm building a Rails engine plugin (I had no idea I was doing this), and it requires a different directory structure, one that appears like so:
File Structure
---/vendor
|---/plugins
|---/todo
|---/lib
|---/app
|---/controllers
|---todos_controller.rb
|---/models
|---todos.rb
|---/views
|---/todos
|---index.html.erb
|---todo_lib.rb
|---/rails
|---init.rb
This required the following changes:
In todo/lib/todo_lib.rb
%w{ models controllers views }.each do |dir|
# Include the paths:
# /Users/Me/Sites/myRailsApp/vendor/plugins/todo/app/models
# /Users/Me/Sites/myRailsApp/vendor/plugins/todo/app/controllers
# /Users/Me/Sites/myRailsApp/vendor/plugins/todo/app/views
path = File.expand_path(File.join(File.dirname(__FILE__), '../app', dir))
# We add the above path to be included when Rails boots up
$LOAD_PATH << path
ActiveSupport::Dependencies.load_paths << path
ActiveSupport::Dependencies.load_once_paths.delete(path)
end
The change made above is in the line: path = File.expand_path(File.join(File.dirname(FILE), '../app', dir)). [Ignore the boldened 'FILE', this is an issue with the website].
Running script/server will render the index.html.erb page under todo/app/views/todos.
Looks like you want to build an "engine" plugin. Create "app" and "config" dirs in the root of your plugin dir (not under /lib). You can use app/views/ and app/controllers in your plugin as if it was a full featured Rails app. In config/routes.rb you should declare routes introduced by your engine.
See http://github.com/neerajdotname/admin_data for a decent example of what engine looks like.

Resources