Jekyll2018-10-10T16:15:43+00:00https://pfoplabs.daraghbyrne.me//Programming for Online Prototypes LabsA series of guides, tutorials and labs to accompany CMU's Programming for Online Prototypes course (49-714); a hands-on introduction to building online products and services through code.Daragh Byrnedaragh at cmu dot eduSeeding Data2018-10-09T00:00:00+00:002018-10-09T00:00:00+00:00https://pfoplabs.daraghbyrne.me//7-databases/9-creating-seed-data<p>Sometimes, when we’re working with out database and testing out applications, it would be great to have some ‘dummy’ data added or some required recorded added to try stuff out.</p>
<p>ActiveRecord makes this pretty easy. To add initial data after a database is created, it has a built-in ‘seeds’ feature. It’s a quick way to feed in default values or quickly make a fresh installation on another server or computer. It’s also really useful if you’re reloading the database from your local machine to a deployment/live environment.</p>
<p>To use this feature, just create a file in your <code class="highlighter-rouge">db</code> folder called <code class="highlighter-rouge">seeds.rb</code> and add some ruby code to create/add/edit/delete records.</p>
<p>For example this is a good template</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># delete anything that already exists
Task.delete_all
# reset the primary ids to start at 1
# when the next item is inserted/created
Task.reset_autoincrement
# create a bunch of data to test with
Task.create!([{ name: "Example task", list_id: 1 } ])
Task.create!([{ name: "Example 2", list_id: 1 } ])
Task.create!([{ name: "Example 3", list_id: 2 } ])
Task.create!([{ name: "Example 4", list_id: 1 } ])
</code></pre></div></div>
<p>Once the file is created, pop open a terminal window and type:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rake db:seed
</code></pre></div></div>
<h2 id="find-out-more">Find out more</h2>
<p><a href="http://edgeguides.rubyonrails.org/active_record_migrations.html#migrations-and-seed-data">Migrations and Seed Data</a></p>Daragh Byrnedaragh at cmu dot eduSometimes, when we’re working with out database and testing out applications, it would be great to have some ‘dummy’ data added or some required recorded added to try stuff out.Validating Models2018-10-08T00:00:00+00:002018-10-08T00:00:00+00:00https://pfoplabs.daraghbyrne.me//7-databases/8-validating-models<p>Models are great. In addition to quickly scaffolding out connections to our database, we can also do lots more with them. One thing that we can do (and it’s really useful) is to add validations to our models.</p>
<h2 id="why-do-we-need-validations">Why do we need validations</h2>
<p>Imagine you’re adding information to our database, we’re adding a task. Before we actually create a record, we’ll want to make sure our data is what we’re expecting. For example, we’ll want to check</p>
<ul>
<li>If we’re adding a name or a description that’s required, we might want to check it’s present, not blank and meets a minimum number of characters</li>
<li>If we have a field for year, we’ll set it up as an integer column. But that’ll let us add a number from zero to a million or even a negative number. With a validation, we could check its within a range of 1990 - 2016 for example.</li>
<li>If we have a field that’s a url or an email or has a specific format the data should be in, we can check that too.</li>
</ul>
<h2 id="checking-required-fields-are-filled">Checking required fields are filled</h2>
<p>We can use <code class="highlighter-rouge">validates_presence_of</code> to check that a required field has been added to our model before we create it or save any changes to it.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> validates_presence_of :name
validates_presence_of :list_id
</code></pre></div></div>
<h2 id="checking-string-length">Checking string length</h2>
<p>We can check for the length of a string too. It provides a variety of options, so you can specify length constraints in different ways:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> validates :name, length: { minimum: 2 }
validates :bio, length: { maximum: 500 }
validates :password, length: { in: 6..20 }
validates :registration_number, length: { is: 6 }
</code></pre></div></div>
<h2 id="checking-uniqueness">Checking uniqueness</h2>
<p>If we had a user table and we wanted to make sure that each account was linked to one unique email we could do the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> validates :email, uniqueness: true
</code></pre></div></div>
<h2 id="checking-number-ranges">Checking number ranges</h2>
<p>If we wanted to check that the year was in a valid range, we could do something like</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>validates :year, :numericality => { :greater_than => 1970, :less_than_or_equal_to => 2016 }
</code></pre></div></div>
<p>or we could also do</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>validates :year, :inclusion => { :in => 1990..2020 }
validates :age, :inclusion => { :in => 1..100 }
</code></pre></div></div>
<h2 id="checking-validations">Checking validations</h2>
<p>After you create or save an record you can use the <code class="highlighter-rouge">valid</code> method to see if any validations failed.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>task = Task.create(name: "My Task")
task.valid? # => true
task = Task.create(name: nil)
task.valid? # => false
</code></pre></div></div>
<p>ActiveRecord also create some really nice human readable error messages for you by default if there’s any validations that fail. You can check them like so:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>task.errors.messages
# => {name:["can't be blank"]}
</code></pre></div></div>
<h2 id="but-why">But why?</h2>
<p>Validations are the only way to ensure <em>integrity of your data</em>. If you’re adding forms or allowing anyone to pass data to your application, you need to make sure that only the right kinds of information gets in. It prevents errors and/or people hacking bad info into your database. And no one wants that, so you should make sure you apply validations to every model you create!</p>
<h2 id="find-out-more">Find out more</h2>
<ul>
<li><a href="http://guides.rubyonrails.org/active_record_validations.html">Active Record Validations</a></li>
<li><a href="http://guides.rubyonrails.org/v3.2.13/active_record_validations_callbacks.html">Active Record Validations and Callbacks</a></li>
<li><a href="http://api.rubyonrails.org/classes/ActiveRecord/Validations.html">Documentation - Active Record Validations</a></li>
</ul>Daragh Byrnedaragh at cmu dot eduModels are great. In addition to quickly scaffolding out connections to our database, we can also do lots more with them. One thing that we can do (and it’s really useful) is to add validations to our models.Deploying with a Database2018-10-08T00:00:00+00:002018-10-08T00:00:00+00:00https://pfoplabs.daraghbyrne.me//7-databases/12-deploying-to-heroku<p><em>Full credit: Much of this is adapted <a href="https://devcenter.heroku.com/articles/getting-started-with-ruby">from the Heroku guide</a>, but set up to show you how to transition a local project into a heroku deployable project.</em></p>
<h2 id="connecting-your-heroku-app-to-a-database">Connecting your Heroku app to a database</h2>
<p>Heroku provides production grade <a href="https://elements.heroku.com/addons/heroku-postgresql">PostgreSQL</a> databases as a service.</p>
<h2 id="provision-the-postgres-add-on">Provision the Postgres Add-on</h2>
<p>Add-ons are third-party cloud services that provide out-of-the-box additional services for your application, from persistence through logging to monitoring and more. By default, Heroku stores 1500 lines of logs from your application. However, it makes the full log stream available as a service - and several add-on providers have written logging services that provide things such as log persistence, search, and email and SMS alerts.</p>
<p>In this step you will provision one of these logging add-ons, to set up a postgres database. To add one, type this in the terminal window</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>heroku addons:create heroku-postgresql
</code></pre></div></div>
<p>You’ll see a confirmation like this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Database has been created and is available
! This database is empty. If upgrading, you can transfer
! data from another database with pg:copy
Created postgresql-convex-90661 as HEROKU_POSTGRESQL_GREEN_URL
Use heroku addons:docs heroku-postgresql to view documentation
</code></pre></div></div>
<p>The add-on is now deployed and configured for your application. You can list add-ons for your app like so:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>heroku addons
</code></pre></div></div>
<p>Listing the config vars for your app will display the URL that your app is using to connect to the database, DATABASE_URL:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>heroku config
</code></pre></div></div>
<p>and you’ll see</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== polar-inlet-4930 Config Vars
DATABASE_URL: postgres://xx:yyy@host:5432/d8slm9t7b5mjnd
HEROKU_POSTGRESQL_GREEN_URL: postgres://xx:yyy@host:5432/d8slm9t7b5mjnd
…
</code></pre></div></div>
<p>Heroku also provides a <code class="highlighter-rouge">pg</code> (postgres) command that shows a lot more:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>heroku pg
</code></pre></div></div>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>=== HEROKU_POSTGRESQL_GREEN_URL (DATABASE_URL)
Plan: Hobby-dev
Status: Available
Connections: 0
PG Version: 9.3.3
Created: 2014-07-07 11:30 UTC
Data Size: 6.6 MB
Tables: 2
Rows: 1/10000 (In compliance)
Fork/Follow: Unsupported
Rollback: Unsupported
This indicates I have a hobby database (free), running Postgres 9.3.3, with a single row of data.
</code></pre></div></div>
<h2 id="deploy-and-set-up-the-database">Deploy and set up the database</h2>
<p>Add the changes to the git repo and push to Heroku:</p>
<ol>
<li>
<p>Open GitHub Desktop and commit any new changes (type a name for the commit, and press ‘Commit to Master’, then <code class="highlighter-rouge">Sync</code> on the top right )</p>
</li>
<li>
<p>Once it’s synced, return to the Terminal/Command Prompt window and type the following to deploy your code:</p>
</li>
</ol>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> git push heroku master
</code></pre></div></div>
<p>Now we’ve got our code there, we’ll need to actually set up our database</p>
<p>If you have migrations, you can run them like so:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>heroku run rake db:migrate
</code></pre></div></div>
<p>If you have a seed file, you can add data to your database like so:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>heroku run rake db:seed
</code></pre></div></div>
<p>And, you can also interact directly with the database if you have Postgres installed locally. For example, here’s how to connect to the database using psql and execute a query:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>heroku pg:psql
</code></pre></div></div>
<p>Then you can type in SQL queries to view, insert, delete or update records:</p>
<pre><code class="language-``">d8slm9t7b5mjnd=> select * from widgets;
id | name | description | stock | created_at | updated_at
----+-----------+--------------+-------+----------------------------+----------------------------
1 | My Widget | It's amazing | 100 | 2014-07-08 15:05:13.330566 | 2014-07-08 15:05:13.330566
(1 row)
</code></pre>
<h2 id="all-done">All done</h2>
<p>If you’ve followed these steps, you’ve hopefully got a working project on Heroku!</p>
<p>Type:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>heroku open
</code></pre></div></div>
<p>to see the live application and interact with it.</p>Daragh Byrnedaragh at cmu dot eduFull credit: Much of this is adapted from the Heroku guide, but set up to show you how to transition a local project into a heroku deployable project.Adding Associations2018-10-08T00:00:00+00:002018-10-08T00:00:00+00:00https://pfoplabs.daraghbyrne.me//7-databases/11-crud-2<p>We’ve got our basic Task Model up and running. It’s in the database and we can add, remove, and view data associated with it through the API.</p>
<p>But that’s only half of an application. Imagine we want to add our task to a list? Or if we have multiple users in our application how can we associate it with them?</p>
<p>That’s where ActiveRecord associations come in. With it we can make links between our models.</p>
<h2 id="lets-add-a-list">Let’s add a list</h2>
<p>We want to associate a Task with a list…great. Let’s create an association. But first we’ve got to create the table, right?</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rake db:create_migration NAME=create_lists_table
</code></pre></div></div>
<p>Inside of your migration, you’ll find code similar to the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class CreateListsTable < ActiveRecord::Migration
def change
end
end
</code></pre></div></div>
<p>In this code, add a line to setup the table and have a name associated with it.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
class CreateLists < ActiveRecord::Migration[5.0]
def change
create_table :lists do |t|
t.string :name
end
end
end
</code></pre></div></div>
<p>and finally apply the migration with the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rake db:migrate
</code></pre></div></div>
<h2 id="create-a-model-for-it">Create a model for it</h2>
<p>In the <code class="highlighter-rouge">models</code> folder, create a new file called list.rb and add the following code inside of it:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
class List < ActiveRecord::Base
validates_presence_of :name
end
</code></pre></div></div>
<p>THen we need to include the model in our application by adding it to the main file. Add the following line to your <code class="highlighter-rouge">app.rb</code></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>require_relative './models/list'
</code></pre></div></div>
<h2 id="setup-a-seed">Setup a seed</h2>
<p>Let’s open up the <code class="highlighter-rouge">db/seed.rb</code> and add some dummy data that we can test with. Add the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>List.delete_all
List.reset_autoincrement
List.create!([{ name: "My First List" } ])
List.create!([{ name: "My Second List" } ])
</code></pre></div></div>
<p>To add this to the database, then type</p>
<p><code class="highlighter-rouge">rake db:seed</code></p>
<h2 id="adding-associations">Adding associations</h2>
<p>Wouldn’t it be great if it knew that tasks and lists were linked? Well activerecord let’s us do exactly this. We need to add one line of code to each model to tell it about the nature of these associations.</p>
<p><strong>Commands:</strong></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
has_many :table_name # this goes in the model that's the parent in the relationship - they have many children i.e lists
belongs_to :table_name # this goes in the model that we want to make the link from i.e. tasks
</code></pre></div></div>
<p>When we write this, ActiveRecord expects there to be a column named something like <code class="highlighter-rouge"><table_name>_id</code>. This stores the ID of the table we want to make the association with.</p>
<p>For example, if tasks belongs to <code class="highlighter-rouge">lists</code>, then <code class="highlighter-rouge">tasks</code> must have a column called <code class="highlighter-rouge">list_id</code>. Then when we want to find a list that’s associated with a task, ActiveRecord will look it up by this id. When we want to find the tasks associated with a list, it’ll do a search for all records/rows that contain the matching id in list_id.</p>
<p>So, let’s make those connections</p>
<p>Open <code class="highlighter-rouge">lists.rb</code> and add:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> has_many :tasks
</code></pre></div></div>
<p>This means that any list can have one or more tasks associated with it. This connection is made from the <code class="highlighter-rouge">id</code> of list that is added to the <code class="highlighter-rouge">list_id</code> column of tasks.</p>
<p>Now add the following to <code class="highlighter-rouge">task.rb</code>.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> belongs_to :list
</code></pre></div></div>
<p>This means it has one and belongs to. It can only have one. Now both have a list and a tasks object associated with them. Great!</p>
<h2 id="adding-endpoints">Adding Endpoints</h2>
<p>It’s pretty much the same as before. We can add the following RESTful methods to <code class="highlighter-rouge">app.rb</code></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
get '/lists' do
List.all.to_json(include: :tasks)
end
get '/lists/:id' do
List.where(id: params['id']).first.to_json(include: :tasks)
end
post '/lists' do
list = List.new(params)
if list.save
list.to_json(include: :tasks)
else
halt 422, list.errors.full_messages.to_json
end
end
put '/lists/:id' do
list = List.where(id: params['id']).first
if list
list.name = params['name'] if params.has_key?('name')
if list.save
list.to_json
else
halt 422, list.errors.full_messages.to_json
end
end
end
delete '/lists/:id' do
list = List.where(id: params['id'])
if list.destroy_all
{success: "ok"}.to_json
else
halt 500
end
end
</code></pre></div></div>
<p>Spot the difference. Did you notice this <code class="highlighter-rouge">to_json(include: :tasks)</code>. Yes. We can add a little bit extra to how JSON writes out our objects and tell it also to include our associations. Neat.</p>
<p>Try them out!!!</p>Daragh Byrnedaragh at cmu dot eduWe’ve got our basic Task Model up and running. It’s in the database and we can add, remove, and view data associated with it through the API.CRUD Basics2018-10-08T00:00:00+00:002018-10-08T00:00:00+00:00https://pfoplabs.daraghbyrne.me//7-databases/10-crud<p>So we’ve got all the basics up and running, now it’s time to hook the models up to routes and let us add, edit, view and delete records from our database.</p>
<p>We’re going to follow the conventions of <em>REST</em> requests and responses/</p>
<h2 id="why-rest">Why REST?</h2>
<p><strong>REST is a convention that structures HTTP requests around data access and manipulations</strong></p>
<p>REST been growing in popularity since 2005, and inspires the design of services, such as the Twitter API. This is due to the fact that REST allows you to interact with minimal overhead with clients as diverse as mobile phones and other websites.</p>
<p>The most important part of REST is the way it maps standard data access and manipulation actions onto URLs and HTTP verbs. This is typically how it works.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /tasks/ -> LIST
POST /tasks/ -> CREATE
GET /tasks/:id -> READ
PUT /tasks/:id -> UPDATE
DELETE /tasks/:id -> DESTROY
</code></pre></div></div>
<p>ActiveRecord is built to support REST and these CRUD (create, read, update, delete) type actions so it’s perfectly in synch with rest.</p>
<h2 id="json">JSON</h2>
<blockquote>
<p>JSON (JavaScript Object Notation) is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML.<a href="http://developers.squarespace.com/what-is-json/">*</a></p>
</blockquote>
<p>Typically for any REST API responses, we’ll use <a href="https://github.com/flori/json">JSON</a> (a nice data format) to send clean object-oriented responses back.</p>
<p>Add JSON to your project’s gem file like this</p>
<p><code class="highlighter-rouge">gem ‘json’</code></p>
<p>Then</p>
<p><code class="highlighter-rouge">bundle install</code></p>
<h2 id="lets-get-going-listing-tasks">Let’s get going: Listing Tasks</h2>
<p>Fire up your project and let’s add a basic route to return a list of all tasks</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>get ‘/tasks' do
Task.all.to_json
end
</code></pre></div></div>
<p>Fire up your local server</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>shotgun config.ru
</code></pre></div></div>
<p>and visit the URL: <code class="highlighter-rouge">http://localhost:9393/tasks</code></p>
<p>You should get a lot of content back. If you’re having trouble reading it, you can use a tool like <a href="http://jsonprettyprint.net">JSON pretty print</a> to help present it better</p>
<h2 id="reading-tasks">Reading Tasks</h2>
<p>To add a read action in the REST/CRUD approach you’ll do the following</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>get '/tasks/:id' do
Task.where(id: params['id']).first.to_json
end
</code></pre></div></div>
<h2 id="creating-a-task">Creating a Task</h2>
<p>To add a create action in the REST/CRUD approach you’ll do the following.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>post '/tasks' do
task = Task.new(params)
if task.save
task.to_json
else
halt 422, task.errors.full_messages.to_json
end
end
</code></pre></div></div>
<p>This lets you send a bunch of parameters through a POST method. The ruby code will create an object based on the params it receives and try to add it to the database.</p>
<p>If all goes well you’ll get that object back as a JSON object. Otherwise it’ll return an error that presents the validation information.</p>
<p>You can’t test a POST method from your browser (a browser will only send a GET request.) Instead we can use <a href="https://curl.haxx.se">cURL</a> to test it. It’s installed by default on OSX but if you’re on Windows you’ll <a href="https://help.zendesk.com/hc/en-us/articles/229136847-Installing-and-using-cURL#install">need to install it first</a>.</p>
<p>Once installed, open a terminal window and type the following at the command prompt:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -X POST -F 'name=test' -F 'list_id=1' http://localhost:9393/tasks
</code></pre></div></div>
<h2 id="updating-a-task">Updating a Task</h2>
<p>To add an update action in the REST/CRUD approach you’ll do the following.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>put '/tasks/:id' do
task = Task.where(id: params['id']).first
if task
task.name = params['name'] if params.has_key?('name')
task.is_completed = params['is_completed'] if params.has_key?('is_completed')
if task.save
task.to_json
else
halt 422, task.errors.full_messages.to_json
end
end
end
</code></pre></div></div>
<p>This requires an named ID parameter (that matches the id primary key in the table). Using this parameter it’ll look up the object in the database and if there’s a match we’ll be able to update it.</p>
<p>Then it’ll look to see if parameters have been passed and if they have the values will be updated.</p>
<p>If all goes well you’ll get that object back as a JSON object. Otherwise it’ll return an error that presents the validation information.</p>
<p>You can’t test a PUT method from your browser either. so we’ll use cURL again:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -X PUT -F 'name=updates' -F 'list_id=1' http://localhost:9393/tasks/1
</code></pre></div></div>
<h2 id="deleting-data">Deleting data</h2>
<p>To add an DELETE action in the REST/CRUD approach you’ll do the following.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>delete '/tasks/:id' do
task = Task.where(id: params['id'])
if task.destroy_all
{success: "ok"}.to_json
else
halt 500
end
end
</code></pre></div></div>
<p>This requires an named ID parameter (that matches the id primary key in the table). Using this parameter it’ll look up and return the object from the database.</p>
<p>If the object (matched by ID exists), it’ll be destroyed and confirmed.</p>
<p>Otherwise it’ll return an error that presents the validation information.</p>
<p>You can’t test a DELETE method from your browser either. so we’ll use cURL again:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -X DELETE http://localhost:9393/tasks/1
</code></pre></div></div>Daragh Byrnedaragh at cmu dot eduSo we’ve got all the basics up and running, now it’s time to hook the models up to routes and let us add, edit, view and delete records from our database.Connecting Tables to ActiveRecord models2018-10-07T00:00:00+00:002018-10-07T00:00:00+00:00https://pfoplabs.daraghbyrne.me//7-databases/7-activerecord-models<p>In ActiveRecord we use a particular type of class or Ruby object to link our SQL database and it’s contents to something we can work with in our Sinatra project. These are known as “models”. Each models maps directly onto a single table in our database and contains all of the functionality we need to access, add or remove data from that table.</p>
<h2 id="about-activerecord-models">About ActiveRecord Models</h2>
<p>Models are part of Active Record’s <em>Object Relational Mapping</em>.</p>
<blockquote>
<p>It’s a technique that connects the rich objects of an application to tables in a relational database management system. Using ORM, the properties and relationships of the objects in an application can be easily stored and retrieved from a database without writing SQL statements directly and with less overall database access code.<a href="http://guides.rubyonrails.org/active_record_basics.html#the-active-record-pattern">*</a></p>
</blockquote>
<p>As this <a href="http://guides.rubyonrails.org/active_record_basics.html#the-active-record-pattern">rails guide explains </a>, Active Record gives us several mechanisms, the most important being the ability to:</p>
<ul>
<li>Represent models and their data.</li>
<li>Represent associations between these models.</li>
<li>Represent inheritance hierarchies through related models.</li>
<li>Validate models before they get persisted to the database.</li>
<li>Perform database operations in an object-oriented fashion.</li>
</ul>
<p>Simply put, models are the glue between the database and ruby. They are a set of classes that represent your data and give you access to standard operations you’ll want to perform on that data.</p>
<h2 id="creating-models">Creating Models</h2>
<p>Now that we have a Task table, need need to set it up as an ActiveRecord model so we can access and add data to it. To access this table from Ruby, you need to have a class that models the database table. ActiveRecord makes this really easy!</p>
<p>First things first! Let’s make sure they’re organized. Create a new folder called <code class="highlighter-rouge">models</code> to hold all of our models in one place.</p>
<p>To add a model, just create a new file called <code class="highlighter-rouge">task.rb</code> and add the following code inside of it:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Task < ActiveRecord::Base
end
</code></pre></div></div>
<p><strong>The fact that <code class="highlighter-rouge">Task</code> is in the singular form is very important.</strong> Table names are plural (“the tasks table”) and model names should be singular (“the Task model”). This convention is what let’s ActiveRecord automatically map data into your models.</p>
<p>Next, we need to add this file to our main application. We do this by requiring it. Just add the following line to your main <code class="highlighter-rouge">app.rb</code> beneath the line where you set your database using the following code:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>require_relative './models/task'
</code></pre></div></div>
<p>That’s all you need to hook it up to data.</p>
<p>Now activerecord will link the model to the SQL table on or behalf. It’ll look up what columns are available from our schema and automagically adds methods to this class for your data. We can do all sorts of things.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
Task.all # Get all of the records in our database
Task.all.each do |task|
#loop over each record
# and write out the id to the command prompt
# note we can access any column using .column_name
puts task.id
# we can assign data to a record
task.name = "New name"
# and we can save that record easily with one line of code
task.save
end
Task.find( id: 1 ) # search for a record based on the id
Task.where( is_complete: true ) # or find those that are completed.
Task.destroy_all # remove all the tasks
</code></pre></div></div>
<p>Neat!</p>
<h2 id="important-naming-conventions-for-models">Important: Naming conventions for Models</h2>
<p>To reiterate the above, here’s a section directly from the ActiveRecord guide</p>
<blockquote>
<p>By default, Active Record uses some naming conventions to find out how the mapping between models and database tables should be created. ActiveRecord will pluralize your class names to find the respective database table. So, for a class <strong>Book</strong>, you should have a database table called <strong>books</strong>. The pluralization mechanisms are very powerful, being capable of pluralizing (and singularizing) both regular and irregular words. When using class names composed of two or more words, the model class name should follow the Ruby conventions, using the CamelCase form, while the table name must contain the words separated by underscores. Examples:</p>
</blockquote>
<ul>
<li>Database Table - Plural with underscores separating words (e.g., <code class="highlighter-rouge">book_clubs</code>).</li>
<li>Model Class - Singular with the first letter of each word capitalized (e.g., <code class="highlighter-rouge">BookClub</code>).</li>
</ul>
<table>
<thead>
<tr>
<th>Model / Class</th>
<th>Table / Schema</th>
</tr>
</thead>
<tbody>
<tr>
<td>Article</td>
<td>articles</td>
</tr>
<tr>
<td>LineItem</td>
<td>line_items</td>
</tr>
<tr>
<td>Deer</td>
<td>deers</td>
</tr>
<tr>
<td>Mouse</td>
<td>mice</td>
</tr>
<tr>
<td>Person</td>
<td>people</td>
</tr>
</tbody>
</table>
<h2 id="read-more">Read more</h2>
<p><a href="http://guides.rubyonrails.org/active_record_basics.html#the-active-record-pattern">Active Record Basics: Creating Active Record Models</a>
<a href="http://guides.rubyonrails.org/active_model_basics.html">Active Model Basics</a></p>Daragh Byrnedaragh at cmu dot eduIn ActiveRecord we use a particular type of class or Ruby object to link our SQL database and it’s contents to something we can work with in our Sinatra project. These are known as “models”. Each models maps directly onto a single table in our database and contains all of the functionality we need to access, add or remove data from that table.Database Schemas2018-10-06T00:00:00+00:002018-10-06T00:00:00+00:00https://pfoplabs.daraghbyrne.me//7-databases/6-schemas<p>Did you notice we also got a new file in our <code class="highlighter-rouge">db</code> directory called <code class="highlighter-rouge">schema.rb</code>. This is a running log of the structure of our database or at least as sinatra sees it. It’s updates every time a new migration is applied to our database. And it’s a really useful resource for seeing where things are at with our SQL database.</p>
<h2 id="what-is-the-schema">What is the schema</h2>
<p>It’s the authoritative source for your database schema. Active Record generates <code class="highlighter-rouge">db/schema.rb</code> by examining the database to represent it’s current state.</p>
<blockquote>
<p>Schema files are useful if you want a quick look at what attributes an Active Record object has. This information is not in the model’s code and is frequently spread across several migrations, but the information is nicely summed up in the schema file. The <a href="https://github.com/ctran/annotate_models">annotate_models</a> gem automatically adds and updates comments at the top of each model summarizing the schema if you desire that functionality.</p>
</blockquote>
<h2 id="what-does-it-look-like">What does it look like</h2>
<p>A schema looks something like this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ActiveRecord::Schema.define(version: 20161101024543) do
create_table "lists", force: :cascade do |t|
t.string "name"
end
create_table "tasks", force: :cascade do |t|
t.string "name"
t.integer "list_id"
t.boolean "is_complete", default: false
end
end
</code></pre></div></div>
<p>You’ll notice that:</p>
<ul>
<li>
<p>The version will match a number from one of your migrations. This tells ActiveRecord if there are migrations that haven’t been applied. And this is also why there can’t be two migrations with the same ID number.</p>
</li>
<li>
<p>Each of the tables are listed and we can see what columns exist for them.</p>
</li>
</ul>
<h2 id="find-out-more">Find out more</h2>
<ul>
<li><a href="http://edgeguides.rubyonrails.org/active_record_migrations.html#schema-dumping-and-you">6 Schema Dumping and You</a></li>
<li><a href="http://api.rubyonrails.org/classes/ActiveRecord/Schema.html">Documentation Active Record Schema</a></li>
</ul>Daragh Byrnedaragh at cmu dot eduDid you notice we also got a new file in our db directory called schema.rb. This is a running log of the structure of our database or at least as sinatra sees it. It’s updates every time a new migration is applied to our database. And it’s a really useful resource for seeing where things are at with our SQL database.Making Migrations2018-10-05T00:00:00+00:002018-10-05T00:00:00+00:00https://pfoplabs.daraghbyrne.me//7-databases/5-migrations<h2 id="what-are-migrations">What are migrations</h2>
<p>Migration files are small Ruby scripts that make changes to your database.</p>
<p>Some examples of cases where a migration is used:
• To create a new table in your database and define the columns it will contain as well as their data types
• To drop a table in your database (completely erase it and all of its data)
• To add a column to an existing table in your database
• To rename a column or table in your database
• To add an index to a database column</p>
<p>Changing a migration file will not make a change to your database until the file is run i.e. with <code class="highlighter-rouge">rake db:migrate</code></p>
<p>Migrations aren’t used to change add or remove data in your database. They’re only used to define the schema or structure of your database. We use them to set up the tables and define the columns that exist.</p>
<p>A migration is basically a set of instructions written in Ruby that define what structure we want to have in our database. Each migration normally contains a version of the database structure. As the structure of our database might change over the course of the project, migrations are like a version history of our database and how its evolved (e.g. migration 1: create our first table, migration 2: add a new column to the table, migration 3: a new table is added, etc.)</p>
<h2 id="creating-a-migration">Creating a migration</h2>
<p>To create a migration, we use rake from the command line:</p>
<p><code class="highlighter-rouge">rake db:create_migration NAME=a_descriptive_name_for_my_migration</code></p>
<p>For example, if I wanted to create a task management tool, I’d need a table to store all of my tasks. To begin, I’d create a migration with a nice name that tells me what I’m about to put in this particular migration (basically to make it easier to find later.) To make a migration that’ll hold the instructions to create my new table I’d do something like this:</p>
<p><code class="highlighter-rouge">rake db:create_migration NAME=create_tasks_table</code></p>
<p>Notice some conventions: <strong>a migration name is all lowercase separated by underscores (“_“)</strong></p>
<p>Also, you should give it a pretty descriptive name. Good practices says you should keep one or two discrete activities to a migration, even if that means creating lots of migrations e.g. create_tablename_table, add_column_name_to_tablename, remove_column_names_from_tablename, etc.</p>
<p>Once the migration has been generated, you can edit the file created. Go to the <code class="highlighter-rouge">/db/migrate</code> folder inside of your project directory (ActiveRecord will create this automagically for you). Migration files are named in the format:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>db/migrations/<date><randomhash>_<migrationname>.rb
</code></pre></div></div>
<p>And inside your migration you’ll find some boilerplate code like this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class CreateTasksTable < ActiveRecord::Migration
def change
end
end
</code></pre></div></div>
<h2 id="creating-a-table-with-migrations">Creating a table with migrations</h2>
<p>Inside of this file, we put a series of activerecord instructions that allow us to define the changes we’d like to make to the database. These go inside the <code class="highlighter-rouge">change</code> method, like so</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class CreateTasks < ActiveRecord::Migration[5.0]
def change
create_table :tasks do |t|
t.string :name
end
end
end
</code></pre></div></div>
<p>This tells activerecord to create a table named tasks in our database and add a column named ‘name’ with a string type. What other types exist, good question! Our columns could also be</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> t.boolean :column_name #a boolean (true or false)
t.integer :column_name #a whole number
t.string :column_name #a text string up to 256 characters long
t.text :column_name # a long text string
t.datetime :column_name # a date time object
t.decimal :column_name # a decimal number
t.float :column_name # a floating point decimal number
</code></pre></div></div>
<h2 id="creating-a-table">Creating a Table</h2>
<p>Remember once again that just because we’ve defined a migration file, it doesn’t mean anything has been done to our database. In order for our changes to take effect, we need to run the database migration command:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rake db:migrate —— creates and adds the migration
</code></pre></div></div>
<p>If your migration ran successfully, you should see something like this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> == CreateTasksTable: migrating ===============================================
-- create_table(:tasks)
-> 0.0009s
== CreateTasksTable: migrated (0.0010s) ======================================
</code></pre></div></div>
<p>At this point, pop open the database in something like Base. If you look at the table structure you’ll notice that it’s created an extra column named <code class="highlighter-rouge">id</code> for you. This is the primary key for the database table and it’s used to uniquely identify all of the records. ActiveRecord knows every table will need this so it sets it up for you by default.</p>
<p>One other great thing active record can do is track when new data is added and modified on our tables. These ‘timestamps’ are super useful, but not included by default. Let’s change the table creation to add them.</p>
<h2 id="uh-oh-we-did-something-wrong">Uh Oh! We did something wrong</h2>
<p>What if you realize you made a mistake? Well thankfully activerecord handles this. You can use a rollback to undo a migration.</p>
<p>If you type:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rake db:rollback
</code></pre></div></div>
<p>Your database will be stepped back one version (one migration). You can do this over and over - if you have multiple migrations to undo.</p>
<p>Open the migration and add the following</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class CreateTasks < ActiveRecord::Migration[5.0]
def change
create_table :tasks do |t|
t.string :name
t.timestamps
end
end
end
</code></pre></div></div>
<p>Apply the changes</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rake db:migrate
</code></pre></div></div>
<p>And voila you’ll have two additional columns <code class="highlighter-rouge">created_at</code> and <code class="highlighter-rouge">updated_at</code> that will be automatically managed by activerecord. It’ll give you timestamps of any new changes to data.</p>
<h2 id="adding-a-new-column">Adding a new column</h2>
<p>As our project grows, we’ll add new migrations creating other tables. What happens if we want to add a new column to our table? We don’t want to have to rollback everything just to do that because we’ll loose all the data we’ve added to our database. Instead we can create a migration just for this action.</p>
<p>Let’s say we want to add a boolean flag to keep tabs on if a task is completed. We’ll need to ads this column in. First we’ll create a new migration</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rake db:create_migration NAME=add_is_complete_to_tasks
</code></pre></div></div>
<p>Notice the descriptive name again! Then we’ll open it up</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class AddIsCompleteToTasks < ActiveRecord::Migration[5.0]
def change
end
end
</code></pre></div></div>
<p>To change a table and add a column to it, activerecord gives us a command called <code class="highlighter-rouge">add_column</code>. It takes the following parameters:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>add_column table_name, column_name, type, options
</code></pre></div></div>
<p>So we can do the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> add_column :tasks, :is_complete, :boolean
</code></pre></div></div>
<p>Basically, we’ve said add a column on the table ‘tasks’ that’s called ‘is_complete’ and is of type ‘boolean’</p>
<p>We can also add an optional parameter called <code class="highlighter-rouge">default</code> that’ll specify the default information to add to any new column</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> add_column :tasks, :is_complete, :boolean, default: false
</code></pre></div></div>
<p>Finally we apply this to the database by using a migration</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rake db:migrate
</code></pre></div></div>
<p>Open up your database to take a look, it should be added now too!</p>
<h2 id="other-actions">Other Actions</h2>
<p>In addition to <code class="highlighter-rouge">create_table</code> and <code class="highlighter-rouge">add_column</code>, there’s two other common actions you might use in your migrations these are:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> remove_column :table_name, :column_name
drop_table :table_name
</code></pre></div></div>
<p>Hopefully these are self-explanatory!</p>
<h2 id="important-notes">Important notes</h2>
<ul>
<li>
<p>If you rollback a create_table migration for a table that has had data inserted into it since you initially ran the migration, <em>you will lose all of your data.</em> Instead, create an entirely new migration file to make the changes you’re looking to make in this case.</p>
</li>
<li>
<p>The dates (the numbers) in your migration have to be unique. These identify the version of the migration and tell Sinatra/ActiveRecord what migrations have been applied to the database. You can’t and shouldn’t just copy and paste these files. <strong>Always use the command line helper with rake to generate a migration</strong></p>
</li>
<li>
<p>If a migration has already been run, it will not be run again unless it has been rolled back</p>
</li>
<li>
<p>There are conventions on how you name your tables</p>
<ul>
<li>The names of your tables should be unique</li>
<li>The names of your tables should be lowercase, without any spaces (use underscores instead)</li>
<li>You should name your tables in the plural i.e. you want a table named <em>tasks</em> not <em>task</em>. <strong>Note</strong> This is really important for how ActiveRecord maps tables and records into ruby later.</li>
</ul>
</li>
</ul>
<h2 id="learn-more">Learn more</h2>
<ul>
<li><a href="http://edgeguides.rubyonrails.org/active_record_migrations.html">Active Record Migrations: Guide</a></li>
<li><a href="http://api.rubyonrails.org/classes/ActiveRecord/Migration.html">Active Record Migrations documentation</a></li>
</ul>Daragh Byrnedaragh at cmu dot eduWhat are migrationsSet up a project Rake file2018-10-04T00:00:00+00:002018-10-04T00:00:00+00:00https://pfoplabs.daraghbyrne.me//7-databases/4-configuring-rake-commands<p>In your project, you’ll need to create a <code class="highlighter-rouge">Rakefile</code>. As part of the <code class="highlighter-rouge">ActiveRecord</code> gem, it uses rake to make a bunch of helper methods - quick useful commands available from the command line. These commands let us setup, modify and change the database structure easily; and without ever touching the database directly.</p>
<p>Similar to the Gemfile, your Rakefile is saved with that exact name and no file extension. First things first, create a new file called <code class="highlighter-rouge">Rakefile</code> in your project folder. And open it in your text editor.</p>
<p>Our Rakefile for this project needs to include a couple of tasks necessary to prepare our database. We just need to tell rake that we want to use these command line utilities that ActiveRecord offers to us. We require them in our <code class="highlighter-rouge">Rakefile</code>, along with our main app.</p>
<p>Add the following to the Rakefile:</p>
<p>````# require your app file first
require ‘./app’
require ‘sinatra/activerecord/rake’</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
_Sidebar:_ Rake is simply a command line task runner, meaning that it runs small scripts when prompted to do so from the command line.
------
## Try out Rake
Now run
```rake -T````
You should see a list of the commands involved. This is what Rake can help with. These are a bunch of basic commands
</code></pre></div></div>
<p>rake db:create # Creates the database from DATABASE_URL or config/database.yml for the current RAILS_E…
rake db:create_migration # Create a migration (parameters: NAME, VERSION)
rake db:drop # Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV…
rake db:environment:set # Set the environment value for the database
rake db:fixtures:load # Loads fixtures into the current environment’s database
rake db:migrate # Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)
rake db:migrate:status # Display status of migrations
rake db:rollback # Rolls the schema back to the previous version (specify steps w/ STEP=n)
rake db:schema:cache:clear # Clears a db/schema_cache.dump file
rake db:schema:cache:dump # Creates a db/schema_cache.dump file
rake db:schema:dump # Creates a db/schema.rb file that is portable against any DB supported by Active Record
rake db:schema:load # Loads a schema.rb file into the database
rake db:seed # Loads the seed data from db/seeds.rb
rake db:setup # Creates the database, loads the schema, and initializes with the seed data (use db:re…
rake db:structure:dump # Dumps the database structure to db/structure.sql
rake db:structure:load # Recreates the databases from the structure.sql file
rake db:version # Retrieves the current schema version number</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
But there's only a few that you need to pay real attention to
</code></pre></div></div>
<p>rake db:create
rake db:create_migration
rake db:seed <br />
rake db:migrate <br />
rake db:rollback</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
## Create your DB with Rake
Open a command prompt in your project folder and type
</code></pre></div></div>
<p>rake db:create
````</p>
<p>Et voila your database should now be in your projects <code class="highlighter-rouge">db</code> folder</p>Daragh Byrnedaragh at cmu dot eduIn your project, you’ll need to create a Rakefile. As part of the ActiveRecord gem, it uses rake to make a bunch of helper methods - quick useful commands available from the command line. These commands let us setup, modify and change the database structure easily; and without ever touching the database directly.Adding Postgres and ActiveRecord2018-10-03T00:00:00+00:002018-10-03T00:00:00+00:00https://pfoplabs.daraghbyrne.me//7-databases/3-adding-activerecord<h2 id="set-up-your-application">Set up your application</h2>
<p>First set up a basic Sinatra application as outlined in the previous section. Then, add your base routes to it.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>get "/" do
401
end
error 401 do
"Not allowed!!!"
end
</code></pre></div></div>
<p>or better yet, download/use the basic application template from the code samples folder!</p>
<h2 id="configure-your-project-for-a-database">Configure your project for a database</h2>
<h4 id="add-gems">Add gems</h4>
<p>You’ll need to add a few gems to your project. Add the following to your Gemfile (if they’re not already there!)</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gem 'activerecord'
gem 'pg'
gem 'sinatra-activerecord' # excellent gem that ports ActiveRecord for Sinatra
gem 'rake'
</code></pre></div></div>
<p>Install and update your project gems by typing the following at the command line:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle install
</code></pre></div></div>
<h4 id="requirements">Requirements</h4>
<p>Now that we have all of the necessary libraries, we need to setup an actual database to store all of our data in.</p>
<p>Require sinatra/activerecord in your project like so, right after the line where you’ve required Sinatra itself:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>require "sinatra"
require 'sinatra/activerecord'
</code></pre></div></div>
<h4 id="configure-the-database">Configure the Database</h4>
<p>Next, we need to tell Sinatra what kind of database we’ll use and where to find it. We do this with a single line near the top of our main application file.</p>
<p>Create a file called <code class="highlighter-rouge">database.yml</code> in a subfolder of your project called <code class="highlighter-rouge">config</code></p>
<p>It should look something like this</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>development:
adapter: postgresql
encoding: unicode
database: database-name
pool: 5
timeout: 5000
test:
adapter: postgresql
database: database-test
pool: 5
timeout: 5000
production:
adapter: postgresql
database: ENV['DATABASE_URL']
pool: 5
timeout: 5000
</code></pre></div></div>
<p>You’ll notice that there are three mappings to databases. The first is in your development environment - i.e. your local machine. The second is something called <code class="highlighter-rouge">test</code> - this supports the case where you might want to deploy your app to a testing environment to allow users or QA to test your app before you make it live. The third is <code class="highlighter-rouge">production</code> or the live instance i.e. what we’ll deploy to heroku.</p>
<p>Each of these definitions will tell our application how to setup the actual database for this project as well as tell Sinatra how to connect to it.</p>
<ul>
<li>
<p>Ultimately the heroku instance will have a mapping to the database defined in an environment variable. Don’t edit this!</p>
</li>
<li>
<p>But… For your local machine <strong>make sure to replace <code class="highlighter-rouge"><databasename></code> with a better database name</strong> that describes the project a little, like <code class="highlighter-rouge">employeedirectory</code> or <code class="highlighter-rouge">twitter_bot_db</code>.</p>
</li>
</ul>Daragh Byrnedaragh at cmu dot eduSet up your application