App Academy W5D4
4 min readOct 28, 2020
Models, migrations & Associations
Rails: A server-side MVC web-application framework
- ****full stack framework*****
如何建立一个新的rails project 都可以
ActiveRecord - an ORM Framework (The M in MVC)
Allows us to:
- Represent models and their data
- Represent associations between data
- Validate models before they get persisted to the database
- Perform database operations (CRUD) in OOP fashion
- Migrations
- Models
- Associations
Migrations
- Incremental and reversible changes made to a database schema, allowing it to evolve over time.
- Not just a Rails thing - ubiquitous to app frameworks that work with relational DBs.
- Rails allows you to use an easy Ruby DSL (domain-specific language) to describe changes to your tables, rather than write raw SQL.
Let's Migrate!
Note:
Migration demo
rails g migration createUsers 大小写,复数 convention
t.string column_name,
add_index :users, :username, unique: true
add_index :users, :email, unique: true
2.
rails g migration AddAgeToUsers
AddAgeToUsers class
def change add_column :users, :age, :integer, null: falseenddb:migrate
check schema.rb
will see t.integer "age", null, false
bgg createChirpsclass CreateChirps < ActiveRecord::Migration[5.2]
def change
create_table :chirps do |t|
t.text :body, null: false
# string <= 255, text longer
t.integer :author_id, null: false #这里的null false都是数据库层面的constraint而不是rails本身的validation。
end add_index :chirps, :author_id # cannot unique this one, can have a lot of authors in the table
end
endbr db:migrate
tweets的表建立好了。
*****Common migration terminal commands*****
bundle exec rails g migration Create{TableName} #必须是复数
bundle exec rails g migration Add{ColumnName}To{TableName}
bundle exec rails g migration Remove{ColumnName}From{TableName}
bundle exec rails g migration AddIndexTo{TableName}
*****Common migration methods***************
create_table
add_column
change_column
remove_index
Changing existing migrations
- You can't just edit the migration and run the migration again
- Instead, you have two options:
- Write a new migration (much preferred) migration就是用来改变数据库的工具,你在model里面修改再多的class都没用,那些都是调用数据库的函数而已,并没有对数据库进行真正意义的修改,只有是做了一个migration,这才是对数据库进行改进,比如说加个column,改个表名啊这些,这些操作一旦进行,有的就很难撤回,所以要非常小心,关于表格的操作还是要更仔细的看一看。addtable会了,但是drop table啊什么的这些还没见过。
- Rollback: 这种操作其实非常不推荐,也不太现实,未来在真正的production环境下是不可能允许任何人rollback的,假如说某个数据库操作删掉了某个行,那就只能通过一些操作再把它加回来,rollback不是万金油,很多时候都不好用。
3. up down,在很多文档中看到过关于up和down的介绍,但是不知道怎么用,有时间要研究一下。
*****************************
- rollback the migration (via
rails db:rollback
) - then edit your migration
- run
rails db:migrate
to run the corrected version
Model
- The central component of the MVC pattern
- A class that represents and directly manages the data, logic, and rules for a table 必须是单数存在的
- Typically contains: validations, associations, and custom methods
- Inherits from ApplicationRecord (which, in turn, inherits from ActiveRecord) 不直接继承active record的原因是不想修改它,多一层保护。
- There is a one-to-one correspondence between a model and a table,每个表对应一个class,每个instance对应一条数据。
- An instance of this class / model represents a row in our table
Database Constraints vs Model Validations
- Model validations are best used to provide error messages to users interacting with your app # validation更好,error更好看,初步防线,而model的contraints是最后防线
- It's highly likely that:
- You will interact with the database at some point outside of Rails
- You will make a mistake in your code that causes invalid data
- Database constraints are the last line of defense for data-integrity
- Writing constraints is work, but they will save you a lot of pain
Common Validations
validates :some_column, presence: true
- similar to
null: false
validates :other_column, uniqueness: true
- similar to
unique: true
- Custom Validations
Rails Models Demo
gem 'annotate'
能把schema里面的表关系以comment的形式放到相应的model里面去
create user的时候,id是postgres提供的。
rails c 已经load了所有的model
v.save!如果不成功会raise error
v.save 这个只会给你返回个true false
fakev.errors.full_messages #return array of full message
fakev.errors.messages #return as hashChirp.create(body:"msg",author_id: some_user.id)
增加自己的validationdef body_too_longif body && body.length > 140
errors[:body] << "is too long"
end
end
validate的时候,要注意,是errors[:class_name] << 'error message' 最好写的相关一点,这个如果validate不同多,errors就会直接停止数据库操作,并返回写好的数据信息了。不再是validates了,而是validate******不要忘记这个部分。validate :body_too_long #后面也不用写什么true什么的
select user.id from users join likes on likes.liker_id = users.id join chirps on users.id = chirps.author_id
- Connections between two Active Record models.
- 两个model之间的关系了,has_many, belongs_to, has_one, has_many_through…
- Make common operations simpler and easier in your code.
- We don't have to write anymore SQL
JOIN
statements - Simply methods that we can call
class Chirp < ApplicationRecord
belongs_to :author, primary_key: :id, foreign_key: :author_id, class_name: :User
validates :body, presence: true
validates :author_id, presence: true
validate :body_too_longdef body_too_long
if body && body.length > 140
errors[:body] << "is too long"
end
end
end
Example Association
class Strike < ApplicationRecord
belongs_to :student,
primary_key: :id,
foreign_key: :student_id,
class_name: :Student
end凡是这种belongs to的就说明这个表的级别要相对低一些,它存了别人的id,就说明有一种隶属关系,user可以有很多的transction,但是user表绝对不可能存那么多transaction id在里面,那样存储就会非常的费,而且没有意义,join之后正常就都出来了,但是transaction这种级别很低的表,就会存很多别人的id,users,product,shopper,market...因为它就是最granular的级别。数据库的建立有的时候就是要考虑,哪些东西是真正需要建立关系的,关系(id)存在哪个表里面,这些其实是费时间的。
有时间的话,尝试建立一个tlq的数据库吧。
- belongs_to is an ActiveRecord method that takes the following arguments
def belongs_to(:name, options = {})
end
Associations Code Demo
*****Associations Recap*****
class Chirp < ApplicationRecord
#validations go here
belongs_to :user,
primary_key: :id,
foreign_key: :author_id,
class_name: :User
end
class User < ApplicationRecord
#validations go here
has_many :chirps,
primary_key: :id,
foreign_key: :author_id,
class_name: :Chirp
end为什么primary——key都一样?暂时记住就是conversion吧
belongs to的foreign key同时也是has——one has——many的foreign key,都一样,虽然关系是相反的,我们就这样决定。
has_one
- easily confused with belongs_to
- only write them if you've already made the corresponding belongs_to
- 这个反正还是看id存在哪吧,id存的那个model就是belongs——to,否则就是has one
Strategy when writing associations
- Start with belongs_to
- Write the corresponding has_many or has_one in the other model.
- Write has_many throughs using only other associations in the model as the through, check the associated model for an association to be the source.
- has many through这个东西很牛逼,就是把表和表相连接了,association级别的join,model中互相就通过某个id,就连在一起。
Terminal Commands Recap
rails new {project_name} -G -d postgresql
orrails _VERSION_ new {project_name} -G -d postgresql
bundle exec rails db:create
bundle exec rails g migration Create{TableName}
bundle exec rails db:migrate
bundle exec rails db:migrate:status
bundle exec rails g model {ModelName}