Skip to content →

Modeling More Complex Datasets In Rails

Let’s say your company manages books. And not like account records, but perhaps books in a store, or a catalog of books available to check out.

Books present a more complicated data model because there are so many of them! And there are many attributes that you might want to track, starting with the title and author, and moving into important but obscure items like ISBN, Dewey Decimal Number, and binding type. Let’s design a system that can handle a small number of books, but scales as our library grows.

I’m going to create a new rails project called BookData, and then I’ll create a Book model that we’ll use throughout this tutorial. You can get the source code here: https://github.com/johnbeatty/book_data_tutorial/

$ rails new BookData --webpack=stimulus
$ cd BookData
$ rails g model Book title:string author:string publisher:string category:string isbn:string dewey_decimal_number:string binding:integer
$ rails db:migrate

We’re going to make binding an enum since there are only a few options, so change book.rb to this:

class Book < ApplicationRecord
  enum binding: [:hardcover, :paperback]
end

In order to test our system with a lot of books, I’m going to use the Faker gem to create about 2000 fake books.

In our Gemfile:

gem 'faker'

Then run

bundle install

Then we’ll create the books in our db/seeds/rb file.

2_000.times do |i|
  Book.create!( title: Faker::Book.title, 
	author: Faker::Book.author, 
	publisher: Faker::Book.publisher,
	category: Faker::Book.genre,
	isbn: "#{Faker::Number.number(3)}-#{Faker::Number.number(1)}-#{Faker::Number.number(2)}-#{Faker::Number.number(6)}-#{Faker::Number.number(1)}",
	dewey_decimal_number: "#{Faker::Number.number(3)}.#{Faker::Number.number(3)}",
	binding: Faker::Number.between(0,1))
  print '.' if i % 100 == 0
end

Now we have a lot of books records that we can use.

Let’s build an index page so that we can look at our books.

We need to update routes.rb:

Rails.application.routes.draw do
  resources :books
end

And we need a app/controllers/books_controller.rb file with an index action, and we’ll start by loading all the books.

class BooksController < ApplicationController
  def index
	@books = Book.all
  end
end

And finally, a view at app/views/books/index.html.erb.

<h1>All Books</h1>

<table>
  <thead>
	<tr>
	  <th>Title</th>
	  <th>Author</th>
	  <th>Publisher</th>
	  <th>Category</th>
	</tr>
  </thead>
  <tbody>
	<% @books.each do |book| %>
	  <tr>
		<td><%= book.title %></td>
		<td><%= book.author %></td>
		<td><%= book.publisher %></td>
		<td><%= book.category %></td>
	  </tr>
	<% end %>
  </tbody>
</table>

Run rails s and visit it in the browser.

I hope this gives you an idea of how you can take a data set with a lot of variation, and model it with just one database table.

Comments or Questions? Find me on twitter @jpbeatty

More To Come

I’m going to work on some more tutorials on how to slice and dice this data in more user friendly ways. Sign up to get the tutorial when it’s ready.

Get the next tutorial when it comes out!

Please enter your email below, and you won’t miss the next Rails Tutorial


Published in ruby on rails Tutorial

2 Comments

Comments are closed, but trackbacks and pingbacks are open.