更好的设计是使用构建器类。 它只是一个PORO(Plain Old Ruby Object)。 这将允许您做的是围绕构建器编写好的测试。 因此,您可以更加放心,它将始终有效,并且某些更改为rails并未破坏它。
这里有一些伪代码可以帮助你:
ProjectsController << ApplicationController def update @project = Project.find(params[:id]) # This should return true if everything works, and result = ProjectMilestoneBuilder.perform(@project, update_params) if result == false # Something went very wrong in the builder end if result.errors.any? #handle success else # handle failure # The project wasn't updated, but things didn't explode. end end private def update_params params.require(:project).permit(:name, :milestones => [:name, :milestone_ids, :tasks => [:task_ids] ] ) end end
在/lib/project_milestone_builder.rb中
class ProjectMilestoneBuilder def self.perform(project, params) milestone_params = params[:project][:milestones] milestone_params.each do |m| # Something like this # Might be able to use nested attributes for this # Milestone.create(m) end return project.update_attributes(params) end end
在/spec/lib/project_milestone_builder_spec.rb中
descibe ProjectMilestoneBuilder do # Create a template and project let(:template) {FactoryGirl.create :template} let(:project) {FactoryGirl.create :project, template: template} # Create the params to update the project with. # This will have to have dynamic code segments to get the appropriate milestone_template_ids in there let(:params) { "{project: {milestones ..." }) descibe '#perform' do let(:result) { ProjectMilestoneBuilder.perform(project, params) } it {expect(result.id).to eq project.id} # ... end end