2011-05-06 39 views
0

有没有一种方法可以干净利落地加载对象(不使用before_filter)。Rails 3 - 如何重构此控制器代码?

事实上,我需要@answer和@question以外的其他方法比“show”。

控制器:

def show 
@answer = Answer.new pre_form 
@question = Question.find(params[:id]) 
@answers = @question.answers.page(params[:page]) 
respond_with @question 
end 

private 

def pre_form  
    session[:pre_form][:answer] || session[:pre_form][:question] if session[:pre_form] 
end 

在此先感谢

回答

2

你可以很确定如果需要的话,其获取这些为你一个方法:

def fetch_question_and_answer(params) 
    @answer = Answer.new pre_form 
    @question = Question.find(params[:id]) 
    @answers = @question.answers.page(params[:page]) 
end 

这会推出这种成一个简单的方法调用您的各种控制器方法:

def show 
    fetch_question_and_answer(params) 
    respond_with @question 
end 

在这样的方法中去分配实例变量可能有些鬼鬼祟祟,因为它最终会在坏的意义上变成一个小的神奇的,所以要小心地标记你的方法以避免混淆。另一种方法是简单地返回并根据具体情况分配它们。

但我不确定为什么你反对before_filter方法,因为这就是那些应该设置实例变量,所以相同的规则不适用。

+0

+1,强调'before_filter'是正确的路要走。 – coreyward 2011-05-06 16:51:59

+0

我读过它被折旧,而不是通过筛选前设置实例变量的最佳实践。因为它是魔术,并且因为它是私有/受保护的,因此实例变量被隐藏。我错了吗 ? – invaino 2011-05-06 16:53:09

+0

我想知道你在哪里阅读,因为我从来没有听说过这样的事情。 'before_filter'是控制器中的重要方法之一,并且由于各种原因很重要。有时候,文档标记方法的*实现*被弃用,因为它被移动到另一个模块,但该方法本身仍然有效。实例变量隐藏或保护的情况也不是这样,因为在Ruby中这是不可能的。如果定义了一个实例变量,它将被传递给视图上下文。 – tadman 2011-05-06 19:11:10

1

上面类似,你可以有,你可以像使用实例变量的辅助方法:

helper_method :answer, :question, :answers 

def answer 
    @answer ||= Answer.new pre_form 
end 

def question 
    @question ||= Question.find(params[:id]) 
end 

def answers 
    @answers ||= question.answers.page(params[:page]) 
end 

因为他们是helper_methods,你可以在你的观点太使用它们!

1

除了来自@ question.answers.page(params [:page])之外,你做这件事的方式已经足够好了,它不遵循德米特法则,并且可以用更好的方式书写。

相反,你可以创建一个answers.page委托,这样就可以调用:

@question.answers_page(params[:page]) 

如果你有兴趣更好的设计(好像你是),请记住,2点在Rails声明能够以更好,更封装的方式书写的可能性更高。

如果您发现自己一直在创建新的答案和提取参数,则可以使用tadman提出的方法使其保持DRYer状态。而且,您应该考虑将该方法推入模块。然而,想一想,看看你是否真的需要为DRYer代码做这件事。一般来说,id的新实例和最简单的查找器往往通过控制器来使用。