Course 2, Quiz 1
I’ve completed the first lesson of Course 2 . In the pre-course, we followed the classic Ruby on Rails ‘Build a Blog’ tutorial, which was great, because I did that back in July, but this time, I could open the files, and understand the Ruby syntax. The tutorial uses Rails generators, which auto-magically build the pages and tables for you. When you run the code, and the files are set up in seconds, it looks impressive, but it isn’t clear to beginners what is happening. By the end of this course, I’ll be able to build a Rails project from scratch, without any gimmicks or shortcuts.
I’ve spent a lot of time going over the Rails guides , the Rails API documentation , and reading blogs and Stack Overflow to deepen my understanding. I read a lot of technical writing and documentation at work, and I’ve learned that the most important thing is to go from an extensive understanding to an intensive understanding. In other words, the first time you go through the documentation, you’re going to be bombarded with information, much of which will not be relevant of perhaps even very easy to digest. But you should get an overall feel of the features and limitations of the product or system. Most imporantly, you should make sure that you can refer to it again, so that when you need that information, you can find it. Unless you have a photographic memory, you’re not going to memorize it all in one reading, or even several.
Frameworks like Rails provide a lot of shortcuts and powerful features for knowledgeable developers, but they can be hard to understand for beginners. Based on some of the questions and discussions I’ve seen online, I think a lot of people dive right into Ruby on Rails, without understanding Ruby. Then, they get lost as they follow along with tutorials that help them automatically generate the files they need, complete with the data they need to get started. It seems like a great convenience, but when it’s time to customize it, it’s suddenly very challenging. That’s where I was back in July. Rails conventions make it so easy, that it seems like magic, but it’s a very logical process of setting up models to manage the data, viewers to display the data in ways that humans can understanding, and controllers that direct the process. In this course, we’re learning to peel back all of the ‘Rails magic’ and learn how each line of code can be used to build powerful applications. The Tealeaf program starts with Ruby, then moves through Sinatra, and then Rails, which has helped me build a foundation for mastering Rails. In the first lesson, we started working on a new project, which I’ll be discussing soon.
I keep my notes, experiments, and source code for each lesson in Emacs Org-Mode files. Org-Mode’s Babel feature is a fantastic implementation of literate programming ; You can write source code, in a variety of languages (hence, the name, “Babel…”), and evaluate the code right inside of the Org-Mode outline file. You can also export (“tangle”) the code into separate files, which can be updated via org-mode! Keeping all my work in an org-mode file makes it convenient to study the code, and track my development. For this course, I’ve started a ‘course2-notes.org’ outline. I took the quiz in my ‘course2-notes.org’ file, and exported the quiz to a Gist, which I’ve embedded into this blog post. While that might seem complicated, it provides me one central location to store all of the content, links, source code, and experiments for each lesson. It’s perfect for reviewing the material, and it’s really simple to implement. After all, it’s all just data…
Here’s the quiz, which I saved a as a gist , and embedded in this post…
* Quiz: Lesson 1
** Question 1
Why do they call it a relational database?
*** Solution 1
Because data is stored and accessed in context, or relation, to other data. Every table has a Primary Key, which is a unique identifier for that row. When that data is inserted into another table, as a Foreign Key, We can form relationships between different data tables, allowing us to select, update, and join data in countless ways.
For example, let's say that we worked at a university, and we were asked if a student had turned in an assignment. We could check the table with all student activity, "ACTIVITY_ACCUMULATOR", but we probably wouldn't understand the data, because user information has been abstracted into UID numbers and keys. But because databases are relational, we can use the information we know to find information that we need.
For example:
**** USERS table
We know the student's User ID is: *buchanana*. So we can use that to get more relevant information:
#+BEGIN_SRC sql
SELECT pk1, user_id, firstname, lastname, row_status, email FROM users WHERE user_id = 'buchanana';
#+END_SRC
And we would get the following:
| PK1 | USER_ID | FIRSTNAME | LASTNAME | ROW_STATUS | EMAIL |
|-------+-----------+-----------+----------+------------+-----------------------|
| 10002 | buchanana | Andrew | Buchanan | 2 | buchanana@example.edu |
**** COURSE_MAIN table
Now, we can check for the PK1 of the course. We know that the ID includes 34789...
#+BEGIN_SRC sql
select * from course_main where course_id like '%34789%';
#+END_SRC
| PK1 | COURSE_ID | COURSE_NAME | DATA_SRC_PK1 |
|--------+---------------------------+------------------+--------------|
| 598851 | ECON101-0012-34789-FS2014 | Economics 101 | 833 |
| 788372 | HIST306-0001-34789-SP2015 | U.S. History 306 | 834 |
We can ignore the first row, because it's the wrong semester. So we know that the =Course Main= table's primary key is '788372'.
Now that we have the primary keys for the user and the course, we can check the user's activity.
**** ACTIVITY_ACCUMULATOR table
And we can see that the user submitted an assignment in that class on March 3, 2015, at 2:03PM.
| PK1 | COURSE_MAIN_PK1 | USERS_PK1 | COURSE_CONTENT_PK1 | DATA | TIMESTAMP |
|--------+-----------------+-----------+--------------------+-----------------------------------+-----------------|
| 873737 | 788372 | 10002 | 83712682 | Assignments/assignment_submit.jsp | 03-MAR-15 14:03 |
| | | | | | |
We could do a few things to combine the steps, and also narrow down our search, but even this simple example shows the power of manipulating data in relational databases.
** Question 2
What is SQL?
*** Solution 2
SQL, or Structured Query Language, is a declarative language that allows us to work with relational databases. Common declarations include:
1. SELECT
2. UPDATE
3. COMMIT
4. JOIN
5. UNION
6. ADD TABLE
7. DROP TABLE
8. INSERT
(In my job, I'm not a DBA, but I do have some do basic database operations. I use the first three daily, 4 and 5 occasionally, and the others almost never.)
** Question 3
There are two predominant views into a relational database. What are they, and how are they different?
*** Solution 3
1. *Schema:* Provides a 'bird's eye view' of the structure of the database, including the column and row names, constraints, and data types.
2. *View:* Provides a live view of the data in a table layout, like a spreadsheet.
** Question 4
In a table, what do we call the column that serves as the main identifier for a row of data? We're looking for the general database term, not the column name.
*** Solution 4
The *primary key* is the main identifier for a row of data in a database table.
** Question 5
What is a foreign key, and how is it used?
*** Solution 5
A foreign key in one table is a primary key from another table; it's used to join the data from multiple tables. (e.g., The =USERS.USER_PK1= primary key will always refer to the same user; if that value is associated with data in another table, that data will then be available to query/edit, just as if it were in the =USERS= table.)
** Question 6
At a high level, describe the ActiveRecord pattern. This has nothing to do with Rails, but the actual pattern that ActiveRecord uses to perform its ORM duties.
*** Solution 6
ActiveRecord is a way of accessing databases without SQL (in the Rails implementation, we can just use Ruby).
- DB Tables = Classes
- DB Rows = Objects
** Question 7
If there's an ActiveRecord model called "CrazyMonkey", what should the table name be?
*** Solution 7
I think it should be =crazy_monkeys=. Fortunately, I can open up the Rails console and check, using the =.tableize= method:
#+BEGIN_SRC sh
小A曰:rails console
Loading development environment (Rails 4.2.0)
irb(main):001:0> "CrazyMonkey".tableize
=> "crazy_monkeys"
#+END_SRC
Looks like I was right. :)
** Question 8
If I'm building a 1:M association between =Project= and =Issue=, what will the model associations and foreign key be?
*** Solution 8
#+BEGIN_SRC ruby
class Project < ActiveRecord::Base
has_many: :issues
end
#+END_SRC
#+BEGIN_SRC ruby
class Issue < ActiveRecord::Base
belongs_to: :project
end
#+END_SRC
** Question 9
Given this code =class Zoo < ActiveRecord::Base has_many :animals end=
- What do you expect the other model to be and what does database schema look like?
- What are the methods that are now available to a zoo to call related to animals?
- How do I create an animal called "jumpster" in a zoo called "San Diego Zoo"?
*** Solution 9
1) The other table should look like this:
#+BEGIN_SRC ruby
class Animal
:belongs_to :zoo
end
#+END_SRC
Because the =Zoo= class includes the =has_many :animals= association, we know that =Animal= will include =belongs_to :zoo=.
Besides all of the inherited methods from =ActiveRecord= and any methods declared within the =Zoo= class, =Zoo= will be able to access =zoo.animal=, as well as =zoo.animal.first=, =zoo.animal.last=, etc.
To create an animal called "jumpster' in a zoo called "San Diego," you'd need to create the objects:
1. In the terminal, make sure that you are in Rails Console, or navigate to the correct directory and start the Rails Console.
2. Enter the following Command to create a row for a new 'Zoo' object, 'San Diego Zoo', in the database:
#+BEGIN_SRC ruby
irb(main):019:0> zoo = Zoo.create(name: 'San Diego Zoo')
#+END_SRC
3. Enter the following command to create a row for a new 'Animal' object, 'Jumpster', in the database:
#+BEGIN_SRC ruby
irb(main):020:0> Animal.create(name: 'jumpster', zoo: zoo)
#+END_SRC
** Question 10
What is mass assignment? What's the non-mass assignment way of setting values?
*** Solution 10
Mass assignment is a convenience, which allows us to assign all of the values in a single operation. For example:
#+BEGIN_SRC ruby
irb(main):021:0> user = User.new({username: 'carmichaelc', firstname: 'Chuck', lastname: 'Bartowski'})
# Note that we can omit the '{}' (and also use hash rockets to set values):
irb(main):021:0> user = User.new(username => 'carmichaelc', firstname => 'Chuck', lastname => 'Bartowski')
#+END_SRC
Without mass assignment, we'd need to set up each value separately, like this:
#+BEGIN_SRC ruby
irb(main):021:0> user = User.new user.username = 'carmichaelc' user.firstname = 'Chuck' user.lastname = 'Bartowki'
#+END_SRC
** Question 11
What does this code do? =Animal.first=
*** Solution 11
It will return the first row (remember that a row == an object...) from the =Animal= table.
** Question 12
If I have a table called "animals" with columns called "name", and a model called Animal, how do I instantiate an animal object with name set to "Joe". Which methods makes sure it saves to the database?
*** Solution 12
You can use the =.new= method, just like with Ruby, but that object will not be persistent. To save it to the database, you'll also have to call the =.save= method. For example:
#+BEGIN_SRC ruby
irb(main):025:0> animal = Animal.new(name: 'Joe')
irb(main):026:0> animal.save
#+END_SRC
Or you can use =.create= method, from Rails, to instantiate an object and save it to the database, in one operation:
#+BEGIN_SRC ruby
irb(main):025:0> animal = Animal.create(name: 'Joe')
#+END_SRC
** Question 13
How does a M:M association work at the database level?
*** Solution 13
- Table *users* has a 1:M association with the JOIN table, *memberships*.
- Table *organizations* has a 1:M association with the JOIN table, *memberships*.
- Table *memberships* belongs to both *users* and *organizations*, and provides a means for joining the other tables.
Consider these very simple models:
#+BEGIN_SRC ruby
class User < ActiveRecord::Base
has_many :memberships
has_many :organizations, through :memberships
end
class Membership < ActiveRecord::Base
belongs_to :users
belongs_to :organizations
end
class Organization < ActiveRecord::Base
has_many :memberships
has_many :users, through :memberships
end
#+END_SRC
**** Users
| ID | USERNAME | FIRSTNAME | LASTNAME | EMAIL |
|-----+----------+-----------+----------+---------------------|
| 111 | smithj | John | Smith | smithj@example.com |
| 112 | jensenc | Carol | Jensen | jensenc@example.com |
**** Memberships
| ID | USER_ID | ORGANIZATION_ID | ROLE | ROW_STATUS |
|----+---------+-----------------+------+------------|
| 1 | 111 | 54 | L | 0 |
| 2 | 112 | 54 | M | 2 |
**** Organizations
| ID | ORGANIZATION NAME | Category |
|----+---------------------+----------|
| 54 | Pocahontas Fan Club | History |
Looking at the the information in the database, we can see that John Smith is the Leader of the 'Pocahontas Fan Club', and that Carol Jensen is a Member. Also, her 'ROW_STATUS' is different, so we'll need to check the schema to find out what that means.
ActiveRecord provides a powerful way to add, edit, and remove data from the database, without needing to worry about different SQL syntax styles, directly from within Rails. The database provides a way to easily verify the data, and it also allows Rails developers to work with Database Administrators and programmers more familiar with SQL.
** Question 14
What are the two ways to support a M:M association at the ActiveRecord model level? Pros and cons of each approach?
*** Solution 14
There are two ways to support a M:M association with ActiveRecord:
1. =has_and_belongs_to_many=: The main advantage is that it doesn't require a JOIN table, because it can make the M:M association directly between two tables.
2. =has many :through=: requires a JOIN table and a JOIN model, but because we have a JOIN table, we can add more attributes to the association, so that it can store more data, making it a much more flexible option.
Going forward, =has_many :through= is the recommended method for creating ActiveRecord associations, because =has_and_belongs_to_many= will be deprecated in the future.
** Question 15
Suppose we have a User model and a Group model, and we have a M:M association all set up. How do we associate the two?
*** Solution 15
We can create a =USER_GROUP= model, and a =user_groups= table.
#+BEGIN_SRC ruby
class User < ActiveRecord::Base
has_many :user_groups, foreign_key: :user_id
has many :groups, through: :user_groups
end
class UserGroup < ActiveRecord::Base
belongs_to :user, foreign_key: :user_id
belongs_to :group, foreign_key: :group_id
end
class Group < ActiveRecord::Base
has_many :user_groups, foreign_key: :group_id
has_many :users, through: :user_groups
end
#+END_SRC
If you enjoyed this post, you might want to subscribe , so you don't miss the next one!