Rails: Render a View (not a partial) From Within a View
Solution 1
Rendering a non-partial view inside another view isn't exactly the Rails Way™. Your current solution is probably better, and not an uncommon approach. Rename it _body, or something else appropriate, if you feel weird about the the partial name being the same as the action.
However if your view can be shared, as it seems like it could in this case, you could just make it a layout.
This is facilitated by the fact that, somewhat against the principle of least surprise, Rails will render an html
template for a js
action if no js
template exists. This means that you could remove both the js template, and the partial, and just create a layout entitled, for example, fadein.js.erb
:
# yourviews/show.html.erb
<div>Content!</div>
# layouts/fadein.js.erb
$("#main").fadeIn("<%= escape_javascript(yield) %>");
# YourController.rb
def show
# ...
respond_to do |wants|
wants.html
wants.js { render :layout => "fadein" }
end
end
Solution 2
Like others have mentioned, rendering another non-partial view in another view is "Not the rails way", if however you still insist on doing it, one method is:
<%= render :file => '<replace with relative/absolute path>' %>
Solution 3
This is not a good practice as you can see by the comments. Rails have the concepts of view, partial and layout. That said, the view is the only one you should keep using only once. So my suggestions are:
- If you feel that more than one extra view could be rendered inside your current view, you are most likely looking for a layout
- If you feel that one of your views should be rendered in many pages, you are looking for a partial
- If this view should render only one extra view inside it, and that view should only be rendered inside the current view, you can pick any of the above or none of it - that's it, go with a single file
Solution 4
you just need to pass a context to your render
method:
<%= render :template => "show" -%>
nullnullnull
Updated on July 09, 2022Comments
-
nullnullnull almost 2 years
I have a controller that responds to both
html
andjs
. Thehtml
view renders the whole page (including the header and footer), while thejs
only replaces#main
. Aside from the header and footer, both formats render the same content. I can get this effect with three files:_show.html.erb <div>Content!</div> show.html.erb <%= render "show" %> show.js.erb $("#main").fadeIn("<%= escape_javascript(render 'show') %>");
This works, but I'd prefer if I didn't need a separate
_show
partial. Unfortunately, this doesn't work:show.html.erb <div>Content!</div> show.js.erb $("#main").fadeIn("<%= escape_javascript(render 'show') %>");
As Rails will look for the
show
partial, not the actual view.Is there a way to get Rails to look for the view file, rather than a partial?
-
nullnullnull about 11 yearsThanks a million. This solution boils three files (
show.html.erb
,show.js.erb
, and_show.html.erb
) into oneshow.html.erb
. I can apply it across models and actions, and there'll still only need to be onelayouts/fadein.js.erb
file. Brilliant! -
Kopty almost 11 yearsThis worked really well! Thank you so much. I just had a question, I couldn't get this to work for a "create" scenario where a form submission should redirect me to the record which I just created. I have added remote: true in my form_for, but it searches for the create template even though I have done the respond_to for JS to point to the layout JS file. Any tips? Thanks.
-
numbers1311407 almost 11 years@Kopty It's still rendering the template, as HTML, inside the javascript layout. So it's still going to look for a create template as usual unless you tell it not to. If you wanted to render the show template, you could do something like
render :show, :layout => "fadein"
-
Kopty almost 11 yearsThanks for the tip numbers. I tried that and am getting the error "':show' is not an ActiveModel-compatible object. It must implement :to_partial_path." I also tried hard-coding the controller's show action but that didn't work either.