I have a page which displays my testimonials in the my_testimonials action of the testimonials controller.
The correct layout for this action is layouts/frame but I must have changed something because now it is rendering layouts/application
Here is the layout being specified in the controller:
layout "layouts/frame", only: [:my_testimonials]
layout "layouts/shares", only: [:new]
Here is the output in the console:
Started GET "/my_testimonials/c4ca4238a0b923820dcc509a6f75849b" for 105.228.65.202 at 2013-09-27 07:40:49 +0000
2013-09-27T07:40:49.470211+00:00 app[web.2]: Processing by TestimonialsController#my_testimonials as HTML
2013-09-27T07:40:49.686047+00:00 app[web.2]: Rendered testimonials/_testimonial.html.erb (2.6ms)
2013-09-27T07:40:49.686200+00:00 app[web.2]: Rendered testimonials/my_testimonials.html.erb within layouts/application (79.2ms)
The testimonials are being displayed but with the incorrect layout. As I said it was working yesterday so I must have changed some small detail or the order of something.
I'm inclined to think that a layout() call overrides previous calls. In this case, that the last layout() call you did for :new overrode the one for :my_testimonials.
You can also choose the layout at runtime:
layout :set_layout
protected
def set_layout
case action_name.to_sym
when :my_testimonials
'frame'
when :new
'shares'
else
'application'
end
end
Or specify your layout per action:
def my_testimonials
respond_to do |format|
format.html { render :layout => 'frame' }
end
end
Update:
The code suggests they do override previous calls. So calling layout "layouts/shares", only: [:new] is essentially saying to use "shares" for :new and "application" otherwise.
Rails looks for the layout in the 'app/layouts/' folder. See Section 2.2.2
So, when you specify 'layouts/frame', rails looks for 'app/layouts/layouts/frame', which it obviously cannot find.
Change your layout directives to the following:
layout "frame", only: [:my_testimonials]
layout "shares", only: [:new]
change
layout "layouts/frame"
to
layout 'frame'
I think this should work.
Related
So I am trying to change the layout of a view based on url params.
So far, I figured out I have to set the layout in the controller. In my controller under the show action I have:
if params['iframe'] == 'true'
render :layout => 'vendored'
end
The layout 'vendored' exists in views/layouts. I am getting the dreaded rendering multiple times. Here is the rest of the show action in my controller:
def show
#event = Event.find(params[:id])
#user = current_user
#approved_employers = current_user.get_employers_approving_event(#event) if user_signed_in?
respond_with(#event)
The problem is that I don't see another render. I don't see another one in the entire controller. Of course, there is a render somewhere because it is rendering my default application layout, is that causing the problem? I read in the rails docs that I can add
and return
to the end and that should fix the problem, but not sure where to put that since the two renders are not next to each other. I also don't see any other redirect_to's either. Where should I be looking for this other render? Is that the problem?
Alternatively, I think this is easier to understand:
class YourController < ApplicationController
layout :iframe_layout
private
def iframe_layout
params['iframe'] ? "vendored" : "application"
end
end
See this answer. For your case:
before_filter :set_layout, :only => [:show]
private
def set_layout
self.class.layout ( params['iframe'] == 'true' ? 'vendored' : 'application')
end
I have an application.html.erb file which sets out layout for every pages in my app (header, footer etc.) like a typical Rails app.
However, I would like to have a landing page which I don't want to use this file. How should I bypass application.html.erb?
Thank you.
Use
render :layout => false
or
render :layout => 'whatever'
in your action. If you are using a separate LandingController you simply can create a app/views/layouts/landing.html.erb which will be picked up or you can override the layout via
class LandingController < ApplicationController
layout 'whatever'
...
end
You can set a layout in your render function:
render {other arguments}, :layout => :homepage
You can also set that option to false to not use any layout at all.
You can do something similar if you want an entire controller to use a custom layout:
class MyController < ApplicationController
layout :homepage
#...
end
Hope that helps!
In the controller that renders the view, change the render to:
render :layout => false
You can read more about options to render and how to work with layouts at the Rails guide to render and layouts.
How can I remove the layout application.html.erb from rendering on a particular page. It is now visible on all pages in my application.
You can override default rendering at the controller level.
class Admin::HomeController < Admin::BaseController
layout "admin"
You can also override rendering of layouts at a controller action level:
def show
render :layout => "layout_for_show_only"
end
And, if you are really desperate, you can override layouts in the view:
<%= render "print_view", :layout => "print" %>
See the excellent rails guide on the subject: layouts and rendering in Rails
ian.
You can simply add to the controller:
layout false, only: [:show, :edit]
which means, that application layout won't be rendered for the show and edit pages
Here is an answer.
You can set: format.js {render :layout=>false}
jQuery + Ajax + Haml. js.erb files not firing
I can do request.path_parameters['controller'] and request.path_parameters['action'], but is there anything like request.path_parameters['template'] so I can discern which template file (such as index.html.erb) is being rendered?
I'm writing a method that automatically sets the body id to the template being rendered, for easy css manipulation:
class ApplicationController < ActionController::Base
...
after_filter :define_body_selector
...
def define_body_selector
# sets #body_id to the name of the template that will be rendered
# ie. if users/index.html.erb was just rendered, #body_id gets set to "index"
#body_id = ???
end
...
If you have different template files you could use content_for in them (check out guide about layouts and templates) to set id in layout file, or just stick to params[:action] (it should be enough -- choice of template is based on action called).
You can make universal before_filter for all (or not all) actions with
before_filter :set_id_for_body, :only => [...]
def set_id_for_body
#body_id = params[:action]
end
Always think how to keep your code DRY!
EDIT:
You could define hash that will link actions with matching templates:
ActionClasses = {
:update => "show",
:show => "show,
:new => "new",
:edit => "new",
...
}
Within your layout file just add
<body id="<%= ActionClasses[params[:action]] %>">
EDIT:
It is possible to access template via ActionBase::template method, but it won't work the way you would like it to. If you call filename or name method in layout file, you will get path to layout file, not template. AFAIK It is impossible to check what template is being rendered, as multiple of them can be used to render single action.
#body_id = params[:action]
I have a controller with the following layout logic
layout 'sessions', :except => :privacy
layout 'static', :only => :privacy
The issue is that Rails seems to ignore the first line of code and the layout "sessions" is not applied for any actions. It simply thinks to render the static layout for privacy and no layout for the rest.
Anyone know how to fix this?
The reason this doesn't work is because you can only have global one layout declaration per controller. The :only and :except conditions just differentiate between actions that should get the specified layout and the ones that are excluded get rendered without a layout. In other words, a layout declaration always affects all actions that use default rendering.
To override you simply specify a layout when you render like one of the following examples inside an action:
render :layout => 'static'
render :action => 'privacy', :layout => 'static'
render :layout => false # Don't render a layout
Another option is to define a method for your layout call, like so:
layout :compute_layout
and then
def compute_layout
action_name == "privacy" ? "static" : "sessions"
end
However this is really only useful when you want to determine the layout at runtime based on some runtime parameter (like a variable being set). In your example, that does not seem to be necessary.
You can just specify layout :static where you need it.
You can also dynamically determine the layout within your controller:
class SampleController < ApplicationController
layout Proc.new { |controller| (controller.action_name == 'privacy') ? 'static' : 'sessions' }
...
end
If more actions within the controller are sharing the same layout:
class SampleController < ApplicationController
layout Proc.new { |controller| ['action1', 'action2'].include?(controller.action_name) ? 'layout1' : 'layout2' }
...
end
Source: https://guides.rubyonrails.org/layouts_and_rendering.html#using-render