清理(​​DRY)此控制器的好方法是什么?

时间:2019-06-18 12:40:25

标签: ruby-on-rails ruby design-patterns dry

我对控制器上的每个create,update和update_status方法都执行了一项操作,但是我感到自己在重复自己的工作,并且非常感谢您提供了一些更好的编写方法的帮助。

我已经将更新逻辑抽象为服务,但是在控制器的每个方法上,参数都是不同的。

def create
    @story = Story.new(story_params)
    @story.creator = current_user

    if @story.save

      next_state = StoryStateService.new(@story, current_user, nil).call

      if next_state 
        @story.update_column(:status_id, next_state) 
      end 

      redirect_to stories_path
    else
      render 'stories/new'
    end
  end

  def update
    @story = Story.find(params[:id])   

    if @story.update(story_params)

      next_state = StoryStateService.new(@story, current_user, nil).call

      if next_state 
        @story.update_column(:status_id, next_state) 
      end  

      redirect_to stories_path
    else
      render 'edit'
    end
  end

  def update_story_status_event
    story = Story.find(params['story_id'])
    sub_action = params['sub_action']

    next_state = StoryStateService.new(story, current_user, sub_action).call

    if next_state 
      story.update_column(:status_id, next_state) 
    end

    redirect_to stories_path
  end

如您所见,我有

   next_state = StoryStateService.new(story, current_user, sub_action).call

    if next_state 
      story.update_column(:status_id, next_state) 
    end

在三种方法上重复,但是在常规创建和更新时,我不需要发送sub_action参数(字符串)。

2 个答案:

答案 0 :(得分:0)

我不确定StoryStateService在做什么,但是如果它正在处理更新许多模型的问题,那么您还可以制作一个模块或类并将其放在lib目录中。 / p>

另一个选择是(对于Story.find()可能更优选)是使用before_action回调。 (https://apidock.com/rails/v4.0.2/AbstractController/Callbacks/ClassMethods/before_action

例如

Story.find()update中使用update_story_status_event时,您可以执行以下操作:

before_action :find_story, :only => [:update, :update_story_status_event]

   def find_story
     @story = Story.find(params[:id])
   rescue ActiveRecord::RecordNotFound
     # handle error here
   end  

答案 1 :(得分:0)

考虑到其他所有内容的简单性,我只会讲故事的进展,这对我来说是过大的。

def create
  @story = Story.new(story_params)
  @story.creator = current_user

  if @story.save
    advance_story @story

    redirect_to stories_path
  else
    render 'stories/new'
  end
end

def update
  @story = Story.find(params[:id])

  if @story.update(story_params)
    advance_story @story

    redirect_to stories_path
  else
    render 'edit'
  end
end

def update_story_status_event
  story = Story.find(params['story_id'])
  sub_action = params['sub_action']

  advance_story story, sub_action

  redirect_to stories_path
end

private 

def advance_story(story, sub_action = nil)
  next_state = StoryStateService.new(story, current_user, sub_action).call

  if next_state
    story.update_column(:status_id, next_state)
  end
end