Adding Overtime Hours to the Post Model with Validations
In this guide, we are going to add another field called hours to our posts database table. This is an important field, since this application's goal is managing overtime hours. I didn't add it earlier because I don't like to add items until I'm ready to use them.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

In this guide, we are going to add another field called hours to our posts database table. This is an important field, since this application's goal is managing overtime hours. I didn't add it earlier because I don't like to add items until I'm ready to use them.

To start open your console and add the hours field with a migration command:

rails g migration add_post_hour_request_to_posts overtime_request:decimal

We are using the decimal data type here because we want users to be able to give partial hours, such as 4.5 hours or 1.5 hours. Now open the migration file, and add a default value of 0.0 since we want the hourly value to always start at 0.0.

# db/migrate/20160726165516_add_post_hour_request_to_posts.rb

class AddPostHourRequestToPosts < ActiveRecord::Migration
  def change
    add_column :posts, :overtime_request, :decimal, default: 0.0
  end
end

Next let's migrate the database with the command:

bundle exec rake db:migrate

Now, I'm going to quickly do a universal search to see where we are using our Post.create method so that we can add in our new hours parameter. In seeds.rb, let's add hours to the list of Post arguments for our test data.

# db/seeds.rb

100.times do |post|
  Post.create!(date: Date.today, rationale: "#{post} rationale content", user_id: @user.id, overtime_request: 2.5)
end

puts "100 Posts have been created"

Next, we are using the create method in our integration tests in several places, let's add the overtime_request field with a value of 3.5 in each spot.

# spec/features/post_spec.rb

# Line 6
let(:post) do
  Post.create(date: Date.today, rationale: "Rationale", user_id: user.id, overtime_request: 3.5)
end

# Line 36
post_from_other_user = Post.create(date: Date.today, rationale: "This post shouldn't be seen", user_id: other_user.id, overtime_request: 3.5)

# Line 60
post_to_delete = Post.create(date: Date.today, rationale: 'asdf', user_id: delete_user.id, overtime_request: 3.5)

# Line 69
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"
    fill_in 'post[overtime_request]', with: 4.5 # Added here

    expect { click_on "Save" }.to change(Post, :count).by(1)
  end

  it 'will have a user associated it' do
    fill_in 'post[date]', with: Date.today
    fill_in 'post[rationale]', with: "User Association"
    fill_in 'post[overtime_request]', with: 4.5 # Added here
    click_on "Save"

    expect(User.last.posts.last.rationale).to eq("User Association")
  end
end

Next, we'll update our post factories. Open posts.rb, and include these fields:

# 

FactoryGirl.define do
  factory :post do
    date Date.today
    rationale "Some Rationale"
    overtime_request 3.5
    user
  end

  factory :second_post, class: "Post" do
    date Date.yesterday
    rationale "Some more content"
    overtime_request 0.5
    user
  end
end

Now, go to post_spec.rb in spec/models and let's see what happens when we add overtime_request, and make it nil.

# spec/models/post_spec.rb

it 'cannot be created without a date, rationale, and overtime_request' do
  @post.date = nil
  @post.rationale = nil
  @post.overtime_request = nil
  expect(@post).to_not be_valid
end

If you run rspec, everything passes. But, it shouldn't pass since our overtime hours can't be nil.

So, let's make this field mandatory by adding it to the list of required fields in the model, like this:

# app/models/post.rb

validates_presence_of :date, :rationale, :overtime_request

Next we need to ensure that our overtime_request is greater than 0.0 since it wouldn't make sense to have an overtime request with no time requested. Let's create another test case that is going to check if our overtime_request is greater than 0.0.

# spec/models/post_spec.rb

it 'has an overtime_request greater than 0.0' do
  @post.overtime_request = 0.0
  expect(@post).to_not be_valid
end

So in this case we're updating the value to 0.0 and we want the post to be rendered invalid.

If you run rspec, t gives a failure, which is what we want.

To implement this feature, go to post.rb to add the validation:

# app/models/post.rb

validates :overtime_request, numericality: { greater_than: 0.0 }

If we test this, it throws an error.

large

However the error isn't with our implementation code. Instead we have an error in the test case "will have a user associated with it.". In the next guide we'll walk through how to clean up the test to get the full suite of tests back to green.

Resources