清理(DRY)这个控制器的好方法是什么?
What's a good approach to clean up (DRY) this controller?
我在我的控制器上的每个创建、更新和 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 参数(字符串)。
我不确定StoryStateService
在做什么,但是如果是处理更新一些模型,那么你也可以制作一个模块或class并将它放在lib
目录。
另一种选择是(这可能更适合 Story.find()
)是使用 before_action
回调。 (https://apidock.com/rails/v4.0.2/AbstractController/Callbacks/ClassMethods/before_action)
例如
当您在 update
和 update_story_status_event
中使用 Story.find()
时,您可以执行以下操作:
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
我只会提取故事的进展,考虑到其他一切的简单性,任何超出此范围的内容对我来说都太过分了。
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
我在我的控制器上的每个创建、更新和 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 参数(字符串)。
我不确定StoryStateService
在做什么,但是如果是处理更新一些模型,那么你也可以制作一个模块或class并将它放在lib
目录。
另一种选择是(这可能更适合 Story.find()
)是使用 before_action
回调。 (https://apidock.com/rails/v4.0.2/AbstractController/Callbacks/ClassMethods/before_action)
例如
当您在 update
和 update_story_status_event
中使用 Story.find()
时,您可以执行以下操作:
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
我只会提取故事的进展,考虑到其他一切的简单性,任何超出此范围的内容对我来说都太过分了。
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