I am migrating my 1.8.7 rails app to rails 3. But I have a problem with a partial:
I have the following partial:
in my cms controller :
#clients = Client.all
group = render_to_string :layout => 'layouts/window', :partial => 'clients/index'
in my "clients/index" partial:
<%= render :partial => 'clients/item', :collection => #clients %>
This worked great with rails 1.7.8 but with rails 3 only the partial in the index get's rendered!. So, to clarify this, the group variable in the controller doesn't get the html from the layout.
Also the weird thing is that the window layout is _window.erb (if I do window.html.erb or just window.erb rails can't find it which is strange).
Does anybody know if this behavior is normal for rails 3?
thanxs!
Partials in rails have to start with underscore. Try renaming your "item.html.erb" partial to "_item.html.erb".
Related
I'm using the gems "haml" and "haml-rails" in my rails app and I have this folder structure
-views
-layouts
-public
-layout.html.haml
-_header.html.haml
-_footer.html.haml
And i wanto to render _header and _footer in layout.html.haml using this code:
= render 'layouts/public/_header'
.container= yield
= render 'layouts/public/_footer'
but rails raises a MissingTemplate error but _header and _footer exists...
how can i solve?
You typically omit the underscores when specifying partial names in these helpers. Also, you should be passing them in as a :partial parameter:.
= render :partial => 'layouts/public/header'
.container= yield
= render :partial => 'layouts/public/footer'
partials are named with a leading underscore to distinguish them from
regular views, even though they are referred to without the
underscore.
source: Rails Guides
I've come across an oddity that I can't quite explain with regards to Rails 3 and rendering partials with layouts (from the controller). I'm hoping someone can provide a little insight into what's happening.
First off, we'll call this controller a "legacy" controller. It's been around for a long time and is doing a lot of things wrong, but I'm not looking to refactor it at this point so I'm trying to find ways to work with what we have.
The new action is something like this (in the BarsController)
def new
if something
render :partial => "foo", :layout => "bars"
elsif something_else
render :partial => "foo2", :layout => "bars"
elsif something_else_else
render :partial => "foo3", :layout => "bars"
else
render :partial => "foo4", :layout => "bars"
end
Now, in Rails 2.3.5, this worked fine. It would render the appropriate partial inside the appropriate layout -- I realize the layout option is redundant here as it would default to the bars layout regardless. When we upgraded to Rails 3.0.x, we started getting errors as follows:
Missing partial layouts/bars with {:handlers=>[:erb, :rjs, :builder, :rhtml, :rxml], :formats=>[:html]
Clearly the layouts/bars.html.erb file is and always has been there, so I couldn't figure it out. I was able to render with :layout => false, but that of course wasn't going to work. Eventually I figured out that if I do either of the following, it works:
1) Rename my layout to _bars.html.erb instead of bars.html.erb and:
render :partial => 'foo2', :layout => 'bars'
2) Keep my layout as bars.html.erb (what I want) and :
render '_foo2' # :partial option is redundant here anyway
It seems as though by using the :partial option instead of the string as first parameter is causing rails to apply the _name.html.erb convention to both the partial AND the layout. If I put in the underscore on my own, it falls back to the behaviour I expected which is to not prepend an _ infront of the name of the layout.
Does anyone know why this is the case?
EDIT Alright, not sure how I missed this... but here's something in the docs making mention of this. It seems as though it's been around since 2.3.8, perhaps it was done differently in 2.3.5 (what we were running on)?
3.4.3 Partial Layouts
A partial can use its own layout file, just as a view can use a
layout. For example, you might call a partial like this:
<%= render "link_area", :layout => "graybar" %> This would look for a
partial named _link_area.html.erb and render it using the layout
_graybar.html.erb. Note that layouts for partials follow the same
leading-underscore naming as regular partials, and are placed in the
same folder with the partial that they belong to (not in the master
layouts folder).
Here's my own answer to the question based on what I've edited above:
Since Rails 2.3.8, it would appear as though the default behaviour when rendering a partial with render :partial => 'foo', :layout => 'bars' is to expect a "partial layout" file as well as a partial view file. In this case it will expect
app/views/_foo.html.erb as well as app/views/layouts/_bars.html.erb
For anyone encountering this problem upgrading from Rails 2.3.5, here's the solution I found to have the least amount of impact:
render '_foo', :layout => 'bars'
This solution does not assume you're rendering a partial and therefore does not expect a partial layout. The other option would be to duplicate your layout to
app/views/layouts/_bars.html.erb
and using
render :partial => 'foo', :layouts => 'bars'
but that results in some duplication of code.
RAILS 2.3.8+ DOC REGARDING THIS:
3.4.3 Partial Layouts
A partial can use its own layout file, just as a view can use a
layout. For example, you might call a partial like this:
<%= render "link_area", :layout => "graybar" %> This would look for a
partial named _link_area.html.erb and render it using the layout
_graybar.html.erb. Note that layouts for partials follow the same
leading-underscore naming as regular partials, and are placed in the
same folder with the partial that they belong to (not in the master
layouts folder).
I am developing a rails 3 app for 2 locales (:en, :kr).
I have 2 view files:
index.en.html.haml
index.kr.html.haml
And each file uses partial.
_info.en.html.erb
_info.kr.html.erb
(Partials are erb instead of haml)
= render :partial => "info"
This always uses _info.en.html.erb ignoring locale.
Partial can't be auto-selected for locales?
Thanks.
Try
= render :partial => "info"
In my application.html.erb layout for my app, I want to have a partial that renders if it exists for the given view. for example.
If the visitor is at http://example.com/users/show, I'd want the partial /users/_sidebar.html.erb to render.
But if the visitor were at say, http://example.com/user/locations/san_francisco, I'd want the partial /users/locations/_sidebar.html.erb to render.
So the thing here is that if there were no partial for that controller/action it would render some generic partial in my shared directory, and I'd rather not litter every single view with content_for blocks ya know?
Any ideas guys?
My solution is a bit different. Throw this in your application helper:
def render_partial_if_exists(base_name, options={})
file_name = ::Rails.root.to_s+"/app/views/layouts/_#{base_name}.html.erb"
partial_name = "layouts/#{base_name}"
else_file_name = ::Rails.root.to_s+"/app/views/layouts/_#{options[:else]}.html.erb"
else_partial_name = "layouts/#{options[:else]}"
if File.exists?(file_name)
render :partial => partial_name
elsif (options.key?(:else) and !options[:else].nil? and File.exists?(else_file_name))
render :partial => else_partial_name
end
end
Then in your view:
<%= render_partial_if_exists "page_#{controller.action_name}_sidebar", :else => "page_sidebar" %>
In an edit action, if "layouts/page_edit_sidebar" exists it renders it, otherwise it will render a standby "layouts/page_sidebar"
Sean Behan has a great post on exactly this:
http://seanbehan.com/programming/render-partial-if-file-exists/
I might move it to a helper and tweak it a bit to:
<%= render_sidebar %>
# This method could use either the rescue or the if file exists technique.
def render_sidebar
render(:partial => "/#{controller.name}/sidebar"
rescue
#default side bar
end
I am running a RoR application (rails 2.3.8, ruby 1.8.7), the application runs fine on my local machine. but on production the logs show the following error:
ActionView::TemplateError (Missing template folder/_file_name.erb in view path app/views) on line #19 of app/views/layouts/main.rhtml:
19: <%= render :partial => "folder/file_name" -%>
the file name exists as folder/_file_name.html.erb, I tried to reproduce the problem on the production environment but didnt have any luck, for some reason rails application asks for folder/_file_name.erb at some times while other times it searches for the right file folder/_file_name.html.erb.
Could someone explain to me what is going on?
The same also occurs for .rhtml files, rails application requests .erb at times while others get the right .rhtml file
update:
<%= render :partial => "shared/meta_tags" -%>
<%= render :partial => "shared/common_resources" -%>
<%= render :partial => 'shared/ads/oas' -%>
Any pointers on this issue will be helpful,
thanks in advance
Whats the format of the request?, for the first template (folder/_file_name.html.erb) it will only be correct if the request format is html, but not if it is ajax or any other custom type you have in your app. One quick soluction would be to rename it to folder/_file_name.erb if you want to use the same partial for all the formats
Is there a controller action with the same name as that file?
If you have a foo controller with a bar action and no response defined in your action, Rails will try and render views/foo/bar.html.erb.
If that's not what you want, you need to define a response in your controller and tell Rails to render the appropriate partial, like so:
respond_to do |format|
format.html do
render :partial => "/foo/bar"
end
end
In the latter case, Rails will render "views/foo/_bar.html.erb"
In some cases You can't prevent this error as there are load reasons like missing cache, unknown request format and etc
You can try to restrict the number of predefined formats like:
get '/about-us' => 'controller#about', :format => /(?:|html|json)/
However, I added the following method in my application_controller.rb file so that such errors will render a 404 page rather failing with a error message on screen
rescue_from ActionView::MissingTemplate, :with => :rescue_not_found
protected
def rescue_not_found
Rails.logger.warn "Redirect to 404, Error: ActionView::MissingTemplate"
redirect_to '/404' #or your 404 page
end
you can wrap this code in a if statement, something like this if Rails.env.production? given that the env is setup so your dev environment wont be affected