The Refactoring
Today’s refactoring follows up on yesterday’s. Now that I have the #new
and #create
actions for REST, I can start to remove the duplication I introduced.
Before
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# app/controllers/issues_controller.rb class IssuesController 'new', :layout => !request.xhr? end def create @issue = Issue.new @issue.copy_from(params[:copy_from]) if params[:copy_from] @issue.project = @project # Tracker must be set before custom field values @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first) if @issue.tracker.nil? render_error l(:error_no_tracker_in_project) return end if @issue.status.nil? render_error l(:error_no_default_issue_status) return end if params[:issue].is_a?(Hash) @issue.safe_attributes = params[:issue] @issue.watcher_user_ids = params[:issue]['watcher_user_ids'] if User.current.allowed_to?(:add_issue_watchers, @project) end @issue.author = User.current @priorities = IssuePriority.all @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true) call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue }) if @issue.save attachments = Attachment.attach_files(@issue, params[:attachments]) render_attachment_warning_if_needed(@issue) flash[:notice] = l(:notice_successful_create) call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue}) respond_to do |format| format.html { redirect_to(params[:continue] ? { :action => 'new', :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } : { :action => 'show', :id => @issue }) } format.xml { render :action => 'show', :status => :created, :location => url_for(:controller => 'issues', :action => 'show', :id => @issue) } end return else respond_to do |format| format.html { render :action => 'new' } format.xml { render(:xml => @issue.errors, :status => :unprocessable_entity); return } end end end end |
After
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# app/controllers/issues_controller.rb class IssuesController [:new, :create] def new render :action => 'new', :layout => !request.xhr? end def create call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue }) if @issue.save attachments = Attachment.attach_files(@issue, params[:attachments]) render_attachment_warning_if_needed(@issue) flash[:notice] = l(:notice_successful_create) call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue}) respond_to do |format| format.html { redirect_to(params[:continue] ? { :action => 'new', :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } : { :action => 'show', :id => @issue }) } format.xml { render :action => 'show', :status => :created, :location => url_for(:controller => 'issues', :action => 'show', :id => @issue) } end return else respond_to do |format| format.html { render :action => 'new' } format.xml { render(:xml => @issue.errors, :status => :unprocessable_entity); return } end end end private def build_new_issue_from_params @issue = Issue.new @issue.copy_from(params[:copy_from]) if params[:copy_from] @issue.project = @project # Tracker must be set before custom field values @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first) if @issue.tracker.nil? render_error l(:error_no_tracker_in_project) return false end if @issue.status.nil? render_error l(:error_no_default_issue_status) return false end if params[:issue].is_a?(Hash) @issue.safe_attributes = params[:issue] @issue.watcher_user_ids = params[:issue]['watcher_user_ids'] if User.current.allowed_to?(:add_issue_watchers, @project) end @issue.author = User.current @issue.start_date ||= Date.today @priorities = IssuePriority.all @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true) end end |
Review
By using a before_filter
I was able to move a bunch of the setup logic to #build_new_issue_from_params
. It also let me return false from the before_filter
and handle the two error states properly.
There still is a lot of work that’s needed in IssuesController
but now it finally matches the Rails REST format. I’m going to have to think what I want to do next:
- move the extra actions out of the controller, or
- try to take the controller the full way to a REST controller (e.g.
map.resources :issues
)
What do you think?