guides[1]

目录部分

The Rails Command Line

model
Active Record Basics
Active Record Migrations
Active Record Validations
Active Record Callbacks
Active Record Associations
Active Record Query Interface
Active Model Basics

controllers
Action Controller Overview
Rails Routing from the Outside In

digging deeper
Active Job Basics
The Asset Pipeline

正文部分
The Rails Command Line



rails server -e production -p 4000 #指定环境和端口
rails new demo --database=mysql #指定数据库
rails g scaffold Article name:string #使用scaffold,资源为单数形式
rails g controller Articles index #使用controller为复数形式
rails g model Article name #使用model为单数形式

#和其他表格进行关联,tag has_many artilces
rails g modle Artilce name:string tag:references

#升级到rails5.0之后,之前的rake命令变为rails命令(成为默认的执行命令)
rake routes => rails routes
rake demo.rake =>rails demo.rake #执行rake任务,在lib/tasks中

Active Record Basics
model和数据库名称要相互对应

#普通单数形式
model:Article   #首字母大写
database:articles

#非普通单数形式
model:Person
database:people

#多字段形式
model:LineItem  #camelcase形式
database:line_items

主键和外键

主键:id,自动生成
外键:singularized_table_name_id,比如article_id

#在命名终端生成主键和外键
rails g model Article name:string #自动生成主键id
rails g model Comment name:string article:references #生成外键article_id(注意格式)

Active Record Migrations
创建表单和字段,删除表单

#rails g model Product name:string

#生成表单和字段
class CreateProducts < ActiveRecord::Migration[5.0]
  def change
    create_table :products do |t|
      t.string :name
      t.timestamps
    end
  end
end

#rails g migration remote_product
class RemoteProcut < ActiveRecord::Migration[5.0]
  def change
    drop_table :prefaces
  end
end

生成字段、删除字段

#默认已经有articles这个表单,生成name字段
#rails g migration addnametoarticle
class Addnametoarticle < ActiveRecord::Migration[5.0]
  def change
    add_column :articles, :name, :string
  end
end

#删除字段
#rails g migration removenameformarticle
class Addnametoarticle < ActiveRecord::Migration[5.0]
  def change
    remove_column :articles, :name, :string
  end
end

增加索引,删除索引

#默认已经有articles的name字段
#rails g migration addindextoname
class Addindextoname < ActiveRecord::Migration[5.0]
  def change
    add_index :articles, :name
  end
end

#查看数据中那些字段存在索引
show index from articles
#查看指定字段是否存在索引
show index from articles where column_name like 'name'

#删除索引
class Removeindex < ActiveRecord::Migration[5.0]
  def change
    remove_index :articles, :name
  end
end

建立关联和删除关联

#比如已经有artilces,需要实现article has many tags,因此建立tag model 最简单的关联:
rails g model Tag name:string article:references
#上面在tags表中会出现article_id这个字段

#使用migration进行references
rails generate migration AddUserRefToProducts user:references

class AddUserRefToProducts < ActiveRecord::Migration[5.0]
  def change
    add_reference :products, :user, index: true, foreign_key: true
  end
end

#删除关联
自己没有实现

Active Record Callbacks
callback是指回调的意思,当对象状态改变的时候,这些回调方法会被触发,对象的状态有三种,create,update,destroy,回调的方法调用形式如下:

#第一种,使用预定义的回调函数,里面定义块的内容
class User < ApplicationRecord
  before_validation do |user|
    puts "this is the test"
  end
end

#第二种,使用预定义的回调函数注册回调方法
class User < ApplicationRecord
  before_validation :test
  #可以指定某个action上使用验证
  before_validation :test, on: :create
  #可以指定多个action上使用验证
  before_validation: test, on: [:create, :update]

  private
    def test
      puts "this is the test"
    end
end

对象改变触发的回调函数如下:

#当create时
before_validation
after_validation
before_save
around_save
after_save
before_create
around_create
after_create
after_commit/after_rollback

#当update时
before_validation
after_validation
before_save
around_save
after_save
before_update
around_update
after_update
after_commit/after_rollback

#当destroy时
before_destroy
around_destroy
after_destroy
after_commit/after_rollback

#initialize
after_initialize #对象初始化和从数据库中load对象时触发

#find
after_find #从数据库中load对象时触发

#touch
after_touch #对象进行touch时触发

具体的触发和不触发方法的动作

#create, update, destroy
create
create!
decrement!
destroy
destroy!
destroy_all
increment!
save
save!
save(validate: false)
toggle!
update_attribute
update
update!
valid?

#find
all
first
find
find_by
find_by_*
find_by_*!
find_by_sql
last

#跳过触发动作
decrement
decrement_counter
delete
delete_all
increment
increment_counter
toggle
touch
update_column
update_columns
update_all
update_counters

Active Record Query Interface
获得单个值

find #通过id获得值,也通过通过id数组获得值
Article.find(1)
Article.find([1,2]) #Article.find(1,2)也是可以的

take #没有知名排序取值
Article.take #默认取1个值
Article.take(2) #取两个值

first #默认按照id的升序取第一个值
Article.first #如上
Article.first(3) #取前三个值
Article.order(:name).first #改变默认排序,取第一个值

last #默认按照id的降序取第一个值
Artilce.last
Artilce.last(3)
Article.order(:name).last

find_by #通过相应的字段属性取值
Article.find_by(name: "jayzen")

处理大数据量的情况,目的是避免超出内存容量

#方法依次是
find_each
find_in_batch

#可选的参数包括
batch_size
start
finish

#两者的区别
find_each #每次数据传递一部分
find_in_batch #数据一次性传递,但是按照数组块的形式

使用where进行条件查询

#纯字符查询会出现SQL注入问题,不采用
Client.where("orders_count = '2'")

#数组查询
#单个数组查询
Client.where("orders_count = ?", params[:orders])
#多个数组查询
Client.where("orders_count = ? AND locked = ?", params[:orders], false)
#使用占位符进行数组查询
Client.where("created_at >= :start_date AND created_at <= :end_date",
  {start_date: params[:start_date], end_date: params[:end_date]})

#使用hash条件查询
#单个hash值
Client.where(locked: true)
#范围hash值
Client.where(created_at: (Time.now.midnight - 1.day)..Time.now.midnight)
#数组hash值
Client.where(orders_count: [1,3,5])

#使用not条件查询
Client.where.not(locked: true)

使用order进行排序

#单个字段使用order进行排序,并且使用desc或者asc指定排序方式
Article.order(name: :desc)

#多个字段使用order进行排序
Article.order(name: :desc, content: :asc)

#使用链式排序
Article.order(name: :desc).order(content: :asc)

使用select选择特定的字段

#只选择两个字段内容
Article.select("name, content")

#选择字段的属性内容,不重复出现
Article.select("name").distinct

使用limit和offset指定返回的个数和开始的位置

Article.limit(5) #最多返回5条记录,默认返回最初的5条
Article.limit(5).offset(30) #从第31条开始返回记录,最多返回5条记录

使用group进行分组

#获得某一个时间点的订单数量
Order.select("date(created_at) as ordered_date, sum(price) as total_price").group("date(created_at)")

#统计不同状态值的累计量
Order.group(:status).count

使用having进行条件判断

Order.select("date(created_at) as ordered_date, sum(price) as total_price").group("date(created_at)").having("sum(price) > ?", 100)

对条件进行改变

#unscope取消条件
Article.where('id > 10').limit(20).order('id
asc').unscope(:order) #取消order条件

#使用only重新制定选择条件
Article.where('id > 10').limit(20).order('id desc').only(:order, :where)

#使用reorder进行条件重新制定
class Article < ApplicationRecord
  has_many :comments, -> { order('posted_at DESC') }
end
Article.find(10).comments.reorder('name')

#使用reverse_order改变排列的方式
Client.where("orders_count > 10").order(:name).reverse_order

#使用rewhere改变where的排列方式
Article.where(trashed: true).rewhere(trashed: false)

返回空值

Article.none #返回空值

设置对象可读,在写入的时候会报错

client = Client.readonly.first
client.visits += 1
client.save #会报错ActiveRecord::ReadOnlyRecord exception

数据库中实现join(inner join)和left join的区别
方式和rails中的joins和left_outer_joins一致

#join(inner join)
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
INNER JOIN Orders
ON Persons.Id_P = Orders.Id_P
ORDER BY Persons.LastName
#结果:返回的完全匹配的值,即是必须满足Persons.Id_P = Orders.Id_P

#left join(left outer join)
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
LEFT JOIN Orders
ON Persons.Id_P=Orders.Id_P
ORDER BY Persons.LastName
#首先返回Persons.Id_P = Orders.Id_P的值,如果Orders.Id_P不存在,则只返回左表中的值即可。

悲观锁(pessimistic lock)和乐观锁(optimistic lock)
optimistic lock:认为冲突比较少,用户在检查的更新的检查lock_version的值时候变动,变动即返回错误。应用在实际冲突比较少的场景。举例:rails中model表单存在可选的lock_version字段。
pessimistic lock:认为每一次更新都存在冲突,都有一个锁定和开锁的过程,这样子程序开销比较大,引用在冲突比较多的场景。

Rails Routing from the Outside In
作用:链接url到code;生成url
1、resource routing
resources :photos(复数资源)

GET /photos             photos#index    photos_path
GET /photos/new      photos#new      new_photo_path
POST    /photos         photos#create  
GET /photos/:id      photos#show
GET /photos/:id/edit    photos#edit     edit_photo_path(:id)
PATCH/PUT   /photos/:id   photos#update
DELETE  /photos/:id   photos#destroy  photo_path(:id)

上面提到的都是复述资源,下面讲述单数资源
resource :geocoder

GET       /geocoder/new geocoders#new  new_geocoder_path
POST         /geocoder  geocoders#create    
GET       /geocoder geocoders#show  geocoder_path
GET       /geocoder/edit    geocoders#edit edit_geocoder_path
PATCH/PUT   /geocoder   geocoders#update    
DELETE     /geocoder    geocoders#destroy

对于单例资源生成表格,需要制定url

form_for @geocoder, url: geocoder_path do |f|
...

对于namespace路由、嵌套路由、浅嵌套(shallow nesting)在文档中有叙述,但是自己用到的不多,所以遇到的时候在参考guides即可。Routing concerns是将常用到的路由打包,以备后用。
增加的三个restful形式的路由

#member
resources :photos do
  member do
    get 'preview'
  end
end
=>/photos/1/preview
preview_photo_url
params[:id]

#collection
resources :photos do
  collection do
    get 'search'
  end
end
=>/photos/search
search_photos_url

#new
resources :comments do
  get 'preview', on: :new
end
#/comments/new/preview
preview_new_comment_path

2、non resourceful routes

Active Job Basics
应用场景:在用邮箱注册的过程中,给邮箱发送邮件这个动作应该放在后台进行。
active job可以使用的adapter有很多,比如delayed job,resque和sidekiq,后两者需要安装redis,其中sidekiq是在resque基础上的改进,但是性能方面要优于resque,但是sidekiq的过程中要注意线程安全问题。
active job的其中一个adapter是sidekiq,而这个软件需要安装redis。
其中redis的安装和启动过程如下:

#目前redis的版本是3.2
brew install redis
#启动redis
redis-server /usr/local/etc/redis.conf

其中sidekiq的安装和启动的过程如下:

#安装就是添加gem
gem 'sidekiq'
#启动就是终端输入如下代码
sidekiq

项目启动之前要同时启动redis和sidekiq,下面执行代码中内容:

#生成scaffold
rails g scaffold Article name:string

#生成job文件
rails g job add_article

#修改jobs/add_artilce_job.rb文件
class AddArticleJob < ApplicationJob
  queue_as :default

  def perform(*args)
    sleep 10
    10.times do |index|
      article = Article.new
      artilce.name = "name#{index}"
      article.save
    end
end

#修改app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  def index
    AddArticleJob.perform_later
    @articles = Article.all
  end
end

在没有使用sidekiq作为adapter的情况下,会使用Active Job Inline作为默认的adapter,但是这adapter不是异步的,按照代码执行顺序进行延后,但是如果采用sidekiq作为adapter的情况,可以异步,只需要进行如下的配置:

module JobDemo
  class Application < Rails::Application
    config.active_job.queue_adapter = :sidekiq
  end
end

可以通过log的代码关注执行情况,

The Asset Pipeline
首先需要关注的是css文件和javascript文件如何进行组织的问题。
assets/stylesheets/application.css文件内容

/*
  * This is a manifest file that'll be compiled into application.css, which will include all the files
  * listed below.
  * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
  * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
  * You're free to add application-wide styles to this file and they'll appear at the bottom of the
  * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
  * files in this directory. Styles in this file should be added after the last require_* statement.
  * It is generally better to create a new file per style scope.
  *
  *= require_tree .
  *= require_self
  */

assets/stylesheets/application.js文件

 // This is a manifest file that'll be compiled into application.js, which will include all the files
 // listed below.
 // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
 // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
 // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
 // compiled file. JavaScript code in this file should be added after the last require_* statement.
 //
 // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
 // about supported directives.
 //
 //= require jquery
 //= require jquery_ujs
 //= require turbolinks
 //= require_tree .

上文分别给出了application.js和application.css的说明,其中

 //= require jquery
 //= require jquery_ujs
 //= require turbolinks

会从三个地方寻找对应的文件,分别是app/assets,lib/assets和vender/assets三个文件夹中,require_tree .。表示在app/assets文件中js和css文件会被自动合并到application.css或者application.js文件中,在lib/assets和vender/assets中的文件除非在application.js或者application.css文件中按照如上的方式被引入,不然无效。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容