1、创建一个database
mysql我们已经在1.3节安装过了。连接远程,在项目目录下连接mysql,创建一个database数据库。如果你在1.3节启动项目时碰到了mysql错误并且解决了,那可以跳过1、2步,因为你已经配置好了。
vagrant@vagrant-ubuntu-trusty-64:/vagrant/data_system$ mysql -u root -p
#输入你在1.3节配置的数据库密码
Enter password:
#创建一个名为data_system数据库
mysql> create database data_system;
#系统返回信息
Query OK, 1 row affected (0.09 sec)
#再输入show databases;展示当前数据库的名字,data_symtem数据库就是我们刚刚创建的。
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| data_symtem |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
2、配置config/database.yml文件
根据下面代码示例配置你的database.yml文件,其中password是你安装mysql时配置的密码。将development:下面数据库名改成咱们刚刚创建的数据库名database: data_system。test:和production:下面的代码不需要改动
# SQLite version 3.x
# gem install sqlite3
#
# Ensure the SQLite 3 gem is defined in your Gemfile
# gem 'sqlite3'
#
default: &default
adapter: mysql2
encoding: utf8
pool: 5
username: root #mysql名称,默认为root
password: xzn123xzn #安装mysql时设置的密码
host: localhost
development:
<<: *default
database: data_system #我们建立database的名称
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
#下面信息是默认的,初学的我们暂时不需要改动
test:
<<: *default
database: db/test.sqlite3
production:
<<: *default
database: db/production.sqlite3
3、创建映射文件,在data数据库中添加表
(1)我们先写一下这个表需要哪些字段,表结构如下:
字段名 | 字段说明 | 字段类型 | 备注 |
---|---|---|---|
name | 用户名称 | string | 必填 |
注册邮箱 | string | 必填 | |
password | 密码 | string | 必填 |
role | 用户角色(控制权限) | integer | 0普通用户 1管理员 2超级管理员 |
status | 用户状态(是否激活) | integer | 0已激活 1未激活 |
(2)创建映射文件rails g model …
在项目目录下输入rails g model account name:string email:string password:string role:integer status:integer
。会产生一个映射文件db/migrate/20180915153542_create_accounts.rb
#创建account表
/vagrant/data_symtem$ rails g model account name:string email:string password:string role:integer status:integer
#系统返回信息
create db/migrate/20180915153542_create_accounts.rb
create app/models/account.rb
invoke test_unit
create test/models/account_test.rb
create test/fixtures/accounts.yml
(3)将映射文件映射到数据库rake db:migrate
#运行rake db:migrate,将映射文件映射到数据库中,此操作会在数据库建立account表以及在表中建立相应的字段
/vagrant/data_symtem$ rake db:migrate
== 20181127085433 CreateAccounts: migrating ===================================
-- create_table(:accounts)
-> 0.0150s
== 20181127085433 CreateAccounts: migrated (0.0164s) ==========================
可能出现的错误:
Mac系统中,如果没有安装vagrant,直接在mac系统创建项目并运行rails g model…,可能会出现以下错误:
/Users/xuzhaoning/.rvm/rubies/ruby-2.4.4/lib/ruby/gems/2.4.0/gems/activerecord-
5.1.1/lib/active_record/connection_adapters/connection_specification.rb:188
:in `rescue in spec': Specified 'mysql2' for database adapter, but the gem is
not loaded. Add `gem 'mysql2'` to your Gemfile (and ensure its version is at
the minimum required by ActiveRecord). (Gem::LoadError)
解决方法:
项目在mac电脑上直接运行可能出现这个错误,我们的解决方案是在Mac电脑上安装vagrant(1.1章中有讲),在Ubuntu环境中启动项目
4、进入控制台,查看数据
#进入控制台
/vagrant/data_symtem$ rails c
#查看创建的accounts表
irb(main):001:0> Account.new
=> #<Account id: nil, name: nil, email: nil, password: nil, role: nil, status: 0, created_at: nil, updated_at: nil>
5、数据库操作知识
Rails中的数据库操作用的是Active Record(活动记录),是一种领域模型模式,特点是一个模型类对应关系型数据库中的一个表,而模型类的一个实例对应表中的一行记录。
比如:Account这个模型类对应了mysql数据库中的accounts表,Account类的一个实例对象对应accounts表中的一条数据。
我们在项目目录下,输入rails c进入控制台,在控制台中操作数据库
(1)创建数据
#a是一个Accoun类的实例对象。
irb(main):001:0> a = Account.create(name: "猫宁", email: "12345@qq.com")
#相当于mysql代码。当我们创建或者修改数据时,created_at字段和updated_at字段都会自动改变。
INSERT INTO accounts (name, email, created_at, updated_at) VALUES ('猫宁', '12345@qq.com', '2018-12-26 15:55:30', '2018-12-26 15:55:30')
#再创建一个name为“狗宁”,email为"23456@qq.com"的实例对象
irb(main):002:0> Account.create(name: "狗宁", email: "23456@qq.com")
可能出现错误:
ActiveRecord::StatementInvalid: Mysql2::Error: Incorrect string value: ‘\xE7\x8C\xAB\xE5\xAE\x81’ for column ‘name’ at row 1: INSERT INTO accounts
(name
, email
, created_at
, updated_at
) VALUES (‘猫宁’, ‘12345@qq.com’, ‘2018-12-30 04:54:18’, ‘2018-12-30 04:54:18’)
此错误是向MySQL中插入中文时才会出现,原因是MySQL的字符集不是utf-8,所有不支持中文,我们需要exit退出控制台,登录mysql进行以下操作:
#登录mysql
vagrant@vagrant-ubuntu-trusty-64:/vagrant/data_system$ mysql -u root -p
#输入你在1.3节配置的数据库密码
Enter password:
#修改data_system数据库,accounts表的字符集;
mysql> ALTER TABLE data_system.accounts CONVERT TO CHARACTER SET utf8;
Query OK, 1 row affected (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 0
#重新在数据库中映射accounts表,注意这一步数据库数据会损坏,需要进行数据备份。我们目前没有添加过数据,就不备份了。
vagrant@vagrant-ubuntu-trusty-64:/vagrant/data_system$ rake db:drop
vagrant@vagrant-ubuntu-trusty-64:/vagrant/data_system$ rake db:create
vagrant@vagrant-ubuntu-trusty-64:/vagrant/data_system$ rake db:migrate
(2)查找数据
1)查找第一条数据,返回我们创建的第一个Account对象
irb(main):001:0> a1 = Account.first
=> #<Account id: 1, name: "猫宁", email: "12345@qq.com", password: nil, role: nil, status: nil, created_at: "2018-12-26 15:55:30", updated_at: "2018-12-26 15:55:30">
#相当于mysql代码
SELECT * FROM accounts ORDER BY id ASC LIMIT 1
2)查找最后一条数据,返回我们创建的第二个Account对象
irb(main):002:0> a2 = Account.last
=> #<Account id: 2, name: "狗宁", email: "23456@qq.com", password: nil, role: nil, status: nil, created_at: "2018-12-28 09:31:22", updated_at: "2018-12-28 09:31:22">
#相当于mysql代码
SELECT * FROM accounts ORDER BY id DESC LIMIT 1
3)查找出所有数据,返回Account对象集合,里面包含我们创建的所有对象。
如果数据较多,在实际项目中不建议用.all拿出所有数据,因为这样会耗费很多的内存。数据量大,用分页或者where查询缩小范围。
irb(main):003:0> a3 = Account.all
=> #<ActiveRecord::Relation [#<Account id: 1, name: "猫宁", email: "12345@qq.com", password: nil, role: nil, status: nil, created_at: "2018-12-26 15:55:30", updated_at: "2018-12-26 15:55:30">, #<Account id: 2, name: "狗宁", email: "23456@qq.com", password: nil, role: nil, status: nil, created_at: "2018-12-28 09:31:22", updated_at: "2018-12-28 09:31:22">]
#相当于mysql代码
SELECT * FROM accounts
4)通过id查找数据,这样会返回对应id的Account对象。
需要注意的是,如果没有此id,会报错,所以我们再实际项目中,在不确定该id存在的情况下,一般不会用find查找,而是用find_by替代,下面会讲。
irb(main):006:0> Account.find(2)
=> #<Account id: 11, name: "狗宁", email: "23456@qq.com", password: nil, role: nil, status: nil, created_at: "2018-12-28 09:31:22", updated_at: "2018-12-28 09:31:22">
#相当于mysql代码
SELECT * FROM accounts WHERE id = 2
5)通过条件查找数据,这样会得到Account对象集合,具体对象实例根据集合索引获取。
- 如果没有对应的条件,会返回一个空集合。
- where不管查出多少条数据都是一个对象集合。
#查找name为"猫宁"的数据,得到一个对象的集合。
irb(main):008:0> accs = Account.where(name:"猫宁")
=> #<ActiveRecord::Relation [#<Account id: 1, name: "猫宁", email: "12345@qq.com", password: nil, role: nil, status: nil, created_at: "2018-12-26 15:55:30", updated_at: "2018-12-26 15:55:30">]>
#获取集合中第一个name为"猫宁"的对象
irb(main):009:0> acc = accs.first
=> #<Account id: 1, name: "猫宁", email: "12345@qq.com", password: nil, role: nil, status: nil, created_at: "2018-12-26 15:55:30", updated_at: "2018-12-26 15:55:30">
#然后获取该对象的邮箱,即accounts表中的email字段
irb(main):010:0> email = acc.email
=> "12345@qq.com"
#上面3步可以整合成一句
irb(main):011:0> email = Account.where(name:"猫宁").first.email
=> "12345@qq.com"
#也等同于,find_by相当于where().first
irb(main):012:0> email = Account.find_by(name:"猫宁").email
=> "12345@qq.com"
#如果没有相对应的条件会返回一个nil对象
irb(main):013:0> accounts = Account.find_by(name:"猫宁喵喵喵")
=> nil
#对nil进行.first.email操作会报错
irb(main):014:0> email = Account.where(name:"猫宁喵喵喵").first.email
NoMethodError: undefined method `email' for nil:NilClass
from (irb):14
(3)修改数据
修改一个对象用update,修改对象集合用update_all
#将name为"猫宁"的对象,修改name为"可爱的猫宁"
#如果知道这个对象的id,那直接用find找出对象修改即可
irb(main):018:0> Account.find(1).update(name:"可爱的猫宁")
=> true
#查询符合条件的account对象集合,修改名字为"可爱的狗宁"
irb(main):019:0> Account.where(name:"狗宁").update_all(name:"可爱的狗宁")
=> true
(4)删除数据
- 删除一个对象用delete,删除成功后返回这个被删除的对象
- 删除对象集合用delete_all,删除成功后返回删除的个数
- 在实际项目中一般不用delete或者delete_all删除数据,因为这样删除的数据是不可恢复的。
#删除第一个name为"可爱的猫宁"的对象
irb(main):019:0> Account.where(name:"可爱的猫宁").first.delete
=> #<Account id: 1, name: "可爱的猫宁", email: "12345@qq.com", password: nil, role: nil, status: nil, created_at: "2018-12-26 15:55:30", updated_at: "2018-12-28 10:18:34">
#删除符合name为"可爱的狗宁"条件的对象集合。
irb(main):020:0> Account.where(name:"可爱的狗宁").delete_all
=> 1
(5)数据排序
#将查询结果根据创建时间正序排序
Account.where(name:"猫宁").order(created_at: :asc)
#将查询结果根据创建时间倒序排序
Account.where(name:"猫宁").order(created_at: :desc)
#将查询结果先根据创建时间倒序排序,再根据修改时间正序排序
Account.where(name:"猫宁").order(created_at: :desc,updated_at: :asc)
(6)数据分组及相关应用
#将account数据根据email、name的值分组
Account.where(name:"猫宁").group(:email,:name)
#返回一个哈希。key为email name值的数组,value为对应数据的条数
Account.where("name like '%管理员%'").group(:email,:name).count
=> {["123456781@qq.com", "管理员2"]=>1, ["123456782@qq.com", "管理员3"]=>1, ["12345678@qq.com", "管理员1"]=>1}
(7)其他常用方法
1)map,返回对应字段的数组
irb(main):023:0> Account.where("name like '%管理员%'").collect(&:name)
=> ["管理员1", "管理员2", "管理员3"]
2)select,只返回想要展示的字段
irb(main):025:0> Account.where("name like '%管理员%'").select("name,email")
=> #<ActiveRecord::Relation [#<Account id: nil, name: "管理员1", email: "12345678@qq.com">, #<Account id: nil, name: "管理员2", email: "123456781@qq.com">, #<Account id: nil, name: "管理员3", email: "123456782@qq.com">]>