开发者

DRY a large chunk of common code with two vastly different uses

I have a 'widget' that comprises an html/css block of code. It is a type of data layout, which I call the 'stack'.

The stack has bits of .erb (Ruby on Rails) embedded in it, which enters the data for each user.

I need to include this stack in multiple places, where it needs to represent different data from different models.

So, one stack might contain a field called @company.name and the other stack might contain @project.name || "Unidentified Project".

How does one refactor / organize this situation? Options that I can see:

  1. Have two separate stacks, which would in开发者_JAVA百科troduce redundancy and inconsistency, but would be an obvious answer to the problem without limit to scenario-specific customization.
  2. Include if statements for every data point to test which circumstance the stack is being used for, but this is very code-ugly and unsustainably complicated for more than 2 stacks.
  3. Some unknown unknown.

How would you tackle this?


One simple way would be to write the erb in a generic way so that it works for either a project or a company for example, in your Project model you could put:

def display_name
  name || "Unidentified Project"
end

Then in your Company model put:

def display_name
  name
end

When you render the ERB, pass in a variable with some generic name like main_object and call its display_name function. The ERB code would not know or care what class main_object is:

<%= main_object.display_name %>

If it bothers you to put display-related functions like display_name in your models, you could use the Presenter pattern. A present is basically a plain-old ruby object that you create from your model(s) and then pass to the view. I saw a good talk on this pattern by Jeff Casimir called "Fat Models Aren't Enough" and the slides are here: http://en.oreilly.com/rails2011/public/schedule/detail/18514


David's solutions are good. In some situations you may also consider helpers or partials (e.g. if you want to include complex html). For example:

Helper

def display_name(object)
  if object.respond_to? :name and object.name
    object.name
  else
    if object.class.respond_to? :human_name
      "Unidentified #{object.class.human_name}"
    else
      "Unidentified #{object.class.name}"
    end
  end
end

Partial

<%= render :partial => "stack/name/#{object.class.underscore}", :locals => {object.class.underscore => object} %>

With any complex ERB in app/views/stack/name/_project.html.erb:

<label style="<%= "background-color: red;" if project.name.blank? %>">
  <%= project.name || "Unidentified Project" %>
</label>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜