56

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!

Yuval Karmi
  • 26,277
  • 39
  • 124
  • 175

7 Answers7

60

The Rails convention is to put shared partials in /app/views/shared.

John Topley
  • 113,588
  • 46
  • 195
  • 237
  • 3
    partials in /app/views/shared/ are not being picked up in my Rails 4 app for some reason?!? – Meltemi Aug 01 '13 at 18:08
  • 14
    Not any more, for rails 4, the right directory is app/views/application, and I think it makes sense... https://robots.thoughtbot.com/directory-for-shared-partials-in-rails – Alex Escalante Aug 07 '15 at 20:11
  • 4
    "This makes `app/views/application/` a great place for your shared partials" - [Rails Guide Layouts & Rendering](http://edgeguides.rubyonrails.org/layouts_and_rendering.html) – Eliot Sykes Sep 30 '15 at 10:31
53

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!

ecoologic
  • 10,202
  • 3
  • 62
  • 66
  • 2
    I've been looking for this solution for a while now. Can't believe the guide nor any other online tutorials neglect to mention this. – LunaCodeGirl Dec 14 '13 at 11:11
  • 1
    I've sent a pr to the guides doc about this, hopefully it'll get some attention sooner or later https://github.com/rails/rails/pull/16738 – ecoologic Nov 11 '14 at 00:13
  • 1
    dhh wrote: It's [app/views/application] a side-effect from this reasonable case: EmployeesController < PeopleController, which will look first for employees/show, then fall back to look for people/show. It was never intended to fall all the way back to look for application/show. That's an unintended side-effect. https://github.com/rails/rails/pull/9911#issuecomment-15462128 – notapatch Sep 11 '19 at 16:50
  • Interesting. I like `app/views/application`: it's very consistent, I doubt they'll remove it now. – ecoologic Sep 12 '19 at 01:54
30

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.

Community
  • 1
  • 1
Mihai Dinculescu
  • 19,743
  • 8
  • 55
  • 70
5

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.

3

I general have a shared folder in my views that contains commonly used partials.

Toby Hede
  • 36,755
  • 28
  • 133
  • 162
2

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' %>
stevec
  • 41,291
  • 27
  • 223
  • 311
0

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'
Jimmy
  • 35,686
  • 13
  • 80
  • 98