□active record概要
ruby on rails: ruby on railsの一部として開発されている
or mapper (object – RDB)
単体で使うこともできる
active recordの概要はこんなかんじのようですが、プログラマーじゃないので正直つかいどころがわかりません。しかしRailsをちょっとさわったことがあるひとならわかるかもしれません。railsのシェルで入力していた構文はactive recordの構文だったのです。
とりあえずこの記事では構文を中心に書いていますが、非プログラマーが書いているのでコードの内容は保証しません。
目次
準備
activerecordのgemがあるか確認します
$ gem list activerecord
gemがなかったらインストールします
$ sudo gem install activerecord
sqliteのgemもインストールしておきます
$ sudo gem install sqlite3
sqlite3でテーブルを作成しておく
create table users( id integer primary key, name text, age integer, created_at, updated_at );
ActiveRecordの設定とデータベースを使用するひながた
require 'active_record' require "active_support/all" require 'pp' Time.zone_default = Time.find_zone! 'Tokyo' ActiveRecord::Base.default_timezone = :local ActiveRecord::Base.establish_connection( "adapter" => "sqlite3", "database" => "./myapp.db" ) #Userはここでは単数形にする必要がある class User < ActiveRecord::Base end user = User.new user.name = "tanak" user.age = 23 user.save #user = User.new(:name=>"hayasi", :age=>25) user = User.new(name: "hayasi", age: 25) User.create(name: "hosi", age: 22)
Time.zoneの調整でエラーになる可能性があるのでrequire “active_support/all”もいれておきます
ブロックを使ってインスタンスを作る方法
user = User.new do |u| u.name = "tanaka" u.age = 18 end
ログを出力したい場合
ロガーの設定は必須かと思います
require 'active_record' require 'logger' # # ActiveRecord::Base.logger = Logger.new(STDOUT)
レコードの抽出
ppがないとデータの確認がしにくくなるのでrequireしておきます
require pp
全件抽出
pp User.all
カラムを指定して抽出(ダブルクォーテーションがついていることに注意)
pp User.select("id, name, age").all
最初と最後のレコードを抽出する
pp User.select("id, name, age").first pp User.select("id, name, age").last
最初の3件最後の3件を取得する
pp User.select("id, name, age").first(3) pp User.select("id, name, age").last(3)
抽出条件
idが1の人を抽出する。idが1の人のカラムを指定して抽出する
pp User.find(1)
pp User.select(“id, name, age”).find(1)
条件に名前を指定する場合はfind_byを使います。idにも使うことができます
pp User.find_by(name: "tanaka") pp User.select("id, name, age").find_by(name: "tanaka") pp User.select("id, name, age").find_by(id: 1)
存在しないレコードを指定したときにエラーを返すには命令に!をつけます
pp User.select("id, name, age").find_by!(id: 10)
whereを使った条件抽出
pp User.select("id, name, age").where(age: 20..29) pp User.select("id, name, age").where(age: [30, 35])
演算子は以下のようなものがあります
andornot
pp User.select("id, name, age").where("age >= 30 and age < 30") pp User.select("id, name, age").where("age >= 30 or age < 30") pp User.select("id, name, age").where.not(id: 3)
whereで変数を使うには直接値をうめこんではいけないので、?を使う方法もしくはシンボルを使う方法があります
min = 20; max = 35 pp User.select("id, name, age").where("age >= ? and age <= ?", min, max)
シンボルを使う方法
min = 20; max = 35 pp User.select("id, name, age").where("age >= :min and age <= :max", min: min, max: max) pp User.select("id, name, age").where("age >= :min and age <= :max", {min: min, max: max})
like
like演算子はワイルドカードを指定することができます。変数を使う場合と同様でプレースフォルダー。(?記号のこと)を使う必要があります。
ワイルドカードはSQL文と同じようにspan calss=”m”>%と_を使用することができます
- %⇀ すべてに何文字でも
- _⇀ 任意の一文字
pp User.select("id, name, age").where("name like ?", "%i") pp User.select("id, name, age").where("name like ?", "__r__")
order, limit, offset
ActiveRecordのならびかえはorder byではなくorderを使います。
pp User.select("id, name, age").order("age") pp User.select("id, name, age").order(:age) pp User.select("id, name, age").order("age desc") pp User.select("id, name, age").order(age: :desc)
limitを使うと何件抽出してくるかを指定することができます
pp User.select("id, name, age").order("age").limit(3)
offsetを使うと途中から〇件文データをひっぱってくることができます。
pp User.select("id, name, age").order("age").limit(3).offset(3)
抽出条件を登録する
抽出条件を登録する方法はclassmethodを使用する方法とscopeを使用する方法があります。
scopeもclassmethodもclassの中に書きます
# # class User < ActiveRecord::Base #class method def self.top3 select("id, name, age").order("age").limit(3) end #scope scope :top3, -> {select("id, name, age").order("age").limit(3)} end # #
クラスメソッドには引数をもたせることもできます
# # class User < ActiveRecord::Base #class method def self.top(num) select("id, name, age").order("age").limit(num).offset(num) end end # # pp User.top(3);
scopeの場合は以下のようになります
# # class User < ActiveRecord::Base scope :top, ->(num) {select("id, name, age").order("age").limit(num)} end # # pp User.top(3);
レコードの挿入
もしそのレコードが存在しなかったらあらたに挿入するという命令はfind_or_create_by()という命令を使います。
user = User.find_or_create_by(name: "hayasi")#レコードがなかったら挿入される pp user #確認する pp User.all
他の値を埋めたいときはそのまま追加することもどきます。ブロックで書くこともできます。
ただしfind_or_create_byは値の更新には向いていません。データの更新はupdateを使います
user = User.find_or_create_by(name: "wakabayasi", age: 30) user = User.find_or_create_by(name: "wakabayasi") do |u| u.age = 30 end
レコードの更新
update
レコードの更新はupdateを使い条件指定をするにはwhereを使います。whereで先に条件指定していますが、
updateとwhereの順番を逆にするとエラーになります。
User.update(1, age: 50) pp User.select("id, name, age").all User.where(name: "aosima").update(age: 60) pp User.select("id, name, age").all User.where(name: "aosima").update(age: 30, name: "kuroda") #複数の項目を更新する User.where("age >= 20").update(age: 90) #複数のレコードを更新することも可能 pp User.select("id, name, age").all
update_all
update_allは引数に式を書くことができます。update_allはvalidationを設定することができません
User.where("age >= 20").update_all("age = age + 2")
データ削除
データの削除する命令はdeleteとdestroyがあるようですが、この違いはActiveRecordのオブジェクトを介するか介さないかの違いのようです。
User.delete(1) # id1を削除する User.where("age > 30").delete_all # 30歳より上の人を削除 pp User.select("id, name, age").all
validation
validationは制限のことです。validationはclassの中に記述すればよいようです。presenceは空の値を許さない。lengthで最小文字数や最大文字数を設定することができます
# # class User < ActiveRecord::Base validates :name, :age, presence: true validates :name, length: {minimum: 3} end # # User.create!(name: nil, age: nil)
validationのエラーメッセージを取得するには errors.messagesを使います
if !user.save pp user.errors.messages end
callback
callbackはなにか処理をおこなったときにメソッドが呼び出される仕組みです。callbackはあらかじめたくさん用意されているようです
after_destroyというコールバックを使ってみます
# # class User < ActiveRecord::Base after_destroy :print_after_msg protected def print_after_msg puts "#{self.name} deleted" end # # User.where("age > 20").destroy_all
association
associationはテーブルを紐づけるための仕組みです
以下はusersテーブルとcommentsテーブルを1対多の関係にしています。
# # class User < ActiveRecord::Base has_many :comments end class Comment < ActiveRecord::Base belongs_to :user end # #
紐づけを行った状態でincludeを使うともう片方の情報もひっぱってくることができるようになります
user = User.includes(:comments).find(1) # pp user.comments user.comments.each do |c| puts "#{user.name}: #{c.body}" end comments = Comment.includes(:user).all comments.each do |c| puts "#{c.body} by #{c.user.name}" end
Userを削除したときにコメントも一緒に削除するには dependent: :destroyを設定してやります
# # class User < ActiveRecord::Base has_many :comments, dependent: :destroy end # # User.find(1).destroy #ユーザーを削除したときにコメントも一緒に削除する
dependent: :destroyを設定した上でdeleteを使ってもコメントは削除されないので注意が必要です。関連したオブジェクトを削除するにはdestroyを使います。