假设我有以下控制器和包含的方法。我觉得这个控制器方法(列表)太重了。我该怎么分开呢?什么应该移动到视图层,什么应该移动到模型层?
注意:返回格式(包含:text,:leaf:,id,:cls)包含与ProjectFile数据库表中的字段不同的字段,因此这让我怀疑这个控制器方法实际应该移动到多少模型层。
class ProjectFileController < ApplicationController
before_filter :require_user
def list
@project_id = params[:project_id]
@folder_id = params[:folder_id]
current_user = UserSession.find
@user_id = current_user && current_user.record.id
node_list = []
# If no project id was specified, return a list of all projects.
if @project_id == nil and @folder_id == nil
# Get a list of projects for the current user.
projects = Project.find_all_by_user_id(@user_id)
# Add each project to the node list.
projects.each do |project|
node_list << {
:text => project.name,
:leaf => false,
:id => project.id.to_s + '|0',
:cls => 'project',
:draggable => false
}
end
else
# If a project id was specfied, but no file id was also specified, return a
# list of all top-level folders for the given project.
if @project_id != nil and @folder_id == nil
# Look for top-level folders for the project.
@folder_id = 0
end
directory_list = []
file_list = []
known_file_extensions = ['rb', 'erb', 'rhtml', 'php', 'py', 'css', 'html', 'txt', 'js', 'bmp', 'gif', 'h', 'jpg', 'mov', 'mp3', 'pdf', 'png', 'psd', 'svg', 'wav', 'xsl']
# Get a list of files by project and parent directory.
project_files = ProjectFile.find_all_by_project_id(@project_id,
:conditions => "ancestry like '%#{@folder_id}'",
:order => 'name')
project_files.each do |project_file|
file_extension = File.extname(project_file.name).gsub('.', '')
if known_file_extensions.include? file_extension
css_class_name = file_extension
else
css_class_name = 'unknown'
end
# Determine whether this is a file or directory.
if project_file.is_directory
directory_list << {
:text => project_file.name,
:leaf => false,
:id => @project_id + '|' + project_file.id.to_s,
:cls => css_class_name
}
else
file_list << {
:text => project_file.name,
:leaf => true,
:id => @project_id + '|' + project_file.id.to_s,
:cls => css_class_name
}
end
end
node_list = directory_list | file_list
end
render :json => node_list
end
end
答案 0 :(得分:3)
我认为您可以将大部分逻辑放在模型中ProjectFile
或任何合适的模型名称:
ProjectFile < ActiveRecord::Base
def node_list(project_id, folder_id, user_id)
node_list = []
# If no project id was specified, return a list of all projects.
if project_id == nil and folder_id == nil
# Get a list of projects for the current user.
projects = Project.find_all_by_user_id(user_id)
# Add each project to the node list.
projects.each do |project|
node_list << {
:text => project.name,
:leaf => false,
:id => project.id.to_s + '|0',
:cls => 'project',
:draggable => false
}
end
else
# If a project id was specfied, but no file id was also specified, return a
# list of all top-level folders for the given project.
if project_id != nil and folder_id == nil
# Look for top-level folders for the project.
folder_id = 0
end
directory_list = []
file_list = []
known_file_extensions = ['rb', 'erb', 'rhtml', 'php', 'py', 'css', 'html', 'txt', 'js', 'bmp', 'gif', 'h', 'jpg', 'mov', 'mp3', 'pdf', 'png', 'psd', 'svg', 'wav', 'xsl']
# Get a list of files by project and parent directory.
project_files = ProjectFile.find_all_by_project_id(project_id,
:conditions => "ancestry like '%#{folder_id}'",
:order => 'name')
project_files.each do |project_file|
file_extension = File.extname(project_file.name).gsub('.', '')
if known_file_extensions.include? file_extension
css_class_name = file_extension
else
css_class_name = 'unknown'
end
# Determine whether this is a file or directory.
if project_file.is_directory
directory_list << {
:text => project_file.name,
:leaf => false,
:id => project_id + '|' + project_file.id.to_s,
:cls => css_class_name
}
else
file_list << {
:text => project_file.name,
:leaf => true,
:id => project_id + '|' + project_file.id.to_s,
:cls => css_class_name
}
end
end
node_list = directory_list | file_list
end
end
然后将node_list
分解为更易于管理的方法。我上面定义的方法很长并且做了很多事情(低内聚力),所以打破它会有助于消除这些缺点。
在您的控制器中,您可以这样称呼:
class ProjectFileController < ApplicationController
before_filter :require_user
def list
@project_id = params[:project_id]
@folder_id = params[:folder_id]
current_user = UserSession.find
@user_id = current_user && current_user.record.id
nodes = node_list(@project_id, @folder_id, @user_id)
render :json => nodes
end
end
现在您的控制器更易于阅读并且提取了业务逻辑。这遵循咒语“瘦的控制器,胖模型”。
答案 1 :(得分:1)
您的用户模型中应该有一个关联,如
has_many => :projects
因此,您可以使用
获取项目对象的数组current_user.projects
而不是:
projects = Project.find_all_by_user_id(@user_id)
这意味着您也不需要检索user_id。
您还可以将用于填充node_list的所有逻辑放入用户模型中。只需输入你的模型:
def node_list(project_id, folder_id=0)
if @project_id == nil
list = self.projects.map do |project|
{
:text => project.name,
:leaf => false,
:id => project.id.to_s + '|0',
:cls => 'project',
:draggable => false
}
end
else
... # the rest of your code here, etc
end
return list
end
请注意,如果folder_id为nil且设置为零,也可以删除您的检查,因为folder_id=0
中的def node_list(project_id, folder_id=0)
会自动执行此操作。
然后您的控制器将如下所示:
def list
@current_user = UserSession.find
render :json => @current_user.node_list(params[:project_id], params[:folder_id])
end
同时强>
因为你只是组合了directory_list和file_list,为什么不把if-else语句组合成:
{
:text => project_file.name,
:leaf => project_file.is_directory,
:id => @project_id + '|' + project_file.id.to_s,
:cls => css_class_name
}
如有必要,您随后可以随后对数组进行排序。
答案 2 :(得分:1)
@Chad,
我认为你已经有很好的例子来重构你在我之前发布的人的代码。
你似乎有能力编写ruby代码,所以我将尝试从“如何重构”的观点回答你的问题。
保持控制器枯瘦
保持模特脂肪