This question already has answers here:
Where to put partials shared by the whole application in Rails?
(7 answers)
Closed 8 years ago.
I am using Ruby on Rails 3.0.7 and I am planning to use partial templates. All classes in my application would use same partials so I have to decide where to located all those.
Is it a good idea to put "global" shared partial templates in the lib folder? If no, what is a common practice to choose the folder where to put those? Any advice on how to properly name and load that folder?
The standard is placing all shared partials in app/views/shared, and referencing them as
render :partial => 'shared/partial_name'
If you have a standard "row in a list" partial (say, for an index page), you could use a shared partial like:
# To render a single object row:
render :partial => 'shared/item', :locals => { :item => #item }
# Or to render them all:
render :partial => 'shared/item', :collection => #items
Rails 4:
put the partials you intend to use through out your application in /app/views/application
Then anywhere in your application you can easily:
render partial: 'partial_name', variable_name: variable
The added benefit is that you can always override the partial in a particular view space by redefining what that partial means in /app/views/controller_name/_partial_name.html.erb and the calls to the partial will then reference the more specific context you're in. If that doesn't exist you get the application level partial.
Suggestion taken from Thoughtbot
Conventions is to put them under app/views/shared
If you're going to have many partials, I'd recommend you putting them into subdirectories of that folder, whatever makes sense to your application, since having many partials in one directory is generally not a good practice.
Related
I have code like render #posts to render my posts collection in an index template which the PostsController renders.
Now I have an Admin::PostsController that also should render the collection but when my posts controller renders #posts it looks for the admin/posts/_post.html.erb partial. Do I now have to write the partial path explicity? Is this feature by design or a bug? It doesn't seem to make sense.
Yes, you need to supply the path explicitly. And yes, this is by design.
It actually makes sense because Rails is a MVC framework and if you create a controller under a different namespace one would expect separate views for that controller too. Think about convenience, if you wanted to quickly bootstrap an application with a few simple commands, an application where there's a public view of posts and an admin view where all of the admin goodies for editing are, you would EXPECT to have a different directory to store all that admin views.
render #posts is a shortcut for a longer method signature.
In case of PostsController, it is a short cut for render :partial => "post", :collection => #posts; the partial is _post.html.erb and it is expected to be in app/views/posts folder.
In case of Admin::PostsController, it is a short cut for render :partial => "admin#post/post", :collection => #posts; the partial is _post.html.erb, and it is expected to be in app/views/admin/posts folder.
If you want a different partial to be used, you should specify it explicitly.
See the Rendering Collections section of Rails Guides page on Layouts & Rendering for detailed explanation.
I need to use a single partial for anything inside my views/admin folder. My setup:
/app/views/
+ admin
+ accounts
+ users
+ layouts
- application.html.slim
+ application
- _header.html.slim
+ users
+ accounts
I have a partial called _header.html.slim in /views/application/. The partial is rendered from /views/layouts/application.html.slim.
I want to render a different _header.html.slim partial for anything under the /views/admin dir. I can create a new _header.html.slim and add it to /views/admin/accounts and /views/admin/users, but I don't want to repeat my self. I want a single partial for everything under admin.
How can I so this? I tried adding /views/admin/application and /views/admin/layouts folders hoping they would override the ones in the /view dir, but no luck.
layouts/application.html.slim:
- if controller.controller_name == "admin"
== render :partial => "admin/header"
- else
== render :partial => "application/header"
The structure of the folders themselves don't control which ones get run or applied - the folder structure is really just to help you organize it in a way that makes sense.
You could accomplish what you're looking for in a couple of ways, depending on your needs:
One way is to specify the layout (which includes the desired partials) in the controller, using the render :layout => 'some_layout_name' option as outlined here (skip to the heading "2.2.11.2 The :layout Option" for the specifics).
Another way is to set a variable in your action that contains, say, the name of the layout(s) or partial(s) you want to render, and in your view do something like:
<% if #custom_partial == "slim" %>
<%= render :partial => 'header.html.slim' %>
<% end %>
So, either specify a custom layout (if you want the whole layout including partials to be custom), or set a flag variable that controls which partials get rendered at which time, and use that variable to control the flow of rendering in your view. Which of those options is right for you depends really on which is cleaner, most reliable, and makes sense for your project; that is, it's up to you to decide.
What is the convention for using a partial to list an item, vs the partial show show / edit / new
For instance on an overview one would want to do:
[ app/parts/ ]
(parts/index.html.erb)
<h1> Parts and stuff! </h1>
<table>
# headers and such
<%= render :partial => #parts %>
</table>
# calls _part to make a list, usually the 3 most important things
Then we have something like
[ app/parts/new ]
(parts/new.html.erb)
# what is the convention for the partial here?
# Said partial would be used for new / edit
I know you can specify render :partial => "path/to/partial", but I was hoping for a resource based route to want a partial by some conventional name.
Rails doesn't really have conventions for partial names. Conventions are for RESTful template names for controller actions, i.e., index, new, show, edit. The actions create, update, and destroy use redirects rather than rendering anything directly.
Partials serve two purposes: one is when you want to avoid duplication, i.e., for new/edit forms. The other is when you want to update pages with AJAX. Naming conventions are basically up to you, just try to be consistent.
But routes (resource-based or otherwise) don't really apply to partials; they're handled by the template engine, not the dispatcher.
If you'd like to see generators that effectively use partials in action, try Ryan Bates' nifty_generators gem.
You can find it here: https://github.com/ryanb/nifty-generators
Usually _form_part or _part depending on context.
I have a collection, #comments, that is heterogeneous but hierarchical. Each comment is either an instance of Comment or some derived class, like ActionComment or InactionComment. I am rendering a different partial for each type of Comment. The View code is:
= render #comments
As all the partials are related, I would like to keep them in a single view directory, i.e.:
app/views/comments/_comment.haml
app/views/comments/_action_comment.haml
app/views/comments/_inaction_comment.haml
But right now in order to use the automatic rendering of the correct partial, I am using separate directories, like:
app/views/comments/_comment.haml
app/views/action_comments/_action_comment.haml
app/views/inaction_comments/_inaction_comment.haml
Rails 3.2 makes a Model#to_partial_path method available which allows you (as its name suggests) to override the partial pathname.
def to_partial_path
self.action.to_s
end
The path it returns does not include the leading underscore and is assumed to be relative to .../views/modelname/. See http://blog.plataformatec.com.br/2012/01/my-five-favorite-hidden-features-in-rails-3-2/ for an overview
You can't do it quite as magically, but you can do it by just rendering each item individually and specifying the partial.
example in haml:
- #comments.each do |c|
= render :partial => "comments/#{c.class.to_s.underscore}", :locals => {:comment => c}
Where would I go about placing partial files shared by more than one model?
I have a page called crop.html.erb that is used for one model - Photo.
Now I would like to use it for another model called User as well.
I could copy and paste the code but that's not very DRY, so I figured I would move it into a partial.
Since it's shared between two models - where would I place that partial?
Thanks!
The Rails convention is to put shared partials in /app/views/shared.
Update
Layout inheritance is now in the guides under layout and rendering
Template inheritance works similarly.
Rails 3.1 and following versions implement template inheritance, so I think the correct place for shared partials is now /app/views/application/, say you are in products#index you can do the following:
-# products#index
= render #products.presence || 'empty'
-# /app/views/application/_empty.html.haml
There are no items
btw it's application because the connection is the controller inheritance, so this assumes ProductsController < ApplicationController
This way if you implement /app/views/products/_empty.html.haml that will be taken, the above is a fallback for all the missing partials, and I can't check right now, but I think even for the template itself...
Railscast: template inheritance!
TL;DR
Rails 3.1, Rails 4, Rails 5 and whatever comes next
app/views/application
The engine searches this path automatically if the view is not found in the controller path.
Rails 3 and prior
app/views/shared
The engine does NOT search this path automatically.
Long story
Rails 3 (and prior version) have no default location for storing shared views.
The unofficial convention is to store shared views in app/views/shared. Wherever you'd end up storing them though, you have to specify the path
# render app/views/shared/menu.html.erb
<%= render :partial => "shared/menu" %>
This suggestion was popularized by Agile Web Development with Rails.
Rails 3.1 introduces an official standard for where to store shared views:
app/views/application
Thanks to this standard, the engine now automatically looks for templates in app/views/application. As a result, you don't have to use the full path anymore.
Those curious can follow here the thought process behind this decision.
Old syntax
# render app/views/application/menu.html.erb
# unless menu.html.erb is found in appp/views/my_controller
<%= render :partial => "menu" %>
New syntax
# render app/views/application/menu.html.erb
# unless menu.html.erb is found in appp/views/my_controller
<%= render partial: "menu" %>
Of course, you can still place your shared views wherever you want and reference them by path
<%= render :partial => "my_own_special_shared_folder/menu" %>
Unless you have a very good reason to do this though, please stick to the new standard and store your shared views in app/views/application.
The Rails View uses app/views/layouts for shared partials like header and footer, but the Ruby on Rails Guide uses app/views/shared in an example. I guess it comes down to personal preference. I would use layouts for high-level stuff like a main nav or a footer, but shared for more narrow controller-level stuff like a form.
I general have a shared folder in my views that contains commonly used partials.
I arrived here in 2021 (rails 6) and got confused by the answers (many different ways).
I asked some senior rails developers what they'd do and they also gave me 2 different answers.
But TL;DR
Create a folder called 'shared' or 'application' inside your views folder (e.g. app/views/shared or app/views/application.
Then simply move the partial there, and access it with either
<%= render partial: 'shared/socials' %>
# or
<%= render partial: 'application/socials' %>
or even simpler
<%= render 'shared/socials' %>
# or
<%= render 'application/socials' %>
It doesn't matter where you put them. You can render any partial at any arbitrary location by providing the file's path to render - it doesn't need to be associated with the controller that's rendering it. I use a directory simply called partials under the view directory, and call partials in it like this:
render :partial => 'partials/mypartial'