Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save jennceng/6938d5725cbbfd08fdf60d501a3143e7 to your computer and use it in GitHub Desktop.
Save jennceng/6938d5725cbbfd08fdf60d501a3143e7 to your computer and use it in GitHub Desktop.

Brief Overview

  • If you ever need to store something like a phone number, a zip code, essentially anything with the possibility of having a leading 0 such as an account number ALWAYS STORE THIS AS A STRING, if you store it as an integer 02143 will become 2143

  • In general you will see a common theme of doing things both on the database level and the model level to accomplish things such as validations and associations, this leads to extra safeguards and also

  • recall that SQL is how we talk to databases, if something does not get saved to the database due to some erroneous attempt (such as forgetting something that you put a NULL: false constraint on, the record will not be saved BUT the database may not tell us anything informative about what happened so we might assume things are A-ok

  • keep in mind that we have more specificity with Model level validations than we do with Database level, sometimes we will only be able to do specific validations on the model level such as having a very specific phone number format

  • similarly when making ActiveRecord Associations this is a two step process

  • 1. Make the correct column names in your migration to give the correct schema, such as if an item belongs to a user, the item will have a column called user_id with the type integer

  • 2. Make the association on the model level (this will allow ActiveRecord to know how to correctly make the SQL join query) so that you won’t have to do it on your own!


ActiveRecord Validations

  • model level validations - allows you to have a second level of validation
  • after just .new, no errors, only populates once you run valid / save
  • .errors.full_messages will give you an array of the errors chained
  • errors only populated after .valid? .save? etc., not after .new

let’s open up a pry session! Notice when you make Object related commands that sql queries are generated for you, take a looksie

pry -r './server.rb'

s = Song.new
s.errors
s.save
s.errors
s.errors.full_messages.join(", ")


g = Genre.new()
g.persisted?
g.valid?
# look at model level validations

ActiveRecord Associations

  • pay attention to detail that you’ve correctly set up associations in both the DB and the models

  • again, ER digarams and writing out the relationship will help you, this will tell you where the foreign key(s) should live

  • one to many relationship

  • Song belongs_to genre

  • a Genre has many songs

  • many to many relationship of student, clubs, via join table membership

class Song < ActiveRecord::Base 
  belongs_to :genre
end 
class Genre < ActiveRecord::Base
  has_many :songs # although the table wont have foreign keys, this association allows us to do something like rock.songs if rock is a variable with the value of Genre object
end 

Many-to-many

class Student < ActiveRecord::Base
  has_many :memberships # first the join table, notice the pluralization
  has_many :clubs, through: :memberships
end 
class Club < ActiveRecord::Base
  has_many :memberships # first the join table, notice the pluralization
  has_many :students, through: :memberships
end 
class Membership < ActiveRecord::Base
  belongs_to :student # notice the singularlity, each row / instance of Membership belongs to a single student and belongs to a single club
  belongs_to :club
end 

Be aware of ActiveRecord queries - make sure the return value is what you expect

  • find will either return the object or nil
  • Where will return an array, no matter how many (0 or more) objects it finds
  • if it’s expecting an id, you can give it an object, it knows to grab its primary key
Comment.where(article_id: article.id)
Comment.where(article: article)

FYI - two different syntax for migration lead to same exact schema

$ rake db:create_migration NAME=create_task
# in the new migration
class CreateTasks < ActiveRecord::Migration
  def change
    create_table :tasks do |t|
      t.string :title, null: false
      t.text :description
      t.belongs_to :user, null: false

      t.timestamps
    end
  end
end
$ rake db:migrate && rake db:rollback && rake db:migrate
$ rake db:test:prepare
$ rake

Notice how this translates to the schema

create_table "tasks", force: :cascade do |t|
    t.string   "title",       null: false
    t.text     "description"
    t.integer  "user_id",     null: false
    t.datetime "created_at"
    t.datetime "updated_at"
  end

If instead, you did this syntax in your migration:

class CreateTasks < ActiveRecord::Migration
  def change
    create_table :tasks do |t|
      t.string :title, null: false
      t.text :description
      t.integer :user_id, null: false

      t.timestamps
    end
  end
end

and you rake, notice that it leads to the same schema (pause for gasps)

create_table "tasks", force: :cascade do |t|
    t.string   "title",       null: false
    t.text     "description"
    t.integer  "user_id",     null: false
    t.datetime "created_at"
    t.datetime "updated_at"
  end

take care to never do t.belongs to user_id or the resulting schema will have a column called "user_id_id"! always check your schema after migrations/rollbacks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment