在Rails 5中使用responders gem的控制器代码问题咨询
Hey there! Let's take your OfficehoursController and trim it down to be even more DRY using the Responders gem. Your current code is already on the right track, but we can leverage the gem's built-in tools to make it cleaner and add useful functionality without extra lines.
Your Current Code
class OfficehoursController < ApplicationController def new @officehour = Officehour.new end def create @officehour = Officehour.create(officehour_params) respond_with(@officehour, location: officehours_path) end def officehour_params params.require(:officehour).permit(:end, :start, :status) end end
First Pass: Basic DRY Refactor
First, make sure the responders gem is installed in your project. Then we can start by adding common responder behaviors and cleaning up the respond_with call:
class OfficehoursController < ApplicationController # Include flash messages and HTTP caching helpers out of the box responders :flash, :http_cache def new @officehour = Officehour.new end def create @officehour = Officehour.create(officehour_params) # No need to explicitly pass location if we set a default below respond_with(@officehour) end # Mark params method as private (Rails best practice) private def officehour_params params.require(:officehour).permit(:end, :start, :status) end end
Even Cleaner: Set Default Redirect Location
You mentioned the create action correctly redirects to officehours_path when params are valid. To avoid passing location: every time, we can set this as the default for successful creates:
Option 1: Override Location in the Controller
This is the simplest approach for one-off controller needs:
class OfficehoursController < ApplicationController responders :flash, :http_cache def new @officehour = Officehour.new end def create @officehour = Officehour.create(officehour_params) respond_with(@officehour) end private def officehour_params params.require(:officehour).permit(:end, :start, :status) end # Customize location for successful create actions def location_for(resource) officehours_path if action_name == 'create' end end
Option 2: Custom Responder (For Reusable Logic)
If you want this redirect behavior across multiple controllers, create a custom responder:
- Create
app/responders/resource_collection_responder.rb:
class ResourceCollectionResponder < ActionController::Responder def location # Redirect to index on successful create, use default otherwise if resource.persisted? && action_name == 'create' send("#{controller_name}_path") else super end end end
- Update your controller to use this responder:
class OfficehoursController < ApplicationController # Use our custom responder plus flash/http cache helpers responders ResourceCollectionResponder, :flash, :http_cache def new @officehour = Officehour.new end def create @officehour = Officehour.create(officehour_params) respond_with(@officehour) end private def officehour_params params.require(:officehour).permit(:end, :start, :status) end end
What We Gained:
- Less boilerplate: No more repeating the redirect location in
respond_with - Free functionality: The
:flashresponder automatically adds success/error flash messages when the resource is saved or fails validation (no need for manualif @officehour.saveblocks!) - Best practices: Marked
officehour_paramsas private, keeping internal controller logic encapsulated - Maintainability: Custom responders let you share redirect logic across controllers without duplication
Your create action will still behave exactly as before (redirecting to the officehours index on valid params) but with cleaner, more DRY code.
内容的提问来源于stack exchange,提问作者dev_054

