Refactoring the Post Creation Process in a Rails App
Now that our code is working fine, it's time to ensure that it follows Rails best practices.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

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.

Resources