Railsガイド書写による小ネタが続いております。本日は、8.5 rewhere です。
Article(記事)モデルを作ります。
Railsガイドとは異なるカラムですが、author
(投稿者)とlikes_count
(いいねの数)
というカラムを作っておきます。
[ykt68@macbook testapp]$ rails g model article author likes_count:integer
Running via Spring preloader in process 74847
Expected string default value for '--jbuilder'; got true (boolean)
invoke active_record
create db/migrate/20170225110425_create_articles.rb
create app/models/article.rb
invoke test_unit
create test/models/article_test.rb
create test/fixtures/articles.yml
[ykt68@macbook testapp]$ rails db:migrate
== 20170225110425 CreateArticles: migrating ===================================
-- create_table(:articles)
-> 0.0127s
== 20170225110425 CreateArticles: migrated (0.0128s) ==========================
rails console を立ち上げます。
[ykt68@macbook testapp]$ rails c
Running via Spring preloader in process 74971
Loading development environment (Rails 5.0.1)
100個のレコードを作成します。
likes_count
には、1以上100以下の乱数を入れます。
irb(main):001:0> 100.times do |n|
irb(main):002:1* Article.create author:sprintf('著者-%03d',n), likes_count:rand(0..100)
irb(main):003:1> end
(0.2ms) BEGIN
SQL (0.5ms) INSERT INTO `articles` (`author`, `likes_count`, `created_at`, `updated_at`) VALUES ('著者-000', 0, '2017-02-25 20:06:19', '2017-02-25 20:06:19')
(0.6ms) COMMIT
(0.2ms) BEGIN ・・・
・・・
SQL (0.2ms) INSERT INTO `articles` (`author`, `likes_count`, `created_at`, `updated_at`) VALUES ('著者-099', 48, '2017-02-25 20:06:20', '2017-02-25 20:06:20')
(0.3ms) COMMIT
=> 100
whereとrewhereを使ってみます。
likes_count
が50のものを取得
irb(main):004:0> Article.where(likes_count: 50)
Article Load (9.6ms) SELECT `articles`.* FROM `articles` WHERE `articles`.`likes_count` = 50
=> #<ActiveRecord::Relation [#<Article id: 42, author: "著者-041", likes_count: 50, created_at: "2017-02-25 11:06:19", updated_at: "2017-02-25 11:06:19">, #<Article id: 68, author: "著者-067", likes_count: 50, created_at: "2017-02-25 11:06:19", updated_at: "2017-02-25 11:06:19">, #<Article id: 75, author: "著者-074", likes_count: 50, created_at: "2017-02-25 11:06:19", updated_at: "2017-02-25 11:06:19">]>
で、クエリに rewhere(likes_count: 80)
を付加してみると、
irb(main):005:0> Article.where(likes_count: 50).rewhere(likes_count: 80)
Article Load (3.8ms) SELECT `articles`.* FROM `articles` WHERE `articles`.`likes_count` = 80
=> #<ActiveRecord::Relation [#<Article id: 72, author: "著者-071", likes_count: 80, created_at: "2017-02-25 11:06:19", updated_at: "2017-02-25 11:06:19">]>
なるほど。
articles.likes_count = 50
が、articles.likes_count = 80
に
上書きされています。
では、次に、where
の条件を likes_count > 50
にして、
irb(main):006:0> Article.where('likes_count > 50')
Article Load (11.4ms) SELECT `articles`.* FROM `articles` WHERE (likes_count > 50)
=> #<ActiveRecord::Relation [#<Article id: 2, author: "著者-001", likes_count: 92, created_at: "2017-02-25 11:06:19", updated_at: "2017-02-25 11:06:19">, #<Article id: 3, author: "著者-002", likes_count: 68, created_at: "2017-02-25 11:06:19", updated_at: "2017-02-25 11:06:19">, #<Article id: 4, author: "著者-003", likes_count: 57, created_at: "2017-02-25 11:06:19", updated_at: "2017-02-25 11:06:19">, #<Article id: 9, author: "著者-008", likes_count: 87, created_at: "2017-02-25 11:06:19", updated_at: "2017-02-25 11:06:19">, #<Article id: 13, author: "著者-012", likes_count: 69, created_at: "2017-02-25 11:06:19", updated_at: "2017-02-25 11:06:19">, #<Article id: 16, author: "著者-015", likes_count: 56, created_at: "2017-02-25 11:06:19", updated_at: "2017-02-25 11:06:19">, #<Article id: 18, author: "著者-017", likes_count: 52, created_at: "2017-02-25 11:06:19", updated_at: "2017-02-25 11:06:19">, #<Article id: 19, author: "著者-018", likes_count: 78, created_at: "2017-02-25 11:06:19", updated_at: "2017-02-25 11:06:19">, #<Article id: 25, author: "著者-024", likes_count: 86, created_at: "2017-02-25 11:06:19", updated_at: "2017-02-25 11:06:19">, #<Article id: 26, author: "著者-025", likes_count: 98, created_at: "2017-02-25 11:06:19", updated_at: "2017-02-25 11:06:19">, ...]>
としてから、
「きっと、likes_count > 50
が、likes_count > 80
になってくれるのだろう」
という想定のもと、rewhere('likes_count > 80')
を付加して
irb(main):007:0> Article.where('likes_count > 50').rewhere('likes_count > 80')
としてみると、残念
NoMethodError: undefined method `keys' for "likes_count > 80":String
from /Users/ykt68/.rbenv/versions/2.2.6/lib/ruby/gems/2.2.0/gems/activerecord-5.0.1/lib/active_record/relation/query_methods.rb:650:in `rewhere'
・・・
となりました。
エラーメッセージに、
「"likes_count > 80"は文字列で、keys
メソッドが無いよ」
と怒られています。
それでは、rewhere('likes_count > 80')
をrewhere(likes_count: 80)
に戻してやれば、
WHERE句の中で、likes_count = 80
によって likes_count > 50
が上書きされるかと思きや、
irb(main):008:0> Article.where('likes_count > 50').rewhere(likes_count: 80)
Article Load (7.2ms) SELECT `articles`.* FROM `articles` WHERE (likes_count > 50) AND `articles`.`likes_count` = 80
=> #<ActiveRecord::Relation [#<Article id: 72, author: "著者-071", likes_count: 80, created_at: "2017-02-25 11:06:19", updated_at: "2017-02-25 11:06:19">]>
irb(main):009:0>
と、エラーにはなりませんが、
WHERE (likes_count > 50) AND `articles`.`likes_count` = 80
というWHERE句が生成されています。
ムムッ(←川平慈英のモノマネをする博多華丸口調で)
そこで Rails APIで、rewhere
を調べると、
This is short-hand for unscope(where: conditions.keys).where(conditions).
Note that unlike reorder, we're only unscoping the named conditions – not the entire where statement.
ということで、
only unscoping the named conditions – not the entire where statement.
だそうです。
が、全然ノープロですわ。
rewhere('likes_count > 80')
でもいけちゃうrewhere
欲しければ
自分で書けよって話だと思いますし、こちとら、ActiveRecord様のような
スゴイもの、タダで使わせてもらってる身空でございますしおすし。