ActiveRecord入門(構文の概要をつかむ用)

□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を使います。


Warning: Undefined array key "thumbnail_url" in /home/users/1/boy.jp-rolpop/web/skc/wp-content/themes/godios/inc/schema-org.php on line 49

Warning: Undefined array key "thumbnail_url" in /home/users/1/boy.jp-rolpop/web/skc/wp-content/themes/godios/inc/schema-org.php on line 78