Here is my index.html.erb:
<%= render :action => 'new' %>
<% unless #posts.empty? %>
<%= render #posts %>
<% end %>
The posts are displaying, but nothing in the new page is.
It's not in the log either:
Processing PostsController#index (for 127.0.0.1 at 2010-07-27 20:54:28) [GET]
Post Load (0.2ms) SELECT * FROM "posts"
Rendering template within layouts/application
Rendering posts/index
Rendered posts/_post (8.4ms)
Also, if I replace it with just <%= render :new %>, I get the error:
undefined method `include?' for :new:Symbol
But it should allow me to render the action implicitly with Rails 2.3.8.
I would be grateful if anyone could explain either of these things.
You should only render partials within a view. Since you need the contents in multiple views, you can convert the contents of new.html.erb to a partial (say, _new.html.erb) and then
<%= render 'new' %>
From new.html.erb as well as index.html.erb. render :action => 'actionname' is meant for rendering another action's template from within the controller.
Note that its a common idiom to create a _form.html.erb partial for each model, and use that whenever you need to be able to add or edit a model instance from elsewhere. That would be useful in this case as well. You would then render the form partial from index, new and edit.
Just a thought, but I suspect that erb will treat those two blocks as a single line. As you probably know, in Ruby it's quite idiomatic to put an "unless" or "if" condition at the end of a line.
You may want to add a line break before "unless" but after <%.
Related
I have a collection and want to iterate and render a partial:
<% #programs.each do |program| %>
<%= render "program", link: program_path(program) %>
<% end %>
For each rendering, I will pass a parameter called link. And it varies based on different situation.
program_path(program)
admin_program_path(program)
program.external_link
However, it will spend a huge time to render every partial, so it's a N+1 problem. I also tried to render collections but I don't know how to pass the parameter.
Does anyone know a better way to do it? Or shall I give up partial and put those code to every page which rendering the partial?
Cheers
You could use:
<%= render #programs %>
And create:
views/programs/_programs.html.erb
Then you choose the link with a condition in the partial.
Is is possible to render a partial as a layout?
Currently, I have a partial _show.html.erb under app/views/users. In some other controllers, I tried to include layout 'users/show' to use that partial as a layout.
Yet, by default, Rails seems to be looking for layouts in layouts/ directory. And I get such error as:
Template is missing
Missing template layouts/users/show ....
Any suggestions?
I think that if you just want to include a partial in another view you should user render:
<%= render partial: 'users/show' %>
Perhaps in your other controller's action you have:
#user = #some_object.user
You'll need to pass in the #user to your partial. You might want to refer to a local variable, user, in your users/show partial and pass in the instance variable:
<%= render partial: 'users/show', locals: {user: #user} %>
You can also use the partial and layout options to together so that a partial will render inside a specified layout. For example, you could specify that your
<%= render partial: "contact_info", layout: "users/show" %>
This would tell the contact_info partial to render inside a layout found in app/layouts/users/show.html.erb.
When I render a partial which does not exists, I get an Exception. I'd like to check if a partial exists before rendering it and in case it doesn't exist, I'll render something else. I did the following code in my .erb file, but I think there should be a better way to do this:
<% begin %>
<%= render :partial => "#{dynamic_partial}" %>
<% rescue ActionView::MissingTemplate %>
Can't show this data!
<% end %>
Currently, I'm using the following in my Rails 3/3.1 projects:
lookup_context.find_all('posts/_form').any?
The advantage over other solutions I've seen is that this will look in all view paths instead of just your rails root. This is important to me as I have a lot of rails engines.
This also works in Rails 4.
I was struggling with this too. This is the method I ended up using:
<%= render :partial => "#{dynamic_partial}" rescue nil %>
Basically, if the partial doesn't exist, do nothing. Did you want to print something if the partial is missing, though?
Edit 1: Oh, I fail at reading comprehension. You did say that you wanted to render something else. In that case, how about this?
<%= render :partial => "#{dynamic_partial}" rescue render :partial => 'partial_that_actually_exists' %>
or
<%= render :partial => "#{dynamic_partial}" rescue "Can't show this data!" %>
Edit 2:
Alternative: Checking for existence of the partial file:
<%= render :partial => "#{dynamic_partial}" if File.exists?(Rails.root.join("app", "views", params[:controller], "_#{dynamic_partial}.html.erb")) %>
From inside a view, template_exists? works, but the calling convention doesn't work with the single partial name string, instead it takes template_exists?(name, prefix, partial)
To check for partial on path:
app/views/posts/_form.html.slim
Use:
lookup_context.template_exists?("form", "posts", true)
In Rails 3.2.13, if you're in a controller, you can use this :
template_exists?("#{dynamic_partial}", _prefixes, true)
template_exists? is delegated to lookupcontext, as you can see in AbstractController::ViewPaths
_prefixes gives the context of the controller's inheritance chain.
true because you're looking for a partial (you can omit this argument if you want a regular template).
http://api.rubyonrails.org/classes/ActionView/LookupContext/ViewPaths.html#method-i-template_exists-3F
I know this has been answered and is a million years old, but here's how i ended up fixing this for me...
Rails 4.2
First, i put this in my application_helper.rb
def render_if_exists(path_to_partial)
render path_to_partial if lookup_context.find_all(path_to_partial,[],true).any?
end
and now instead of calling
<%= render "#{dynamic_path}" if lookup_context.find_all("#{dynamic_path}",[],true).any? %>
i just call <%= render_if_exists "#{dynamic_path}" %>
hope that helps. (haven't tried in rails3)
I have used this paradigm on many occasions with great success:
<%=
begin
render partial: "#{dynamic_partial}"
rescue ActionView::MissingTemplate
# handle the specific case of the partial being missing
rescue
# handle any other exception raised while rendering the partial
end
%>
The benefit of the code above is that we can handle tow specific cases:
The partial is indeed missing
The partial exists, but it threw an error for some reason
If we just use the code <%= render :partial => "#{dynamic_partial}" rescue nil %> or some derivative, the partial may exist but raise an exception which will be silently eaten and become a source of pain to debug.
What about your own helper:
def render_if_exists(path, *args)
render path, *args
rescue ActionView::MissingTemplate
nil
end
This works for me in Rails 6.1:
<% if lookup_context.exists?("override_partial", ['path/after/app/views'], true) %>
<%= render partial: "path/after/app/views/override_partial" %>
<% else %>
<%= render partial: "default_partial" %>
<% end %>
Here I have my partial nested some levels deeper than normal (app/views/path/after/app/views/_override_partial) so that's why I'm adding it as the prefixes array, but you can use lookup_context.prefixes instead if you don't need it.
I could have also used prepend_view_path on the controller. It's up to you :)
I want to create several link_to_remote links that are campaign names:
<% #campaigns.each do |campaign| %>
<!--link_to_remote(name, options = {}, html_options = nil)-->
<%= link_to_remote(campaign, :update => "campaign_todo",
:url => %>
<% end %>
I want the output to update on the page to render a partial, which runs a loop through the values associated with the campaign.
The API docs says this will render a partial, but I'm not clear where the name of the :partial template is passed in, either here or in the controller
Thanks.
The controller would render the partial, according to the docs.
Usually, the result would be a partial prepared by the controller with render :partial.
of course in the controller. Here you create an AJAX snippet that will pull an url you specify from your controller.
generated javascript has no access to any partials b/c it runs on client PC.
and controller decides WHAT to respond to this request. it can render a partial, a template, a text, or anything.
Here's the call in the application.html.erb file:
<%= render :partial => 'tasks/_new' %>
Here's the partial being rendered (_new.html.erb):
<% form_for #task do |f| -%>
<%= f.text_field :body %>
<%= submit_tag "Submit" %>
<% end -%>
Here's the method in the 'tasks' controller:
def new
#task = Task.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #task }
end
end
Here's the error message I keep getting:
Missing template tasks/__new.erb in view path app/views
And it says the error is in this line:
<%= link_to "tasks", tasks_path %> <%= render :partial => 'tasks/_new' %>
The file is in the right directory. The weird thing is that there's an
extra _ in the file name, in the error. When I give in and rename the
partial to __new.erb, here's the error I get:
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
And it says the error is in this line:
<% form_for #task do |f| -%>
I had also tried without the _ in the code, as Petros suggested, but it returns the same error as above, Called id for nil….
What's going on?
You don't need the _ in your code. It should be:
<%= render :partial => 'tasks/new' %>
The first error is because you don't need to put the _ inside the :partial parameter. Rails takes care of that. That's why you get double __ because Rails will put one for you.
The second error is your real problem. The error suggests that #task is nil. This is true because the partial only knows what the container view knows, and your view in that particular moment hasn't called the action from the proper controller. As you (Baby Diego) already found out and indicated in one of your comments below, you needed to create an instance of a Task in your partial. I don't know if there is a more elegant solution, but maybe someone can suggest something better in the future.
Thanks to MattMcKnight for informing us that the partial itself does only know what the container view knows.
Petros correctly identified the first issue- you don't need the underscore in the partial call.
The second thing to know about partials is that they don't call the controller method, they just reference the view. Thus, you need to setup the #task object in every action that uses that partial, or just call Task.new in the partial. When I have a partial in a layout in similar situations, I usually load it with JavaScript so that I can call the action.
If the partial needs to know about a variable in the calling erb file, you can pass it like this:
<%= render partial: "tasks/new", locals: { task: #task } %>
And in file app/views/tasks/_new.html.erb, refer to the variable like this:
<% form_for task do |f| %>
<%= f.text_field :body %>
<%= submit_tag "Submit" %>
<% end %>
That is, without the #. (The code a: b is just a more convenient form of :a => b.)
I wonder, though, why do you want to use partials in file application.html.erb? I'm assuming that you mean the Ruby-generated file app/views/layouts/application.html.erb, which is supposed to be used as a layout file containing elements common to all your application's pages, not for business logic. Perhaps the file you need to call the partial from is app/views/tasks/index.html.erb?