Creating a New Model Class to Associate With
In this demonstration, we will lay the groundwork for the upcoming association demos by creating a new class of model objects, Quiz
, to which McQuestion
model objects will belong. The tasks in this demo are for the most part repeats of the ones covered in the previous demos, so we will tend to be brief in our explanations of the tasks. We will continue to build upon the QuizMe project from the previous demos.
In particular, we will be updating our model design by adding a new model class, Quiz
, as depicted in Figure 1.
To enable users to perform CRUD operations on Quiz
records, we will add the standard Rails resource pages and actions (index
, show
, new
/create
, edit
/update
, and destroy
), as depicted in Figures 2–5.
1. Creating the Quiz
Model Class
The tasks in this part were previously introduced in this demo.
Generate the Quiz
model class along with a corresponding database migration, like this:
rails g model Quiz title:string description:text
Run the newly generated migration to update the database schema by running the following command:
rails db:migrate
Verify that the database schema was updated correctly by using pgAdmin to inspect the quizzes
database table. The table should have no rows of data, but the table should be present, and the columns should be correct.
2. Adding and Testing Valid Fixtures for the Quiz
Model Class
The tasks in this part were previously introduced in this demo.
In test/fixtures/quizzes.yml
, add a valid test fixture for the Quiz
model, like this:
one:
title: Rails Concepts
description: This quiz covers basic Rails programming concepts.
Note that we forgo making a second fixture (two
) this time, because we do not anticipate needing a second one for any of our tests.
In test/models/quiz_test.rb
, add a test for all the Quiz
fixtures to verify that they are all valid, like this:
test "fixtures are valid" do
quizzes.each do |q|
assert q.valid?, q.errors.full_messages.inspect
end
end
Confirm that the tests work and are passing by running the following command:
rails test
We should see 0 failures
and 0 errors
. If we do see failures or errors, then there is a bug in the code that needs fixing.
3. Adding and Testing presence
Validations for the Quiz
Model Class
The tasks in this part were previously introduced in this demo.
In the Quiz
model class, add presence
validations for title
and description
, like this:
validates :title, presence: true
validates :description, presence: true
In test/models/quiz_test.rb
, add tests to verify that title
and description
must be present (not nil
and not a blank string) in order for a Quiz
object to be valid, like this:
test "title presence not valid" do
q = quizzes(:one)
q.title = nil
assert_not q.valid?
q.title = ""
assert_not q.valid?
end
test "description presence not valid" do
q = quizzes(:one)
q.description = nil
assert_not q.valid?
q.description = ""
assert_not q.valid?
end
Confirm that the tests work and are passing by running the following command:
rails test
We should see 0 failures
and 0 errors
. If we do see failures or errors, then there is a bug in the code that needs fixing.
4. Seeding the Database with Quiz
Records
The tasks in this part were previously introduced in this demo.
Add a couple of Quiz
seeds at the top of the seeds.rb
file, like this:
quiz1 = Quiz.create!(
title: 'MVC Concepts',
description: 'This quiz covers concepts related to the Model-View-Controller web application architecture.'
)
quiz2 = Quiz.create!(
title: 'Rails Concepts',
description: 'This quiz covers concepts related to web application development using the Ruby on Rails platform.'
)
Reset and seed the database using the following command:
rails db:migrate:reset db:seed
Verify that the data was seeded correctly by using pgAdmin to inspect the quizzes
database table.
5. Creating a Controller for Quiz
Records
The tasks in this part were previously introduced in this demo.
Create a QuizzesController
by entering this command:
rails g controller Quizzes
6. Adding the index
Resource Action for Quiz
Records
The tasks in this part were previously introduced in this demo.
Create the standard RESTful route for index
for the Quiz
model class by adding the following code to the routes.rb
file:
get 'quizzes', to: 'quizzes#index', as: 'quizzes' # index
Add the index
controller action by inserting a new index
method in the QuizzesController
class, like this:
def index
# get all quiz objects
quizzes = Quiz.all
# display index view
respond_to do |format|
format.html { render :index, locals: { quizzes: quizzes } }
end
end
Create a new index
view in app/views/quizzes/index.html.erb
, like this:
<h1>Quizzes</h1>
<% quizzes.each do |quiz| %>
<div id="<%= dom_id(quiz) %>">
<br>
<p>
<%= quiz.title %>
</p>
<p>
<%= truncate quiz.description, length: 75, separator: ' ' %>
</p>
</div>
<% end %>
Note that the truncate
method is a handy way to shorten a long string when we want only a brief summary. In particular, the method will return the first length
characters of a string followed by an ellipsis (“...
”).
Add a link to the index
page for Quiz
on the app’s home page by inserting a call to the link_to
helper above the “About
” and “Contact
” links in the welcome.html.erb
view, like this:
<p><%= link_to "Quizzes", quizzes_path %></p>
Verify that the newly added code works by running the app, opening the app’s home page, and using the new hyperlink to navigate to the index
page for Quiz
records.
7. Adding the show
Resource Action for Quiz
Records
The tasks in this part were previously introduced in this demo.
Create the standard RESTful route for show
for the Quiz
model class by inserting the following code after the index
route the routes.rb
file:
get 'quizzes/:id', to: 'quizzes#show', as: 'quiz' # show
Add the show
controller action by inserting a new show
method in the QuizzesController
class, like this:
def show
# find a particular object
quiz = Quiz.find(params[:id])
# display the object
respond_to do |format|
format.html { render :show, locals: { quiz: quiz } }
end
end
Create a new show
view in app/views/quizzes/show.html.erb
, like this:
<h1><%= quiz.title %></h1>
<p>
<%= quiz.description %>
</p>
Add links to the show
pages for Quiz
records on the index
page for Quiz
records by inserting a call to the link_to
helper after the quiz title in the index.html.erb
view, like this:
<p>
<%= quiz.title %>
<%= link_to '🔎', quiz_path(quiz) %>
</p>
Verify that the newly added code works by running the app, opening the app’s index
page for Quiz
records, and using the new hyperlinks to navigate to the show
pages for Quiz
records.
8. Adding the new
/create
Resource Actions for Quiz
Records
The tasks in this part were previously introduced in this demo.
Create the standard RESTful routes for new
/create
for the Quiz
model class by inserting the following code after the index
route (but before the show
route) for Quiz
in the routes.rb
file:
get 'quizzes/new', to: 'quizzes#new', as: 'new_quiz' # new
post 'quizzes', to: 'quizzes#create' # create
Add the new
/create
controller actions by inserting a new new
method and a new create
method in the QuizzesController
class, like this:
def new
# make empty quiz object
quiz = Quiz.new
# display new view
respond_to do |format|
format.html { render :new, locals: { quiz: quiz } }
end
end
def create
# new object from params
quiz = Quiz.new(params.require(:quiz).permit(:title, :description))
# respond_to block
respond_to do |format|
format.html do
if quiz.save
# success message
flash[:success] = "Quiz saved successfully"
# redirect to index
redirect_to quizzes_url
else
# error message
flash.now[:error] = "Error: Quiz could not be saved"
# render new
render :new, locals: { quiz: quiz }
end
end
end
end
Create a new new
view in app/views/quizzes/new.html.erb
, like this:
<h1>New Quiz</h1>
<%= form_with model: quiz, url: quizzes_path, method: :post, local: true, scope: :quiz do |form| %>
<div>
<%= form.label :title %><br>
<%= form.text_field :title %>
</div>
<div>
<%= form.label :description %><br>
<%= form.text_area :description, size: "27x7" %>
</div>
<%= form.submit "Add Quiz" %>
<% end %>
Add a link to the new
form page for Quiz
records on the index
page for Quiz
records by inserting a call to the link_to
helper after the h1
heading element in the index.html.erb
view, like this:
<p>
<%= link_to 'New Quiz', new_quiz_path %>
</p>
Verify that the newly added code works by running the app, opening the app’s index
page for Quiz
records, using the new hyperlink to navigate to the new
form pages for Quiz
records, and using the form to create some new Quiz
records.
9. Adding the edit
/update
Resource Actions for Quiz
Records
The tasks in this part were previously introduced in this demo.
Create the standard RESTful routes for edit
/update
for the Quiz
model class by inserting the following code after the show
route for Quiz
in the routes.rb
file:
get 'quizzes/:id/edit', to: 'quizzes#edit', as: 'edit_quiz' # edit
put 'quizzes/:id', to: 'quizzes#update' # update (put)
patch 'quizzes/:id', to: 'quizzes#update' # update (patch)
Add the edit
/update
controller actions by inserting a new edit
method and a new update
method in the QuizzesController
class, like this:
def edit
# object to use in form
quiz = Quiz.find(params[:id])
respond_to do |format|
format.html { render :edit, locals: { quiz: quiz } }
end
end
def update
# load existing object again from URL param
quiz = Quiz.find(params[:id])
# respond_to block
respond_to do |format|
format.html do
if quiz.update(params.require(:quiz).permit(:title, :description))
# success message
flash[:success] = 'Quiz updated successfully'
# redirect to index
redirect_to quizzes_url
else
# error message
flash.now[:error] = 'Error: Quiz could not be updated'
# render edit
render :edit, locals: { quiz: quiz }
end
end
end
end
Create a new edit
view in app/views/quizzes/edit.html.erb
, like this:
<h1>Edit Quiz</h1>
<%= form_with model: quiz, url: quiz_path, method: :patch, local: true, scope: :quiz do |form| %>
<div>
<%= form.label :title %><br>
<%= form.text_field :title %>
</div>
<div>
<%= form.label :description %><br>
<%= form.text_area :description, size: "27x7" %>
</div>
<%= form.submit "Update Quiz" %>
<% end %>
Add links to the edit
form pages for Quiz
records on the index
page for Quiz
records by inserting a call to the link_to
helper after the quiz title in the index.html.erb
view, like this:
<p>
<%= quiz.title %>
<%= link_to '🔎', quiz_path(quiz) %>
<%= link_to '🖋', edit_quiz_path(quiz) %>
</p>
Verify that the newly added code works by running the app, opening the app’s index
page for Quiz
records, using the new hyperlink to navigate to the edit
form pages for Quiz
records, and using the form to update some existing Quiz
records.
10. Adding the destroy
Resource Action for Quiz
Records
The tasks in this part were previously introduced in this demo.
Create the standard RESTful route for destroy
for the Quiz
model class by inserting the following code after the update
actions in the routes.rb
file:
delete 'quizzes/:id', to: 'quizzes#destroy' # destroy
Add the destroy
controller action by inserting a new destroy
method in the QuizzesController
class, like this:
def destroy
# load existing object again from URL param
quiz = Quiz.find(params[:id])
# destroy object
quiz.destroy
# respond_to block
respond_to do |format|
format.html do
# success message
flash[:success] = 'Quiz removed successfully'
# redirect to index
redirect_to quizzes_url
end
end
end
Add links to the destroy
actions for Quiz
records on the index
page for Quiz
records by inserting a call to the link_to
helper after the quiz title in the index.html.erb
view, like this:
<p>
<%= quiz.title %>
<%= link_to '🔎', quiz_path(quiz) %>
<%= link_to '🖋', edit_quiz_path(quiz) %>
<%= link_to '🗑', quiz_path(quiz), method: :delete %>
</p>
Verify that the newly added code works by running the app, opening the app’s index
page for Quiz
records, and using the new hyperlink to delete some existing Quiz
records.
We now have a working Quiz
model class and CRUD resource pages. In the next demo, we will make the application more interesting by giving each Quiz
object an associated set of McQuestion
model objects.