- Read Tutorial
- Watch Guide Video
Now that our code is working fine, it's time to ensure that it follows Rails best practices. The first thing we are going to do is to remove some code in the create
method, and move it to a private method.
# app/controllers/posts_controller.rb private def post_params params.require(:post).permit (:date, :rationale) end
This is a necessary refactor since our create
method shouldn't be required to create a record in the database AND manage the list of allowable form components. That would break the single responsibility principle.
Next, notice how we are always redirecting to another page with the command redirect_to
? What if there are errors when saving a record? We need to implement the ability for our application to handle issues that arise during the creation process.
Let's implement some error management code in the create
method, like this:
# app/controllers/posts_controller.rb if @post.save redirect_to @post, notice: "Your post was created successfully." else render :new end
In this code, we are checking if the record was saved, and if so we are redirecting it, along with a notice that the post was created successfully. Otherwise, we are asking Ruby to render a new one. The complete code looks like this:
# app/controllers/posts_controller.rb class PostsController < ApplicationController def index end def new @post = Post.new end def create @post = Post.new(post_params) if @post.save redirect_to @post, notice: 'Your post was created successfully' else render :new end end def show @post = Post.find(params[:id]) end private def post_params params.require(:post).permit(:date, :rationale) end end
Now, if you run rspec
, everything should still be passing, which is always the goal after performing a refactor.
Next, let's look at our post_spec.rb
file and see if anything needs refactoring here. If you see, there's quite a bit of duplicate code, most notably our visit new_post_path
is duplicated in a number of places. So let's move that to a before
block:
# spec/features/post_spec.rb describe 'creation' do before do visit new_post_path end it 'has a new form that can be reached' do expect(page.status_code).to eq(200) end it 'can be created from new form page' do fill_in 'post[date]', with: Date.today fill_in 'post[rationale]', with: "Some rationale" click_on "Save" expect(page).to have_content("Some rationale") end end
Let's run rspec
again, and all of our tests should still be passing.
The last thing that needs to be changed is the show
method. Since the code inside it will be called for edit
and delete
actions (if we ever choose to implement them), it's probably a good idea to put it inside a private method called set_post
.
We also want this method set_post
to run only before the show
method, and not before other methods like new
and create
, so we'll add a before_action
call right at the top of the controller:
# app/controllers/posts_controller.rb class PostsController < ApplicationController before_action :set_post, only: [:show] def index end def new @post = Post.new end def create @post = Post.new(post_params) if @post.save redirect_to @post, notice: 'Your post was created successfully' else render :new end end def show end private def post_params params.require(:post).permit(:date, :rationale) end def set_post @post = Post.find(params[:id]) end end
If you run rspec
you'll see that all the tests are still passing, so this has been a successful refactor.