这是我努力寻找良好解决方案的那些“真实世界项目”问题之一。Rails 4+:具有多个关联的单个资源,控制器组织
我有一个task
模型与几种不同的资源相关联,我需要允许来自每个这些关联资源的CRUD能力。
例如,一个project
有很多tasks
,我需要更新tasks
在project
的上下文中。
此外,每个project
有许多milestones
,并且每个milestone
也可以有很多tasks
。
这种情况下,task
可能会或可能不会与milestone
相关联。
class Project < ApplicationRecord
has_many :milestones
has_many :tasks
end
class Milestone < ApplicationRecord
belongs_to :project # required
has_many :tasks
end
class Task < ApplicationRecord
belongs_to :project # required
belongs_to :milestone # optional
end
我有命名空间我的控制器更好的组织和控制。这使我的路线,如:
# routes.rb
resources :projects do
namespace :projects do
resources :milestones # app/controllers/projects/milestones_controller.rb
resources :tasks # app/controllers/projects/tasks_controller.rb
end
end
resources :milestones do
namespace :milestones do
resources :tasks # app/controllers/milestones/tasks_controller.rb
end
end
我也是用了很多AJAX的,使接口快(与Turbolinks),所以我的行动遵循<action>.js.erb
格式,其中使用JavaScript来更新页面,而不是页面刷新。请注意,我为task
表单也使用了对话框/弹出式界面,因此我不能只进行整个页面刷新。
虽然这个“工作”,它结束了我有很多重复代码的情况。
# projects/tasks_controller.rb
def new
@project = Project.find(params[:project_id])
@task = @project.tasks.new
end
def create
@project = Project.find(params[:project_id])
@task = @project.tasks.new(task_params)
if @task.save
# create.js.erb
else
render js: "alert('error');" # example...
end
end
# app/views/projects/tasks/create.js.erb
$("#tasks_for_<%= dom_id(@project) %>").append("<%=j render(partial: 'projects/tasks/task') %>");
# milestones/tasks_controller.rb
def new
@milestone = Milestone.find(params[:milestone_id])
@task = @milestone.tasks.new
end
def create
@milestone = Milestone.find(params[:milestone_id])
@task = @milestone.tasks.new(task_params)
if @task.save
# create.js.erb
else
render js: "alert('error');" # example...
end
end
# app/views/milestones/tasks/create.js.erb
$("#tasks_for_<%= dom_id(@milestone) %>").append("<%=j render(partial: 'milestones/tasks/task') %>");
这只是一些示例代码,来自实际系统的代码显示了更多的重复。如您所知,每个不同资源中有很多重复代码,与tasks
资源的交互稍有不同。
是否有一些标准格式或Rails功能可以帮助构建由其他资源操纵的资源?
我怎样才能减少这种重复?它直接导致一个复杂的系统,每当我添加或更改某个功能时,我都必须在3个以上的不同地方进行更改。
这正是为什么你应该使用演示者,服务,经理等(所有普通的老红宝石对象)。 – jvillian
@jvillian:我确实使用演示者和服务对象以及其他PORO。但我不确定这些将如何帮助减少上述控制器和视图的重复?问题在于3个以上的地方使用相同代码的90%,我不确定如何干掉代码,但仍然允许10%的差异。 –