RailsによるアジャイルWebアプリケーション開発
第19章 続き
表示についてはhirbを使ってみた。
.pryrcに設定が必要。
FAQ · pry/pry Wiki · GitHub
CRUD
- create は attributes の配列渡すことで複数件同じ登録が可能
- find_by_attribute_name って廃止されたかと思っていたが、されていなかった(DEPRECATEDも出ない)
- find_or_initialize_by は attributes_name を続けて書くことは出来ないので、引数で指定
[5] pry(main)> User.where("(name like :name1 and name like :name2) or name = :name3", name1: "%A%", name2: "%S%", name3: "Mable Kutch") User Load (1.0ms) SELECT "users".* FROM "users" WHERE ((name like '%A%' and name like '%S%') or name = 'Mable Kutch') +----+----------------------+-----------------------------+-------------------------+-------------------------+ | id | name | email | created_at | updated_at | +----+----------------------+-----------------------------+-------------------------+-------------------------+ | 21 | Mrs. Tatum Gislason | laura@example.net | 2015-01-30 10:26:09 UTC | 2015-01-30 10:26:09 UTC | | 24 | Vincenzo Jacobs | antonina@example.net | 2015-01-30 10:26:10 UTC | 2015-01-30 10:26:10 UTC | | 25 | Mable Kutch | darlene@example.org | 2015-01-30 10:26:10 UTC | 2015-01-30 10:26:10 UTC | | 26 | Ms. Sonia Wehner | jillian.goodwin@example.com | 2015-01-30 10:26:10 UTC | 2015-01-30 10:26:10 UTC | | 27 | Sarah Bailey | stacy_haag@example.com | 2015-01-30 10:26:10 UTC | 2015-01-30 10:26:10 UTC | | 30 | Miss Agustin Kuvalis | alana_cassin@example.com | 2015-01-30 10:26:10 UTC | 2015-01-30 10:26:10 UTC | +----+----------------------+-----------------------------+-------------------------+-------------------------+ 6 rows in set
- joinsメソッド(INNER JOIN)を使用すると、saveが使えない(readonly)そうだけど、普通に更新できちゃう
[6] pry(main)> u = User.joins(:books).first User Load (0.6ms) SELECT "users".* FROM "users" INNER JOIN "book_shelves" ON "book_shelves"."user_id" = "users"."id" INNER JOIN "books" ON "books"."id" = "book_shelves"."book_id" ORDER BY "users"."id" ASC LIMIT 1 +----+---------------------+-------------------+-------------------------+-------------------------+ | id | name | email | created_at | updated_at | +----+---------------------+-------------------+-------------------------+-------------------------+ | 21 | Mrs. Tatum Gislason | laura@example.net | 2015-01-30 10:26:09 UTC | 2015-01-30 10:26:09 UTC | +----+---------------------+-------------------+-------------------------+-------------------------+ 1 row in set [7] pry(main)> u.name = Faker::Name.name => "Kellie Muller II" [8] pry(main)> u.save (0.3ms) begin transaction SQL (0.7ms) UPDATE "users" SET "name" = ?, "updated_at" = ? WHERE "users"."id" = ? [["name", "Kellie Muller II"], ["updated_at", "2015-01-30 10:43:15.210122"], ["id", 21]] (119.8ms) commit transaction => true [9] pry(main)> u.reload User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 21]] +----+------------------+-------------------+-------------------------+-------------------------+ | id | name | email | created_at | updated_at | +----+------------------+-------------------+-------------------------+-------------------------+ | 21 | Kellie Muller II | laura@example.net | 2015-01-30 10:26:09 UTC | 2015-01-30 10:43:15 UTC | +----+------------------+-------------------+-------------------------+-------------------------+ 1 row in set
- lockについては各種DBについて意識する必要はありそう
- grouping
depotで使用したOrderにカラムを追加するような形なので、別プロジェクト作ってモデル作製し試した。
ffakerだとFaker::Address.state_abbrが使えなかったのでfakerに。
- 検索+集約関数
[9] pry(main)> Order.where("amount > 20").minimum(:amount) (0.3ms) SELECT MIN("orders"."amount") FROM "orders" WHERE (amount > 20) => 22
- 集約関数とorder, limit
[11] pry(main)> result = Order.group(:state).order("max(amount) desc").limit(3) Order Load (0.5ms) SELECT "orders".* FROM "orders" GROUP BY state ORDER BY max(amount) desc LIMIT 3 +----+-------------------+------------------+----------------------------+----------+-------+--------+-------------------------+-------------------------+ | id | name | address | email | pay_type | state | amount | created_at | updated_at | +----+-------------------+------------------+----------------------------+----------+-------+--------+-------------------------+-------------------------+ | 20 | Virginie Bernier | North Clinthaven | amos.bechtelar@example.org | 現金 | KS | 93 | 2015-01-30 10:52:22 UTC | 2015-01-30 10:52:22 UTC | | 17 | Vallie Hamill III | East Brycen | evans@example.org | 現金 | PA | 49 | 2015-01-30 10:52:22 UTC | 2015-01-30 10:52:22 UTC | | 19 | Mohammad Hickle | New Vaughnburgh | bailey_morar@example.org | カード | WV | 93 | 2015-01-30 10:52:22 UTC | 2015-01-30 10:52:22 UTC | +----+-------------------+------------------+----------------------------+----------+-------+--------+-------------------------+-------------------------+
- scope
class Order < ActiveRecord::Base PAY_TYPES = %w(現金 カード 注文書) scope :last_n_days, ->(days) { where('updated_at < ?', days) } scope :checks, -> { where(pay_type: "現金") } end
[3] pry(main)> Order.last_n_days(Time.now) Order Load (0.3ms) SELECT "orders".* FROM "orders" WHERE (updated_at < '2015-01-30 11:04:43.263452') [4] pry(main)> Order.checks Order Load (0.2ms) SELECT "orders".* FROM "orders" WHERE "orders"."pay_type" = ? [["pay_type", "現金"]]
- delete と destory
- delete はコールバックと検証機能を迂回
- コールバック
- after_findの空メソッドは作る必要無し
- config/initializers/encrypter.rb
class ActiveRecord::Base def self.encrypt(*attr_names) encrypter = Encrypter.new(attr_names) before_save encrypter after_save encrypter after_find encrypter end end
- app/models/order.rb
class Order < ActiveRecord::Base PAY_TYPES = %w(現金 カード 注文書) before_validation CreditCardCallbacks.new after_create do |order| logger.info "after_create 注文 #{order.id} が作製されました" end scope :last_n_days, ->(days) { where('updated_at < ?', days) } scope :checks, -> { where(pay_type: "現金") } encrypt(:name, :email) end
- 実行
[3] pry(main)> Order.all Order Load (0.2ms) SELECT "orders".* FROM "orders" +----+------------------+------------------+------------------------------+----------+-------+--------+-------------------------+-------------------------+------------------+ | id | name | address | email | pay_type | state | amount | created_at | updated_at | cc_number | +----+------------------+------------------+------------------------------+----------+-------+--------+-------------------------+-------------------------+------------------+ | 1 | Merlin Langosh V | East Elouiseport | hazel.hane@example.net | 注文書 | IL | 87 | 2015-01-30 12:05:41 UTC | 2015-01-30 12:05:41 UTC | 1212122111211234 | | 2 | Jody Hamill | New Hayliefort | vivien_heathcote@example.org | 現金 | WV | 39 | 2015-01-30 12:05:41 UTC | 2015-01-30 12:05:41 UTC | 1234212112211211 | | 3 | Marguerite Beier | North Ruthe | elinor.wehner@example.org | カード | MD | 66 | 2015-01-30 12:05:41 UTC | 2015-01-30 12:05:41 UTC | 1211122112342201 | | 4 | Bette Steuber | East Helentown | dale_kautzer@example.org | 現金 | FL | 6 | 2015-01-30 12:05:41 UTC | 2015-01-30 12:05:41 UTC | 1234212112211211 | | 5 | Otto Kling | Lillianborough | patience.okuneva@example.com | カード | RI | 81 | 2015-01-30 12:05:41 UTC | 2015-01-30 12:05:41 UTC | 1212122111211234 | +----+------------------+------------------+------------------------------+----------+-------+--------+-------------------------+-------------------------+------------------+ 5 rows in set
% sqlite3 -line db/development.sqlite3 "select name, email from orders" name = Mfsmjo Lbohpti V email = ibafm.ibof@fybnqmf.ofu name = Jpez Hbnjmm email = wjwjfo_ifbuidpuf@fybnqmf.psh name = Mbshvfsjuf Bfjfs email = fmjops.xfiofs@fybnqmf.psh name = Bfuuf Sufvcfs email = ebmf_lbvuafs@fybnqmf.psh name = Ouup Kmjoh email = qbujfodf.plvofwb@fybnqmf.dpn
- オブザーバ
Rails4では別Gemに。
rails/rails-observers · GitHub
Observerというより、AOPを実現するための方法か。
と思ったらそのような記述があった。
このようにしてオブザーバは、Java のような言語における第一世代のアスペクト指向プログラミングの利点を Rails にもたらしてくれます
- app/models/order_observer.rb
class OrderObserver < ActiveRecord::Observer def after_save(an_order) an_order.logger.info("observer 注文 #{an_order.id} が作製されました") end end
- config/applications.rb
config.active_record.observers = :order_observer
- 実行
[4] pry(main)> FactoryGirl.create(:order) (0.1ms) SAVEPOINT active_record_1 SQL (0.2ms) INSERT INTO "orders" ("name", "email", "cc_number", "address", "pay_type", "state", "amount", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) [["name", "Hbwfo Sdibfgfs"], ["email", "nbswjo.iboe@fybnqmf.dpn"], ["cc_number", "1212122111211234"], ["address", "Port Anika"], ["pay_type", "注文書"], ["state", "NV"], ["amount", 9], ["created_at", "2015-01-30 13:04:20.482480"], ["updated_at", "2015-01-30 13:04:20.482480"]] after_create 注文 9 が作製されました observer 注文 9 が作製されました
ロールバックしたからといって、オブジェクトの値は変化しないので注意。