Query返回两类对象实例:
#第一类是ActiveRecord::Relation 实例, 包括where,group等
Article.where(["title=?", "demo"]).class #=>Article::ActiveRecord_Relation
#第二类是Array实例,Array中每个对象都是model的实例,代表包括:find,first
Article.first.class #=>Article
Article.first(3).class #=>Array
Article.first(3)[0].class #=>Article
?两个多查询方方法的源码分析和总结,其中可以总结Numerator模块方法
#少数据查询
Article.find(1) #查询多个是Article.find([1,2])
Article.take #默认查询任意一条,查询多条为Article.take(3)
Article.first #默认按照id的升序排序,获得升序的第一位
Article.last #默认按照id的降序排序,获得降序的第一位
Article.find_by(name: "demo") #获取任意满足条件的一条值
#find_by和find的区别
User.find(params[:id]) #不存在,会报错, ActiveRecord::RecordNotFound: Couldn't find Article with 'id'=1
User.find_by(id: params[:id]) #不存在,结果为nil
#多查询语句,find_in_batches把一批记录作为模型数组传入块,find_each逐一把每条记录作为模型传入块
find_each
find_in_batches
条件查询
#使用where进行条件查询,参数选择包括字符串,数组和hash
#使用字符串进行查询,就是where后面是纯粹sql语句
Article.where("title='demo'") # sql: select * from article where(title='demo')
Article.where("title='demo' and content='demo'") #sql: select * from article where(title='demo' and content='demo')
Article.where("title='demo' or content='demo'") #sql: select * from article where(title='demo' or content='demo')
#使用数组进行查询
Article.where(["title = ?", "title_demo"]) #单个查询字段
Article.where(["title = ? and content= ?", "title_demo", "content_demo"]) #多个字段
#下面使用hash形式代替“?”,如果指向同一个hash,那么可以节约代码
Article.where(["title = :title_name and content= :content_name", { title_name: "title", content_name: "content" }])
Article.where(["title = #{params[:title]}"]) #下面的代码会产生sql注入,不建议使用
#使用hash进行查询
Article.where(published: true)
Article.where("published" => true) #查询的key可以使用字符串形式
Article.where(title: :demo) #查询会出错,value不可以使用symbol形式
Article.joins(:comments).where(comments: {name: "demo"}) #association中使用hash的形式
Article.where(created_at: (Time.now.midnight - 1.day)..Time.now.midnight) #使用range查询
Article.where(id: [1,3,5]) #使用subset查询
#使用not条件查询
Article.where.not(published: true)
#使用or条件查询
Article.where("title='demo'").or(Article.where("content='demo'")) #or只有在同一个model的情况才能被使用
#like查询
Article.where(["name like ?", "%#{params[:term]}%"])
多字段查询
#Article中有两个字段,分别为title和content,在唯一的输入框中输入变量,分别模糊查询这个model的两个字段
#简单实现方式,出现问题:sql注入,不可扩展,controller中太多逻辑查询代码
#routes.rb
Rails.application.routes.draw do
resources :articles do
collection do
get 'search'
end
end
end
#view
<%= form_tag '/articles/search', method: :get do %>
<%= text_field_tag :search %>
<%= submit_tag "submit"%>
<% end %>
#articles_controller.rb
def search
@articles = Article.where("title like '%#{params[:search]}%'").or(
Article.where("content like '%#{params[:search]}%'"))
render 'index'
end
#比较成熟的解决方式,避免sql注入,具备扩展功能,逻辑代码防止在model层中,以下为改进后的代码
#routes.rb和view中的代码不做变化,改变model和controller中的代码
#articles_controller.rb
def search
@articles = Article.search(params[:search])
render 'index'
end
#article.rb,where中使用纯粹的sql语句
class Article < ApplicationRecord
def self.search(args)
if args
args.strip!
search_fields = %w(title content)
search_conditions = []
search_fields.each do |search_field|
search_conditions << "#{search_field} like :search"
end
Article.where(search_conditions.join(' or '), { search: "%#{args}%"})
else
Article.all
end
end
end
使用arel进行条件查询
#arel的作用
是一种抽象的查询方式,目的是处于对一些复杂查询的简化
#arel的基本用法,arel是rails内置的,不需要添加gem,gemfile.lock中可以查看
@articles = Article.arel
Article.where(@articles[:title].eq("demo")) #title值等于demo
Article.where(@articles[:title].matched("%demo%")) #tilte值like %demo%
Article.where(@articles[:title].matches("demo").or(@articles[:content].matches("demo")))#使用or
#使用arel对上面的多重查询进行改写
class Article < ApplicationRecord
def self.search(search)
if search
search.strip!
search_fields = %w(title content)
condition = search_fields.map do |field|
arel_table[field].matches("%#{search}%")
end.inject(:or)
where(condition)
else
all
end
end
end
使用scope方法
#作用
数据的查询方式在model中定义,controller中直接获取model中定义的scope方法
#常规的scope定义
class Article < ApplicationRecord
#通过scope定义进行定义
scope :published, -> { where(published: true) }
#通过类方法进行定义
def self.published
where(published: true)
end
end
#传入参数
scope :created_before, ->(time) { where("created_at < ?", time) }
#使用条件
scope :created_before, ->(time) { where("created_at < ?", time) if time.present? }
#使用默认的scope
default_scope { where("removed_at IS NULL") }
#合并scope
scope :active, -> { where state: 'active' }
scope :inactive, -> { where state: 'inactive' }
User.active.inactive
#删除scope
Client.unscoped.all
进行order排序
#排序字段的选择,symbol和string
#desc(descend 下降) asc(ascend 上升)
Client.unscoped.all
Article.order("title")
Artilce.order(:title)
#排序方式,升序asc和降序desc
Article.order(title: :desc) #或者Article.order("title desc")
Article.order(title: :asc)
#多个字段排序
Article.order(title: :desc, content: :asc)
Article.order(title: :desc).order(content: :asc)
字段选择
#单个字段
Article.select(:title) #或者Article.select("title")
#多个字段
Article.select(:title, :content)
#选择的字段唯一
Article.select(:title).distinct
Article.select(:title).distinct.distinct(false) #去除唯一性
设定取出数量和开始字段
#取出前5个字段
Article.limit(5)
#从第五个开始取5个字段
Article.limit(5).offset(5)
计算
rails g migration add_mount_to_articles mount:integer
Article.count #计算Article的记录
Article.count(:title) #计算Article.title中存在的记录
Article.average(:mount).to_f
Article.maximum(:mount)
Article.minimum(:mount)
Article.sum(:mount)
todo: enum的使用