views:

55

answers:

3

I have a controller that has two actions: "show", "show_modify". These have very similar yet slightly different views, i.e show_modify has different div classes, has extra links/buttons and so on.

From what I've seen there are a few ways to approach this in rails:

  1. Make one template for the two and just add conditions inside:
    <% if param[:action]=="show_modify"> <% ... %> <% end %>
    yet there are so many differences that this seems very ugly and repetitious, and also is this some kind of violation of the seperation of church and state (I'm not a MVC expert... )

  2. The partial way: For every element that is displayed differently create two partials, one for each action. The views would look something like this:
    # show_modify
    render :partial '_general_stuff'
    render :partial => '_blabla_show_modify'

    # show
    render :partial => '_general_stuff'
    render :partial => '_blabla_show'

    Yet this will violate DRY, because there are overlapping elements. I can continue making more sub partials, but it's basically turtles all the way down - eventually you have to go if/else if you dont want to repeat yourself.

  3. partials with locals:

    if show
    render :partial = '_blabla', :locals => {:bckgrnd => 'blue', :button => 'yes' ....}

but this is another lots-o-ifs solution....

Any better options out there? content_for maybe? I'm kind of a rails noob+, so i might have missed something altogether....

Thanks :)

A: 

From your description, the two views do not seem very similar, throughout the complete view all kind of exceptions are made. Hence your problem with the many if statements or partials which are not working.

Is it not possible to refactor your views in such a way that they matching better? For example keep the div classnames the same and switch CSS depending on your view. Then using the partial views method might be working much nicer. Especially if you also move the links (submit button?) outside this partial view and put it in the show_modify view.

Veger
A: 

If the differences are very small you can use your first idea, but I'd rather make some helpers:

def show_modify?
  param[:action] == "show_modify"
end

and then in views:

<% if show_modify? %>
  some html
<% end %>
...
<%= link_to "something", some_path if show_modify? %>

and so on.

In case of classes of divs I'd use helper methods to generate class name:

def set_class
  return "first_class" if show_modify?
  "second_class"
end
klew
I wasn't aware of the <% link_to .. if .. %> construct. It's very readable and produces much less clutter... Thanks!
Assaf
A: 

Try extending the object as a view model. This is really common in ASP.NET MVC, when you want to extend a domain object with things that have nothing to do with the business domain.

class User < ActiveRecord::Base
  # id, integer
  # first_name, string
  # last_name, string
  # only put the business-y stuff here. validations, etc.
end

class ShowUserViewModel < User
  def background_color
    "#0000ff"
  end

  def template
    "show"
  end
end

class EditUserViewModel < User

  def background_color
    "#00ff00"
  end

  def template
    "show_modify"
  end
end

From your controller, depending on the action taken, return the appropriate object. The view models are still "Users", but they're supplemented with more information necessary for the view. This can really keep a lot of if and for structures out of the view.

Jarrett Meyer
This is not a very clean way, since Models should be used to grab data (from eg a database) so it can be used in a view. A cleaner solution is to use Helper methods and dynamically add their functionality to the Controller depending on the view
Veger