视图层中的逻辑是一种反模式,因为它使视图的可读性降低/与领域语言的关联性降低。
您是否考虑过将您的@places 包装在您自己创建的decorator object 中?假设我正确理解了这个问题(免责声明:不是 100% 肯定我这样做了),我可能会这样做:
假设你的控制器是PlacesController...
# app/controllers/places_controller.rb
class PlacesController < ApplicationController
def index
@places = PlaceWithLevels.decorate(places)
end
private
def places
Place.all
end
end
现在我们定义装饰器对象PlaceWithLevels(根据您的域,您可能会想出一个更好的名称):
# app/models/place_with_levels.rb
class PlaceWithLevels < SimpleDelegator
def self.decorate(places)
places.map do |place|
self.new(place)
end
end
# not sure what to name this since I'm not sure what you're
# trying to accomplish, but note that this is the method we'll
# be calling in the partial
def foo
case levels
when 0; 'Text you want to show up when there are 0 levels'
when 1; 'Text you want to show up when there is 1 level'
when 2; 'Text you want to show up when there are 2 levels'
end
end
那么,在视图中:
# app/views/places/index.html.haml
= render @places
请注意,我们不需要调用@places.each,因为render 将对集合的每个成员调用#to_partial_path,以确定要渲染的部分。
最后,在部分(由于我们使用上面的SimpleDelegator,对places_rooms等的方法调用将在这里工作):
# app/views/places/_place.html.haml
%table.table
%caption
%h2= place.name
%thead
%tbody
%tr
%td
Name:
%td
= place.foo
%tr
%td
Total rooms:
%td
= place.places_rooms
%tr
%td
Total places:
%td
= place.places_count
请注意,我们这里不再需要特殊的逻辑...只需在我们的装饰器对象上调用name 方法(或任何适当的方法),但从视图的角度来看,视图不需要要知道它可以与 place 以外的任何东西一起使用。
如果您需要根据level 属性呈现完全不同的部分,此技术也非常有用 — 只需在装饰器对象上定义您自己的 to_partial_path 方法,例如:
def to_partial_path
case level
when 0; 'zero_level_place'
when 1; 'single_level_place'
when 2; 'two_level_place'
end
希望这有帮助!!!!
PS:我也鼓励你去掉places_rooms、places_count等上的places_前缀...更好的信噪比。