I'm Thinking of Putting View Logic into a Model

25 Aug 2008

As I am clearly crazy, but hear me out. Say there’s a Car object that uses single table inheritance and all the objects that descended from it are routed through the car method in the CarController. The CarController looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

class CarController < ApplicationController
def car
layout = nil
@scripts = []
@stylesheets = []
@car = Car.find(params[:id])
if @car.is_a?(Toyota)
layout = ‘two_column’
@stylesheets « ‘two_column_layout.css’
@stylesheets « ‘two_column_theme.css’
elsif @car.is_a?(Hyundai)
layout = ‘three_column’
@stylesheets « ‘three_column_layout.css’
@stylesheets « ‘three_column_theme.css’
@stylesheets « ‘hyundai_theme.css’
@scripts « ‘discount.js’
elsif @car.is_a?(Ford)
layout = ‘ford’
@stylesheets « ‘ford_layout.css’
@stylesheets « ‘ford_theme.css’
@scripts « ‘discount.js’
elsif @car.is_a?(Saturn)
layout = ‘two_column’
@stylesheets « ‘two_column_layout.css’
@stylesheets « ‘two_column_theme.css’
@scripts « ‘poll.js’
#
# 100 more lines like above
#
end
render :action => find_view, :layout => layout
end
end

So I’m not very happy about this and ultimately I’d like to refactor the app to use different controllers for different objects (crazy huh?), but that is a major undertaking as the whole app assumes this architecture. It occurred to me the other day that there’s an in-between step. I could do something like this:

1
2
3
4
5
6
7
8
9
10
11

class Car < ActiveRecord::Base
def layout
‘two_column’
end
def stylesheets
[‘two_column_layout.css’, ‘two_column_theme.css’]
end
def scripts
[]
end
end

And then the Ford class would look like this:

1
2
3
4
5
6
7
8
9
10
11

class Ford < Car
def layout
‘ford’
end
def stylesheets
[‘ford_layout.css’, ‘ford_theme.css’]
end
def scripts
[‘discount.js’]
end
end

So the CarController could then be shortened to this:

1
2
3
4
5
6
7
8
9

class CarController < ApplicationController
def car
@car = Car.find(params[:id])
@scripts = @car.scripts
@stylesheets = @car.stylesheets

render :action =\> find_view, :layout =\> @car.layout     end   end

Any model that needs to overwrite the default layout, scripts, or stylesheets can.

So should I take this step and put view information in the models, or should I just hold out for the big refactor into separate controllers? Keep in mind the big refactor is so big that it may never happen.