Rails Programming today is a race between software engineers striving to build better and bigger idiot-proof programs, and the Universe trying to produce.

Slides:



Advertisements
Similar presentations
JQuery MessageBoard. Lets use jQuery and AJAX in combination with a database to update and retrieve information without refreshing the page. Here we will.
Advertisements

PHP II Interacting with Database Data. The whole idea of a database-driven website is to enable the content of the site to reside in a database, and to.
Session 2Introduction to Database Technology Data Types and Table Creation.
CC SQL Utilities.
The Librarian Web Page Carol Wolf CS396X. Create new controller  To create a new controller that can manage more than just books, type ruby script/generate.
Introduction to PHP MIS 3501, Fall 2014 Jeremy Shafer
By: Lloyd Albin 11/6/2012. Serials are really integers that have a sequence attached to provide the capability to have a auto incrementing integer. There.
PDF Questions Submitted by our customers: Gus Lluberes.
WebDFS Budget Amendment and Personnel Processing.
Ruby on Rails Model of MVC. Model-View-Controller Paradigm A way of organizing a software system Benefits: Isolation of business logic from the user interface.
Let’s try Oracle. Accessing Oracle The Oracle system, like the SQL Server system, is client / server. For SQL Server, –the client is the Query Analyser.
24-Jun-15 Rails. What is Rails? Rails is a framework for building web applications This involves: Getting information from the user (client), using HTML.
A Guide to SQL, Seventh Edition. Objectives Understand the concepts and terminology associated with relational databases Create and run SQL commands in.
DT211 Stage 2 Databases Lab 1. Get to know SQL Server SQL server has 2 parts: –A client, running on your machine, in the lab. You access the database.
Creating Database Tables CS 320. Review: Levels of data models 1. Conceptual: describes WHAT data the system contains 2. Logical: describes HOW the database.
A Guide to MySQL 3. 2 Objectives Start MySQL and learn how to use the MySQL Reference Manual Create a database Change (activate) a database Create tables.
Creating a wiki blog. Run apps that come with instant rails distribution select I /rails applications/open ruby console window Cd to cookbook or typo.
Ruby on Rails Creating a Rails Application Carol E Wolf CS396X.
1 Functional Testing Motivation Example Basic Methods Timing: 30 minutes.
Introduction To Databases IDIA 618 Fall 2014 Bridget M. Blodgett.
Ruby on Rails: An Introduction JA-SIG Summer Conference 2007 Michael Irion The University of Tulsa.
Rails and Grails. To get started Make sure you have java installed You can get the sdk and jre at:
SQL | PHP Tutorial at 8am. god, it’s early.. SQL intro There are many different versions of SQL available for usage. Oracle MySQL SQLite DB2 Mimer The.
Datasheets I: Create a table by entering data – You type, Access listens Lesson 18 By the end of this lesson you will be able to complete the following:
Databases with PHP A quick introduction. Y’all know SQL and Databases  You put data in  You get data out  You can do processing on it very easily 
A Guide to SQL, Eighth Edition Chapter Three Creating Tables.
1 Dr Alexiei Dingli Web Science Stream Models, Views and Controllers.
Session 5: Working with MySQL iNET Academy Open Source Web Development.
Introduction to Shell Script Programming
1 Dr Alexiei Dingli Web Science Stream Advanced ROR.
PHP meets MySQL.
1 In the good old days... Years ago… the WWW was made up of (mostly) static documents. –Each URL corresponded to a single file stored on some hard disk.
Selecting, Formatting, and Printing a finished Report…….
1 Working with MS SQL Server Textbook Chapter 14.
Ruby on Rails Your first app. Rails files app/ Contains the controllers, models, views and assets for your application. You’ll focus on this folder for.
Installing and Using MySQL and phpMyAdmin. Last Time... Installing Apache server Installing PHP Running basic PHP scripts on the server Not necessary.
Extending HTML CPSC 120 Principles of Computer Science April 9, 2012.
© Copyright IBM Corporation 2007 AP/Americas April 15-18, 2007 Anaheim, California Introduction to RubyOnRails - a J2EE replacement? Russell Scheerer –
U:/msu/course/cse/103 Day 06, Slide 1 CSE students: Do not log in yet. Review Day 6 in your textbook. Think about.
Chapter 7 File I/O 1. File, Record & Field 2 The file is just a chunk of disk space set aside for data and given a name. The computer has no idea what.
Associations INFO 2310: Topics in Web Design and Programming.
Photo Gallery INFO 2310: Topics in Web Design and Programming.
Variables and ConstantstMyn1 Variables and Constants PHP stands for: ”PHP: Hypertext Preprocessor”, and it is a server-side programming language. Special.
Intro to SQL| MIS 2502  Spacing not relevant › BUT… no spaces in an attribute name or table name  Oracle commands keywords, table names, and attribute.
Open Source Server Side Scripting ECA 236 Open Source Server Side Scripting MySQL – Inserting Data.
1. When things go wrong: how to find SQL error Sveta Smirnova Principle Technical Support Engineer, Oracle.
When I want to work with SQL, I start off as if I am doing a regular query.
Validation "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs and the Universe trying to.
Chapter 15 © 2013 by Pearson Overview of Rails - Rails is a development framework for Web-based applications - Based on MVC architecture for applications.
1 Migration. 2 What’s Migration? Migration –Isolates database differences Allows you to write schema updates without worries about differences –Helps.
Creating a simple database This shows you how to set up a database using PHPMyAdmin (installed with WAMP)
COMP3241 E-Commerce Technologies Richard Henson University of Worcester November 2014.
8 Chapter Eight Server-side Scripts. 8 Chapter Objectives Create dynamic Web pages that retrieve and display database data using Active Server Pages Process.
Chapter 8 Manipulating MySQL Databases with PHP PHP Programming with MySQL 2 nd Edition.
Introduction to Ruby&Rails Yuri Veremeyenko Monica Verma.
Class 3Intro to Databases Class 4 Simple Example of a Database We’re going to build a simple example of a database, which will allow us to register users.
CS 160 and CMPE/SE 131 Software Engineering February 9 Class Meeting Department of Computer Science Department of Computer Engineering San José State University.
Introduction to information systems RUBY ON RAILS dr inż. Tomasz Pieciukiewicz.
Migrations Carol Wolf CS 396X. ISBNTitleAuthorImage EmmaAustenemma.jpg Oliver TwistDickenstwist.jpg HamletShakespearehamlet.jpg.
LOGIN FORMS.
Advanced Migration By Aye Mon Tun.  To change database schema in consistent and easy way  In ruby code Migration? 11/25/2013 2Web Application Engineering.
Software-Projekt 2008 Seminarvortrag“Short tutorial of MySql“ Wei Chen Verena Honsel.
1 Adding a Model. We have created an MVC web app project Added a controller class. Added a view class. Next we will add some classes for managing movies.
9/21/04 James Gallagher Server Installation and Testing: Hands-on ● Install the CGI server with the HDF and FreeForm handlers ● Link data so the server.
SQL and SQL*Plus Interaction
Database application MySQL Database and PhpMyAdmin
Intro to PHP & Variables
ISC440: Web Programming 2 Server-side Scripting PHP 3
Agile Web Development with Ruby and Rails
Presentation transcript:

Rails Programming today is a race between software engineers striving to build better and bigger idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning. - Rick Cook No, I'm not Rick

Inventory Application

So, I was reading my Tuesday morning A fellow that reports to me came in to talk about how we order and receive pcs and printers And I've been wanting to convert our machine move form to a web page Suddenly, a real project…

Requirements A form that can handle both acquisitions and moves An hook so we can create remedy tickets as part of the process A mechanism for marking records as processed, and for moving data into our main inventory database This should be simple, following KISS

What we'll cover Migrations and more about Sqlite3 Validations

The usual Create a rails framework Note backslashes Also, use of underscores Some of this is bad thinking… rails inventory cd inventory ruby script/generate scaffold Machine \ user_name:string \ user_name:string \ date_submitted:datetime \ date_submitted:datetime \ ticket_number:integer \ ticket_number:integer \ from_location:string \ from_location:string \ to_location:string \ to_location:string \ from_entity:string \ from_entity:string \ to_entity:string \ to_entity:string \ old_machine_name:string \ old_machine_name:string \ new_machine_name:string \ new_machine_name:string \ serial_number:string \ serial_number:string \ unc_number:string \ unc_number:string \ comments:text \ comments:text \ status:string \ status:string \ exported_to_main:boolean \ exported_to_main:boolean \ unneeded_field:decimal unneeded_field:decimal

Generation of the first Migration The generation of the scaffold creates: The view A controller A model Also a database migration file in the db directory, in this case: _create_machines.rb Note the timestamp and the conventional name

What does this file do? This file is a script, that contains a class, with two defined methods One method creates the database table creates initial fields sets types The other method undoes everything the first one does

class CreateMachines < ActiveRecord::Migration def self.up def self.up create_table :machines do |t| create_table :machines do |t| t.string :user_name t.string :user_name t.datetime :date_submitted t.datetime :date_submitted t.integer :ticket_number t.integer :ticket_number t.string :from_location t.string :from_location t.string :to_location t.string :to_location t.string :from_entity t.string :from_entity t.string :to_entity t.string :to_entity t.string :old_machine_name t.string :old_machine_name t.string :new_machine_name t.string :new_machine_name t.string :serial_number t.string :serial_number t.string :unc_number t.string :unc_number t.text :comments t.text :comments t.string :status t.string :status t.boolean :exported_to_main t.boolean :exported_to_main t.decimal :unneeded_field t.decimal :unneeded_field t.timestamps t.timestamps end end 1st Part Class inherits from ActiveRecord::Mi gration self.up is a method applied when a migration is run A loop assigns type and names

def self.down def self.down drop_table :machines drop_table :machines end endend 2nd Part a second method provides a way to roll back the migration Done properly, this allows one to move forward and back in database "versions" without affecting other structures

Migrations You can modify this file before applying it, adding additional options such as field lengths, default values, etc

What's the point? Migrations allow manipulation of the database with some version control You could also manually manipulate the database, but you'd have to keep track of the changes But some migrations are irreversible, and if you don't define a good way back…. To protect against that, backup! Or use version control systems like cvs, subversion, git

schema.rb Stored in db/ This is the canonical representation of the current state of the database You could modify this--don't Generated after each migration You can use this with db:schema:load to implement the same db structures on another system

ActiveRecord::Schema.define :version => do create_table "machines", :force => true do |t| create_table "machines", :force => true do |t| t.string "user_name" t.string "user_name" t.datetime "date_submitted" t.datetime "date_submitted" t.integer "ticket_number" t.integer "ticket_number" t.string "from_location" t.string "from_location" t.string "to_location" t.string "to_location" t.string "from_entity" t.string "from_entity" t.string "to_entity" t.string "to_entity" t.string "old_machine_name" t.string "old_machine_name" t.string "new_machine_name" t.string "new_machine_name" t.string "serial_number" t.string "serial_number" t.integer "unc_number", :limit => 255 t.integer "unc_number", :limit => 255 t.text "comments" t.text "comments" t.string "status" t.string "status" t.boolean "exported_to_main" t.boolean "exported_to_main" t.datetime "created_at" t.datetime "created_at" t.datetime "updated_at" t.datetime "updated_at" end end

But… We haven't run our first migration yet rake db:migrate This command applies all unapplied migrations in the db/migrate dir The timestamps for the migrations are stored in a table in the database, schema_migrations (this is how rails keeps track of migrations)

What rake really does Analogous to make, it looks for a file to process in order to build something rake db:migrate looks in the db/migrate folder, and finds any of the migration files that have not yet been applied, and runs those Each time you want to make changes to the db, you generate a migration script, edit that, then use rake to migrate the changes into the db

About the database By default, rails 2.1 uses sqlite3, other dbs are also possible to use, like mysql sqlite3 databases are single files, eg. development.sqlite3 We can look at the database directly look, but don't touch!

Sqlite3 syntax Commands that manipulate the db begin with a period Sql commands don’t and must end with a semicolon Get help with.help, exit with.exit

Some sqlite3 commands.databases List names and files of attached databases.exit Exit this program.header s ON|OFF Turn display of headers on or off.help Show this message.output FILENAME Send output to FILENAME.output stdout Send output to the screen.quit Exit this program.read FILENAME Execute SQL in FILENAME.schema ?TABLE? Show the CREATE statements.separator STRING Change separator used by output mode and.import.show Show the current values for various settings

A Sample Session sqlite>.tables machines schema_migrations sqlite>.schema machines CREATE TABLE "machines" "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "user_name" varchar 255, "date_submitted" datetime, "ticket_number" integer, "from_location" varchar 255, "to_location" varchar 255, "from_entity" varchar 255, "to_entity" varchar 255, "old_machine_name" varchar 255, "new_machine_name" varchar 255, "serial_number" varchar 255, "unc_number" varchar 255, "comments" text, "status" varchar 255, "exported_to_main" boolean, "unneeded_field" decimal, "created_at" datetime, "updated_at" datetime ; sqlite>.exit

You might have noticed There's a field named unneeded_field I don't need this field, so we'll look at dumping it To do this, create a new migration hays$ script/generate migration \ RemoveColumn_uneeded_field exists db/migrate create db/migrate/ _remove_column_uneeded_field.rb

A blank migration Now we have a blank migration file: _remove_column_une eded_field.rb file in db/migrate Yes the name is long, but it's explicit and helps us know what the migration was supposed to do We have to edit this file with the commands we need to apply to the database (rails, as good as it is, cannot read minds)

A blank migration Again, a class with two methods, but nothing in them class RemoveColumnUneededField < \ ActiveRecord::Migration def self.up def self.up end end def self.down def self.down end endend

Filling the empty migration We'll use remove_column with the table and field name, and add_column to undo the change in case we were wrong class RemoveColumnUneededField < \ ActiveRecord::Migration ActiveRecord::Migration def self.up def self.up remove_column :machines, :unneeded_field remove_column :machines, :unneeded_field end end def self.down def self.down add_column :machines, :unneeded_field, :decimal add_column :machines, :unneeded_field, :decimal end endend

create_table name, options drop_table name rename_table old_name, new_name add_column table_name, column_name, type, options rename_column table_name, column_name, new_column_name change_column table_name, column_name, type, options remove_column table_name, column_name add_index table_name, column_names, options remove_index table_name, index_name from Available migration commands These are the current commands you can use

Up and down Use rake db:migrate to apply this ne migration (the assumption is that we want to apply a new migration) Use rake db:migrate:down VERSION=xxxxxxxxxxxxxx where xxxxxxxxxxxxxx is the timestamp of the migration file. So if we run rake db:migrate:down VERSION= , we get the column back

Running the Migration When you run it, if you don’t get an error, you'll see something like this hays$ rake db:migrate (in /Volumes/BIL/INLS672/samples/ruby/inventory) == RemoveColumnUneededField: migrating =========== -- remove_column(:machines, :unneeded_field) -> s -> s == RemoveColumnUneededField: migrated (0.3494s) ===

Results hays$ sqlite3 db/development.sqlite3 SQLite version Enter ".help" for instructions sqlite>.schema machines CREATE TABLE "machines" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "user_name" varchar(255), AUTOINCREMENT NOT NULL, "user_name" varchar(255), "date_submitted" datetime, "ticket_number" integer, "from_location" "date_submitted" datetime, "ticket_number" integer, "from_location" varchar(255), "to_location" varchar(255), "from_entity" varchar(255), varchar(255), "to_location" varchar(255), "from_entity" varchar(255), "to_entity" varchar(255), "old_machine_name" varchar(255), "to_entity" varchar(255), "old_machine_name" varchar(255), "new_machine_name" varchar(255), "serial_number" varchar(255), "new_machine_name" varchar(255), "serial_number" varchar(255), "unc_number" varchar(255), "comments" text, "status" varchar(255), "unc_number" varchar(255), "comments" text, "status" varchar(255), "exported_to_main" boolean, "created_at" datetime, "updated_at" "exported_to_main" boolean, "created_at" datetime, "updated_at" datetime); datetime); sqlite>.exit

Rolling back We can get the column back by running: rake db:migrate:down VERSION= But we can't get the data that was in the column back

An aside Rail documentation Tutorials for 2.1 are generally just how to get started API doc are the most complete, but not very readable--see Lots of code snippets out there, playing with those are a good was to learn new things--most of these are unixy and terse Agile Web Development with Rails is the best book I've found. see: Practical Rails Projects, see

An aside Go with the flow Rails is complicated enough that it's best to roll with it This is partly due to the emphasis on convention over configuration The conundrum is where does the knowledge lie CLI versus GUI DB versus Middleware versus Browser Thick versus Thin clients

After all this… We've looked at migrations and the database Migrations do not affect other parts of the applications, such as the model, controller(s), or any of the views We dropped a column after the scaffolding, so the views reference unneeded_field So we get an error when we try to run the pages…

The error

Easy peasy The error message references a method, this is one way fields in the db are accessed Also shows us source code around the offense

Cleaning up In each of the views we need to remove the references For example, in new.html.erb and edit.html.erb:

Now it works

Validations

Simple validation Now that we have the db straighten out (yeah, right), time to add some validations These belong in the model, machine.rb in app/models Right now, that's just: class Machine < ActiveRecord::Base end

Included validations Our class has access to classes and methods from ActiveRecord::Validations The simplest is validates_presence_of Usage: # Validate that required fields are not empty validates_presence_of :user_name, \ :date_submitted, :from_location, \ :from_entity, :to_location, :to_entity, :status see

Other Included Validations validates_acceptance_of validates_associated validates_confirmation_of validates_each validates_exclusion_of validates_format_of validates_inclusion_of validates_length_of validates_numericality_of validates_presence_of validates_size_of validates_uniqueness_of from

Validations added to the model These went easily: #Validates to_location, that should only 6 chars, we'll allow 10 validates_length_of :to_location, :maximum=>15 #Validates fields that should not be more than 15 characters validates_length_of :user_name, :maximum=>15 #Validates fields that should not be more than 30 chars validates_length_of :from_location, :maximum=>30 validates_length_of :from_entity, :maximum=>30 validates_length_of :to_entity, :maximum=>30 # None of these affect the database field lengths

A rabbit hole And, also, I want to make sure that unc_number is an integer, but it can be empty, so I try this: #Validates that unc number is a number validates_numericality_of :unc_number,\ :allow_nil=>true, :only_integer=>true, But it fail--if the field is empty it throws an error…

After digging Google is my friend, and I find: on-empty-not-nil-attributes on-empty-not-nil-attributes This suggests that the problem is that unc_number is really a string, and that an empty string is empty, not nil…

But where? HTML knows shinola about text/integer types But no errors on stuffing the wrong kind of data into a field (esp no ugly ones), so likely sqlite3 doesn't really care But the db type is involved since in the migration it was defined with: t.string :unc_number So rails knows it's a string

A hack Brandon's approach is to define a method that goes through all of the params passed to the model for validation and if empty, set to nil…. def clear_empty_attrs def do do |key,value| self[key] = nil if value.blank? self[key] = nil if value.blank? end end

A hack This method must be called before the validation are run, so it goes to the top of the model (not required, JAGI) This is done using before_validation So before the validation sequence, all empties are converted to nil Does this seem like a good fix? before_validation :clear_empty_attrs

A hack One concern I had was this it hitting all of the fields--and that way leads to madness--so I limited it protected def clear_empty_attrs # we don't need to loop through everything, so I'm # just calling the one field do |key,value| #self[key] = nil if value.blank? self[:unc_number] = nil if unc_number.blank? # end end

Works, but…. It is a hack Using it, I'm working around an error that's due to a bad choice I made-- rarely a good idea, and these things may take time to bite I'm also going against the flow So what to do to fix it? Test, research, change, rinse and repeat

Back to the beginning As it turns out, I did define an integer in the database, ticket_number ruby script/generate scaffold Machine \ user_name:string \ date_submitted:datetime \ ticket_number:integer \ from_location:string \ to_location:string \ from_entity:string \ to_entity:string \ old_machine_name:string \ new_machine_name:string \ serial_number:string \ unc_number:string \ comments:text \ status:string \ exported_to_main:boolean \ unneeded_field:decimal

An easy test I try the same validation against that field and it works, so I confirm the problem is the field type Note the error message… validates_numericality_of\ :ticket_number,\ :ticket_number,\ :only_integer=>true,\ :only_integer=>true,\ :allow_nil=>true,\ :allow_nil=>true,\ :message=>'must be an integer if not blank' :message=>'must be an integer if not blank'

A new migration So, I need to change the type of unc_number Again leaving a way back…. This fixed it for real class ChangeTextToDecimalsUncNumber < ActiveRecord::Migration < ActiveRecord::Migration def self.up def self.up change_column(:machines, :unc_number, :integer) change_column(:machines, :unc_number, :integer) end end def self.down def self.down change_column(:machines, :unc_number, :string) change_column(:machines, :unc_number, :string) end endend

Custom Validations It's also easy to write custom validations Define a method in the protected section (since we don't need this outside our class) Call that method as a symbol in the validation section: validate :our_method As an example, we'll work with ticket_number, even tho it's an artificial example

A new method First, we'll check the value and make sure it's above 1000 In testing this works ok, but obviously it won't accept a nil value def ticket_number_must_be_greater_than_1000 errors.add(:ticket_number, 'must be greater than 1000')\ errors.add(:ticket_number, 'must be greater than 1000')\ if ticket_number < 1001 if ticket_number < 1001 end end

Not a nil So we need to check for not nil and less than 1001 Use a bang (!) to say not def ticket_number_must_be_greater_than_1000 errors.add(:ticket_number, 'must be greater than 1000')\ errors.add(:ticket_number, 'must be greater than 1000')\ if !ticket_number.nil? \ if !ticket_number.nil? \ && ticket_number < 1001 && ticket_number < 1001end

Time Validations We want the date_submitted to be reasonable Fortunately, rails understands time and dates

Time Methods ago day days fortnight fortnights from_now hour hours minute minutes month months second seconds since until week weeks year years

Another Validation # This validates that the date and time are resonable values def date_submitted_must_be_sensible def date_submitted_must_be_sensible errors.add(:date_submitted, \ errors.add(:date_submitted, \ 'Time and date cannot be in the past')\ 'Time and date cannot be in the past')\ if date_submitted < Time.now if date_submitted < Time.now errors.add(:date_submitted, \ errors.add(:date_submitted, \ 'Time and date cannot be more than 2 years in the future')\ 'Time and date cannot be more than 2 years in the future')\ if date_submitted > Time.now.advance(:years => 2) if date_submitted > Time.now.advance(:years => 2) # is equivalent to: # is equivalent to: #if date_submitted > 2.years.from_now #if date_submitted > 2.years.from_now end end

Other minor changes Stripped down the index view, don't need that much detail This version is tarred and gzipped in the samples dir as inventory01.gz.tar

Intelligence in the middleware Although sqlite3 types this field as a string, it doesn't care what the contents are Rails does care though So most all of the control mechanisms are in rails This is a common approach Makes management of the system easier

Sources eets/rails-migrations eets/rails-migrations on-empty-not-nil-attributes on-empty-not-nil-attributes