我有一个很长的控制器方法,有很多重定向条件:
def show
get_param_user
if params[:id].match(/\D/)
@document = Document.where(:user_id => @user.id, :issue => params[:id]).first
else
@document = Document.find(params[:id])
end
unless @document.blank?
unless @document.template.name == "Media"
unless @document.retired?
@creator = User.find(@document.user)
if @creator == @user # if document exists, based on name and id
@document.components.each do |a|
redirect_to share_error_url, :flash => { :error => "#{@document.title} contains retired content and is now unavailable." } if a.retired? and return
end
render @document.template.name.downcase.parameterize.underscore
end
else # if retired
redirect_to share_error_url, :flash => { :error => "That document has expired." } and return
end
else # if media
redirect_to share_error_url, :flash => { :error => "Media has no public link." } and return
end
else # if document doesn't exist
redirect_to share_error_url, :flash => { :error => "Can't find that document. Maybe check your link. Or maybe it was deleted. Ask #{@user.name}." } and return
end
end
正如您可能猜到的那样,在某些条件下容易出错。是否有更简洁的方法来重写它以使其更强大?我知道方法应该只有一个render
或redirect_to
,但我不确定如何实现我的需要。
谢谢!
答案 0 :(得分:3)
一些特定的小事。
首先,一般情况下,最好不要将until
与else
条件一起使用,如果可以使用if
则更少:
unless @document.blank?
与
相同if @document.present?
其次,你使用
@creator = User.find(@document.user)
通常你可以简单地使用:
@creator = @document.user
语义有点不同(在第一种情况下如果@document.user
是nil
你会立即获得异常,在第二种情况下不是),但第二种是你通常需要的。
第三,如果它是明智的,你可以将代码移到远离控制器的模型,并使用一些不错的枚举器:
def has_retired_components?
@document.components.any?(&:retired?)
end
此外,您的控制器方法不是 复杂。它只是
if @document.present? and @document.showable? # also @document.try(:showable?)
render whatever
else
redirect_to error_url, flash: { error: error_message }
end
error_message
可能是方法调用的结果(如果有意义,则在对象本身上)。这样你就可以移动逻辑来验证oject是否可以在其他地方显示,而不是在渲染逻辑上混乱。
问题在于,如果您使用showable?
方法而另一个方法显示错误消息,则必须确保业务逻辑在两者中始终正确。一个选项是对待它与验证的工作方式类似:有一个方法(让我们在这里用可怕的名字showable_validation
调用它继续),它返回一个包含错误和消息的哈希(对象没有的原因)可以显示,例如{title: 'this is an error message'}
。showable?
方法将是:
def showable?
showable_validation.empty?
end
然后你会在模型中有类似的东西:
def showable_error
showable_validation.values.first
end
那就是error_message
(@document.showable_error
)。这样,逻辑只在一种方法中。