Implementing Models for a Book Inventory Management System
(Page 1 of 2 )
In this fifth part of a multi-part series on the scaffolding feature of Ruby on Rails, we'll focus on imiplementing the many models we've been creating for our book inventory management system. This article is excerpted from chapter three of the book Practical Rails Projects, written by Eldon Alameda (Apress; ISBN: 1590597818).
Modifying the Generated Models
Now that you understand both the database schema and the way ActiveRecord maps to the schema, let’s modify the generated models.
Adding the has_many Mapping to the Publisher Model
As we just explained, the one-to-many relationship between thePublisherandBookmodel is set up in ActiveRecord by adding thehas_manydeclaration toapp/models/publisher.rb, as highlighted in the following code snippet:
class Publisher < ActiveRecord::Base has_many :books
validates_length_of :name, :in => 2..255 validates_uniqueness_of :name end
This gives you access to, for example, thebooks.empty?method:
Publisher.find_by_name(‘Apress’).books.empty?
In case you are wondering,find_by_nameis a dynamic finder, which dynamically (at run-time) creates a SQL query that returns the Apress publisher, or nil if the publisher is not found.
DYNAMIC FINDERS
Dynamic finders are features of ActiveRecord that allow you to use the ActiveRecord API instead of SQL to find objects. Dynamic finders use the find_by format and are created by ActiveRecord on the fly at runtime when calling the following, for example:
Publisher.find_by_name("Apress")
As another example, you could make this call:
book.find_all_by_title_and_page_count(‘Drinking Tequila for Dummies’, 538)
This dynamically creates a SQL query that finds all books having both the specified title and page count. Dynamic finders can also create a new record if the query returns no results. This is useful for implementing one-liners like this:
Publisher.find_or_create_by_name(‘Apress’)
This example creates the publisher Apress (if it doesn’t already exist) and then returns it.
Adding the belongs_to Mapping to the Book Model
As you learned in the previous section about ActiveRecord mappings, the many-to-one relationship between theBookandPublishermodel is set up with ActiveRecord by usingbelongs_to. Changeapp/models/book.rbas shown here:
class Book < ActiveRecord::Base belongs_to :publisher end
Thebelongs_toallows you to access, for example, the name of the publisher from theBookmodel:
Adding the habtm Mapping to the Book and Author Models
Next, for the many-to-many mapping between the authors and books, add thehas_and_belongs_to_manymapping toapp/models/book.rbas follows:
class Book < ActiveRecord::Base has_and_belongs_to_many :authors belongs_to :publisher end
Note ActiveRecord tries to guess the name of the join table,authors_books, by combining the two table names. In our example, ActiveRecord will look for a table namedauthors_books, notbooks_authors, since the stringauthorscomes beforebookswhen compared in lexical order.
We also want to be able to access the books from the author’s side of the relationship, so changeapp/models/author.rbas follows:
class Author < ActiveRecord::Base has_and_belongs_to_many :books
validates_presence_of :first_name, :last_name
def name "#{first_name} #{last_name}" end end
That takes care of the ActiveRecord mappings, but we also want to make sure only valid books are stored in the database. This can be done with validations, which we introduced in Chapter 2.