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)我们先写一下这个表需要哪些字段,表结构如下:
(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