27

I have two controllers for two respective models, by example, photos and categories. index and show methods are very similar in each controller, and the views are identical. What is the best method for share the view by the two models?

I've though two options:

  • Use a helper. In the helper will put the code for the view, and will call the helper from each view (photos/views and categories/views)

  • Use a partial in each views. I think it's a more clean solution, but I see huge DRY's in my mind when going to code this solution.

So, I have two controllers from two models, each one at and exposes a @photo object (photos controller with all the photos, and categories controller with just the selected categorie's photos) and I need one view to show both.

I'm looking for an elegant solution for this, complaining REST and DRY principes. Any idea?

Thanks in advance.

blank
  • 17,852
  • 20
  • 105
  • 159
ARemesal
  • 2,923
  • 5
  • 24
  • 23

5 Answers5

40

I have a similar situation with one of my projects. All the delete views for most controllers are styled the same way, display the same confirmation boxes, and simply renders a predictable display of whatever object is being deleted.

The solution was quite simple and elegant in my opinion. Simply put, what we (the developers) did was create a new directory in app/views called shared and put shared views in there. These could be full template files or just partials.

I would suggest using a shared template (in neither categories nor photos view directories, but rather in the shared directory) and rendering it manually from the view.

e.g. have a method as such in both controllers and a file app/views/shared/photo.html.erb:

def show
  @photo = Photo.first # ... or whatever here
  render :template => 'shared/photo'
end

This should successfully render the shared template. It is the DRYest route and doesn't have the feeling of pollution you get when using a more-or-less empty view in each controller's view directory just to include a shared partial, as I understand your question is suggesting.

Bo Jeanes
  • 6,294
  • 4
  • 42
  • 39
  • Ah brilliant! I just spent 2 hours trying to DRY up one of my partials that was causing me grief. Thankyou - this is so simple. – brad Jan 23 '11 at 10:10
  • Now what happens when you need to load that template with AJAX? :) – Noz Feb 17 '15 at 21:18
  • When I try this in Rails 4.2.5 I get the error "ActionController::RackDelegation#content_type delegated to @_response.content_type, but @_response is nil: # – Dave Munger Dec 03 '15 at 01:54
  • I honestly don't know. I haven't done much view stuff in newer versions of Rails (I am more API-oriented these days). Sorry. – Bo Jeanes Dec 08 '15 at 01:15
  • When you do that and realize the magic of rails. How awesome, thank you. – Kostas Andrianos Jul 08 '17 at 14:53
6

About the first answer:

If the partial must be rendered from a view:

<%= render :partial => "shared/photo" %>

and the partial must be in app/views/shared/_photo.html.erb

Community
  • 1
  • 1
Rodrigo
  • 61
  • 1
  • 1
1

I'd use an helper because they are shared among views. For the HTML part, I'd use partials so it would be a mix of both ways.

Keltia
  • 14,535
  • 3
  • 29
  • 30
  • Yes, i think it's the best solution due to its visibility from every controller or view, but, is it correct to put view code (html code) in a helper? – ARemesal Jan 23 '09 at 13:30
  • It'd be better to not put view code in the helpers unless it is less than a few lines – Bo Jeanes Jan 23 '09 at 14:00
  • I'd use a mix of partial for the HTML code and helpers for the code. – Keltia Jan 23 '09 at 14:25
1

This looks like a good use case for the Cells gem.

Marnen Laibow-Koser
  • 5,959
  • 1
  • 28
  • 33
0

@bjeanes If all your delete views are the same, you can create views/default/delete.html.erb and all the delete actions will use it.

That's what i'm doing: Most of my views are on default, and i create specific ones only when needed

Update: Ok, this post is from 2009, anyway, i will keep my comment here in case someone gets here from Google like i did.

carlosvini
  • 1,742
  • 19
  • 18