On my Application.html.erb page I have my navbar and footer so that they are shared accross all pages. I am referencing images on this page as so
src="assets/img-1.jpg"
and they appear but only on my index page "localhost:3000".
When I navigate to these pages:
localhost:3000/pages/contact
localhost:3000/pages/home "index page"
localhost:3000/pages/portfolio
localhost:3000/pages/schedule
None of the images are being found. Here are is my route setup:
Rails.application.routes.draw do
root 'pages#home'
get "/pages/:page" => "pages#show"
end
Here is my pages controller:
class PagesController < ApplicationController
def show
if valid_page?
render template: "pages/#{params[:page]}"
else
render file: "public/404.html", status: :not_found
end
end
private
def valid_page?
File.exist?(Pathname.new(Rails.root + "app/views/pages/# {params[:page]}.html.erb"))
end
end
Again: images referenced as src="assets/img-1.jpg" on my application.html.erb are being found but only when I am in the index page "localhost:3000/", what I am doing wrong?
You must use the rails assets helpers to reference your image
= image_tag 'img-1.jpg'
And please have a look here, it will save you many a headache.
You are missing a /.
it will be src="/assets/img-1.jpg".
For production:
make sure it's in the /public directory or you use asset_path. Otherwise you won't see it after you precompile the assets for production.
Related
while trying to familiarize with using resources for planning routes,
I encountered a weird error:
No template for interactive request
ShoppersController#index is missing a template for request formats: text/html
Here are the routes mapping
routes.rb
Rails.application.routes.draw do
resources :shoppers
end
shoppers_controller.rb
class ShoppersController < ApplicationController
def index
end
def create
#shopper = Shopper.new
end
end
shoppers.html.erb
<h1>Welcome Shoppers</h1>
Does anyone know how to solve this?
Thanks for all the feedbacks you share.
It's because the name of your view is wrong. As the error you're getting says: 'Rails expects an action to render a template with the same name contained in a folder named after its controller'
So in your case, the structure needs to be:
app
controllers
shoppers_controller.rb
views
shoppers
index.html.erb
new.html.erb
Reference: https://guides.rubyonrails.org/layouts_and_rendering.html#rendering-by-default-convention-over-configuration-in-action
Create a view with the name of the action in the controller!
In my rails blog app, I have posts and pages. I am using friendly_id gem. Is it possible to have clean URLs without the controller for both post and pages at the same time? They should look like that:
example.com/my-post
example.com/my-page
Thank you.
Of course you can, but you will need to be extremly carefully to avoid duplicate slugs between pages and posts.
routes.rb
Rails.application.routes.draw do
get ':id', to: 'pages_posts#show', as: 'page_or_post'
end
pages_posts_controller.rb
class PicturesController < ApplicationController
def show
if #page = Page.friendly.find(params[:id])
render 'pages/show'
elsif #post = Post.friendly.find(params[:id])
render 'posts/show'
else
raise ActiveRecord::RecordNotFound
end
end
end
*.html.erb
link_to 'link', page_or_post_path(id: object.slug)
I'm replacing the default robots.txt file in rails with a dynamic one where I can control what the bots see on my site.
I've deleted the public/robots.txt file. In my PagesController, I've defined a robot's action
def robots
respond_to :text
render 'pages/robots.txt.erb'
expires_in 6.hours, public: true
end
And in my routes
get '/robots.:format' => 'pages#robots'
I've created a robots.txt.erb file in the pages views directory to respond only when the site visited is the production site.
<% if Rails.env.production? %>
User-Agent: *
Allow: /
Disallow: /admin
Sitemap: http://www.example.com/sitemap
<% else %>
User-Agent: *
Disallow: /
<% end %>
When I went to the site and robots.txt path, I got the error
Template is Missing
It wasn't finding the robots file in the pages view directory. I had previously named this file robots.html.erb and then renamed it to robots.txt.erb. The error persisted. Finally I just removed the respond_to line so now the robots action in PagesController is just
def robots
render 'pages/robots.txt.erb'
expires_in 6.hours, public: true
end
This works when I go to the URL.
I'm just curious whether or not this is good practice and if I'm losing anything by removing the respond_to action.
You will need to start by creating a route like this
# config/routes.rb
#
# Dynamic robots.txt
get 'robots.:format' => 'robots#index'
Now we have to create a controller called robots
# app/controllers/robots_controller.rb
class RobotsController < ApplicationController
# No layout
layout false
# Render a robots.txt file based on whether the request
def index
...
end
end
I hope that this help.
Have a Help system for a Rails App, that uses a static page controller.
def show
if valid_page?
render template: "help/#{params[:page]}"
else
render file: "public/404.html", status: :not_found
end
with route
get 'help:page' => 'help#show', :via => [:get]
The Help folder started to become overwhelming with all the static views for the application.
So I wanted to split the views into sub-folders with associated controller - so in the Help folder is now
---Welcome
----index.html.erb
----about.html.erb
----contact.html.erb
---Blog
----index.html.erb
etc
Under the help folder there are two dozen or so sub folders each with 3-6 help files, without creating a route for each subfolder, is there an way to have a single smart route to reference controller(folder) and page.
get 'help:folder:page' => 'help#show', :via => [:get]
def show
if valid_page?
render template: "help/#{params[:folder]}/#{params[:page]}/"
else
render file: "public/404.html", status: :not_found
end
Any ideas?
Here's how it should work:
#config/routes.rb
resources :help, only: [:index, :show] #-> url.com/help/:id
This will allow you to use the following:
#app/controllers/help_controller.rb
class HelpController < ApplicationController
def show
#page = Help.find params[:id]
#no need to rescue this, rails will automatically throw a 404 error if not found
end
end
#app/models/page.rb
class Page < ActiveRecord::Base
#columns id | type | title | body | created_at | updated_at
end
#app/models/help.rb
class Help < Page
end
The main issue you have is that you're storing each page as an .html.erb file. Whilst this will be okay in certain circumstances, in this case it's going to get very messy, very quickly.
You'll be much better creating a Model and table to store the help pages you need, allowing you to collate & invoke them as required. An added benefit to this will be that there will be no validation (Rails will handle it all), and you'll be able to use one view file to get it working:
#app/views/help/show.html.erb
<%= #page.title %>
<%= #page.body %>
There are many solutions for creating customized error handling pages, but almost none for Rails 4:
Basic Rails 404 Error Page
Dynamic error pages in Rails
The standard answer of encouraging people to modify 404.html in /public doesn't work for me because I want to use the CSS theme that resides in the asset pipeline. Is there a way that html files can access those styles defined in the asset pipeline? If not, is there a way to create a custom error handler that has access to the pipeline?
For Rails 4.1 I like this answer, add an asset type better; however I have not tried it. On Rails 4.0.8, these three references helped me:
Dynamic error pages is the second reference in the question. This worked just fine for me.
Custom error pages may have cribbed from the first reference, or the other way around, but goes the extra mile by adding some information about testing with Capybara.
I did not do the Capybara testing because I didn't want to change the test configuration; however, RSpec-Rails Request Specs clued me in to test these requests independently and see that they complete and return the correct content.
What follows is a nutshell description of what is taught by the three references:
Add the following setting to config/environments/production.rb
# Route exceptions to the application router vs. default
config.exceptions_app = self.routes
Edit the routing configuration, config/routes.rb to direct the error pages to an errors controller
# error pages
%w( 404 422 500 503 ).each do |code|
get code, :to => "errors#show", :code => code
end
will route the 404, 422, 500, and 503 page requests to the show action of the errors controller with a parameter code that has the value of the status code.
Create the controller, app/controllers/errors_controller.rb. Here is the entire content:
class ErrorsController < ApplicationController
def show
status_code = params[:code] || 500
flash.alert = "Status #{status_code}"
render status_code.to_s, status: status_code
end
end
My preference was to set a status message on flash.alert
Create the pages themselves. I use .erb Here is app/views/errors/500.html.erb
<p>Our apology. Your request caused an error.</p>
<%= render 'product_description' %>
So you see that you can render a partial. The page renders with all of the layout boilerplate from app/views/layouts/application.html.erb or any other layout boilerplate that you have configured. That includes the <div id='alert'><%= alert %></div> that displays the status message from the flash.
Tested with RSpec by adding a test file, spec/requests/errors_request_spec.rb. Here is abbreviated content of that file that shows a test of the 500 status page:
require 'rails_helper'
RSpec.describe "errors", :type => :request do
it "displays the 500 page" do
get "/500"
assert_select 'div#alert', 'Status 500'
assert_select 'div[itemtype]'
end
end
The first assertion checks for the flash alert. The second assertion checks for the partial.
We've made a gem which does this for you: exception_handler.
There is also a great tutorial here.
I also wrote an extensive answer on the subject here.
Middleware
# config/application.rb
config.exceptions_app = ->(env) { ExceptionController.action(:show).call(env) }
Controller
# app/controllers/exception_controller.rb
class ExceptionController < ApplicationController
respond_to :json, :js, :html
before_action :set_status
def show
respond_with #status
end
private
def set_status
def status
#exception = env['action_dispatch.exception']
#status = ActionDispatch::ExceptionWrapper.new(env, #exception).status_code
#response = ActionDispatch::ExceptionWrapper.rescue_responses[#exception.class.name]
end
end
end
View
# app/views/exception/show.html.erb
<h1>404 error</h1>
This is very simple version - I can explain more if you wish.
Basically, you need to hook into the config.exceptions_app middleware, it will capture any exception in the middleware stack (as opposed to rendering the entire environment), allowing you to send the request to your own controller#action.
If you comment, I'll help you out some more if you want!