You don't need view logic in models
Jake Scruggs wrote about moving view logic into his models
It’s hard to tell without knowing the full dataset, but my approach to these sort of problems is to reduce the data down to the simplest possible form (usually a hash), and then use an algorithm to extract what I need.
One commenter tried this and I think it’s heading in the right direction. There is potentially quite a lot of duplication here – the repetition of the layouts and scripts. To ease this it can sometimes be easier to inverse the key/values, for a more concise representation. You could reduce this even further if there were sensible defaults (if 90% of cars used a two_column layout, for instance) – just replace the raise in the following code.
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 |
# See original post for context # Data layouts = { 'two_column' => [Toyota, Saturn], 'three_column' => [Hyundai], 'ford' => [Ford] } scripts => { 'discount' => [Hyundai, Ford], 'poll' => [Saturn] } # Algorithm find_key = lambda {|hash, car| ( hash.detect {|key, types| types.any? {|type| car.is_a?(type)} # types.include?(car.class) if you're not using inheritance } || raise("No entry for car: #{car}") ).first } layout = find_key[layouts, @car] script = find_key[scripts, @car] @stylesheets += ['layout', 'theme'].collect {|suffix| "#{layout}_#{suffix}.css" } @scripts += ["#{script}.js"] render :action => find_view, :layout => layout |
This is preferable to putting this data in your object hierarchy for all the normal reasons, especially since it keeps view logic where you expect to find it and doesn’t muddy up your models.
Hash trumps case
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# Two equivalent functions def rgb(color) case color when :red then 'ff0000' when :green then '00ff00' when :blue then '0000ff' else '000000' # Default to black end end def rgb2(color) { :red => 'ff0000', :green => '00ff00', :blue => '0000ff' }[color] || '000000' end |
Even though these functions are equivalent, the second carries more semantic weight – it maps a symbol directly to a color. The case sample makes no such guarantees since you can execute any arbitrary code in the then block. In addition, a hash is easier to work with – you can easily iterate over the keys, extract to another method if you need reuse, or query it for other properties (for example, 3 colors are available). It is also easier to read – both aesthetically and because it contains fewer tokens. In almost all circumstances I will prefer a hash over a case statement.
Relationships in data are easier to comprehend and manipulate than relationships in code.