I am new to ruby on rails.
I recently converted my erb files to haml files manually. I am facing a weird issue now. I have two controllers and a couple of views. The home page shows the layout correctly but the other views do not. I am trying to use "application.html.haml" for the layout (which is picked up by default).
application.html.haml resides in app/views/layouts
All the controllers except ApplicationController have ApplicationController as their parent class. ApplicationController has ActionController::Base as its parent class
The home page shows all the tags from the application.html.haml layout. However, the other pages do not include those tags. Their source code does not contain html, body, head etc.
I do not have the layout specified in any of the controllers.
When I add the tags to the views, everything works. But, I shouldn't have to do that, right?
application.html.haml
!!! 5
%html
%head
%title XYZ
= stylesheet_link_tag "application", :media => "all"
= javascript_include_tag "application"
= csrf_meta_tags
%body
= yield
my_controller.rb
require 'somefile'
class MyController < ApplicationController
def initialize
#information = Information.new # inside models folder
end
def fetch_information
input = params[:search]
input = input.strip
flash[:error] = nil
#hosts = #information.host(input)
if #hosts.count == 0
flash[:error] = "N/A: #{input}!"
else
# add to cookies
end
end
end
Found the issue! It was because I did not call super in the initialize method of my controller.
Related
I am stuck at what I think is a very simple/common usecase in a Rails web application. I want to use "caches_action, layout:false" and display, from the layout, dynamic tags that will be set by the action (either from the view or the controller).
I could not find any standard rails way to do this as content_for does not work with caches_action, instance variables are not cached (?), and the metatags helper gems that I have tried (metamagic and meta-tags) do not support this usecase.
Is there any way to do this ?
Example
I am using caches_action, layout:false on a SandboxController#show method
#app/controllers/sandbox_controller.rb
class SandboxController < ApplicationController
caches_action :show, layout: false, expires_in: 1.minute
def show
#meta_title = "Best page ever"
do_some_expensive_operation
end
end
The view
#app/views/sandbox/show.html.erb
We are in show action.
The layout
#app/views/layouts/application.html.erb
<title><%= #meta_title %></title>
Debug: <%= #meta_title %> <br/>
<%= yield %>
Thanks !
I found a way to make it work, it's not as pretty as I would like it to be but it helps using caches_action and setting HTML meta tags from the view.
Also, for the record, it seems that this was forgotten and buried deep down in the pipeline, as I did not find any recent mentions of this problem, only that caches_action and content_for together are not expected to work.
Solution: I simply add a before_action to set the meta tags by using as less computation as possible.
#app/controllers/sandbox_controller.rb
class SandboxController < ApplicationController
caches_action :show, layout: false, expires_in: 1.minute
before_action :seo_show, only: :show
def seo_show
#meta_title = "Best page ever"
end
def show
do_some_expensive_operation
end
end
It's worth noting that it can be used in combination with metamagic gem too.
Layout:
#app/views/layouts/application.html.erb
<%= default_meta_tags && metamagic %>
<%= yield %>
And helper:
#app/helpers/application_helper.rb
module ApplicationHelper
def default_meta_tags
meta title: #meta_title || "Default meta-title of my website"
end
end
Hope this helps someone out there !
I generated a Rails application, and am playing around with the internals. Previously my application.html.erb was rendering properly, but now it seems like Rails is totally ignoring it because it won't even generate an error.
There have been a bunch of questions on Stack Overflow regarding this problem. I've looked at what I think is all of them, but none have helped.
My routes:
Rails.application.routes.draw do
# static_pages from rails tutorial ch. 3
get 'static_pages/home'
get 'static_pages/help'
get 'static_pages/about'
end
Here is the views/layout/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>This Title is not showing up</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<p> why isnt this showing up?? </p>
<%= yield %>
</body>
</html>
Here is the static_pages_controller:
class StaticPagesController < ApplicationController
layout 'application' #<- I know this shouldn't be necessary, but I thought i'd try
def initialize
#locals = {:page_title => 'Default'}
end
def about
#locals[:page_title] = 'About'
render #locals
end
def help
#locals[:page_title] = 'Help'
render #locals
end
def home
#locals[:page_title] = 'Home'
render #locals
end
end
Here is the Application Controller:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
end
There are no other layouts. My Views folder has the following structure:
-Views
|-layouts
||-application.html.erb
|
|-static_pages
||-about.html.erb
||-home.html.erb
||-help.html.erb
I've tried purposefully generating an error in the application.html.erb, calling variables that don't exist and whatever other shenanigans. Rails is totally ignoring me and I'm feeling insecure.
All I wanted to do is to display the page name in the <title>, but I can't even get plaintext to render correctly. How can I get this to work so that I can properly fail at getting the controller variable in the title?
You should not override the controller initialize method. Doing this will break the base class behavior.
While, I believe, just calling the super from the initialize will fix your issue, the correct Rails way to initialize a controller for a specific action is to use a before filter instead.
Example:
class StaticPagesController < ApplicationController
layout 'application'
before_action :load_locals
def load_locals
#locals = {:page_title => 'Default'}
end
...
end
As we all know, in ruby on rails, all views extends from application/application.html.erb, most of the time this is great, such as the application.html.erb as follow:
<html>
<head></head>
<body>
<%= render 'layouts/header' %>
<%= yield %>
</body>
</html>
I do not need the write the same code in every view again, but sometimes, just on view is special, this view is different from the view, such as I do not want to add <%= render 'layouts/header' %> in this view.
Maybe a parameter will just help me in this situation, but I want to know if any view is able to not extend from application/application.html.erb?
Views don't 'extend from' application.html.erb, they use it as a default layout. You can change it, of course, using layout method in controller (or layout option in render method), like this:
# this changes the default layout in every views of `AdminController` (and all other controllers that inherit from `AdminController`):
class AdminController < ApplicationController
layout :admin
# ...
end
# this changes the layout of specific action:
class SomethingController < ApplicationController
# ...
def some_action
# ...
render layout: :some_layout
end
end
Here's the reference:
http://guides.rubyonrails.org/layouts_and_rendering.html
What I would like to do :
One layout application.html.haml where I define the common elements to all pages like in the following
%html
%head
%title
= #title
= stylesheet_link_tag "application", :media => "all"
= javascript_include_tag "application"
= csrf_meta_tags
%body
%header
.navbar.navbar-fixed-top
.navbar-inner
.container
.pull-left
.brand
= #title
= render "menu/menu"
.container.centered
- if flash[:notice]
.alert.alert-success
= raw flash[:notice]
- if flash[:error]
.alert.alert-error
= raw flash[:error]
= yield
Then, I would like to have a different layout for every "module" specified in the controller :
class UsersController < ApplicationController
before_filter :authenticate_user!, :authorize
load_and_authorize_resource
layout 'user'
So I would like to have the following workflow :
page template (ex: /users/all)-> module layout (common elements for all /users/ pages) -> app layout (common elements for the whole app)
The first part (page template -> module layout) is extremly easy and is currently implemented. I just need to specify layout 'user' in the controller.
My question is : how can I tell "Don't render only the user layout but render the application layout too" ? I would like to have a layout of a layout.
I hope I was clear enough. Thanks.
I have a bunch of different controllers, and I want to be able to do the standard "Welcome, User." How do I assign the user variable to make it possible to access from any controller?
Here's what I have so far in the application controller:
class ApplicationController < ActionController::Base
before_filter :authorize
protect_from_forgery
private
def current_user
User.find(session[:user_id])
end
protected
def authorize
unless User.find_by_id(session[:user_id])
redirect_to login_url, :notice => "Please Login"
end
end
end
Here's my application.html.haml file:
!!!
%html
%head
%title Pears
= stylesheet_link_tag "application", :media => "all"
= javascript_include_tag "application"
= csrf_meta_tags
%body
%header
= link_to('Home', '/')
- if session[:user_id]
Welcome,
= current_user.firstname
= link_to('Logout', logout_path, method: :delete)
- else
= link_to('Login', login_path)
= link_to('Signup', signup_path)
= yield
What's the best approach?
Thanks!
If all you want is to be able to embed the username into a welcome message, I would probably just store it in the session (as an optimization, to keep from fetching it every time), and then create a partial that displays
Hello, <%= session[:username] %>
and include the partial in your layout, or wherever you want to display this message.
If you're looking for more than a username or small amounts of data like that, a partial is still your best bet to display it, but to fetch the information from the database a before_filter to load the data (as suggested by MrYoshiji), is probably a good idea.
current_user is a private method, do it public, and your code probably will be working.
Normally, views can't call controller methods. However you can allow this for specific methods if you so desire, for example
class ApplicationController < ActionController::Base
...
def current_user
...
end
helper_method :user
end
Whether the user is fetched from the database each time or has some data stored in the session doesn't really matter, but your view shouldn't be coupled to that detail.
I would also be slightly wary of stashing just the user name in the session as an optimisation without first understanding how much of a performance difference it makes