-
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 become2143
-
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!
- 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
-
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)
$ 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