2022年2月12日 ActionMailer, whenever, 特にscopeの深堀りをしました。
ActionMailer
- Railsに組み込まれているメール送信機能です。
コマンドで主要ファイルを作成することが出来ます。
rails g mailer UserMailer
whenever
Railsで定期的に実行したいタスクを設定することが出来るGemです。
スコープとメソッドの違い
- 前提としてクエリメソッドとは、データベースに問い合わせするクエリを発行してくれるメソッドです。
- 簡単に言うと、スコープとは複数のクエリメソッドをまとめて、複雑なデータをDBから取得したい時などに使われます。
スコープの定義方法
class モデル名 < ApplicationRecord scope :スコープの名前, -> { 条件式 } # ->ラムダリテラルはlambdaとも書けます。 scope :スコープの名前,lambda { 条件式 } end
#scopeメソッド
scope(name, body, &block)
以下はbinding.pryで止めて、scopeメソッドの中身を検証した結果です。
159: # We are able to call the methods like this: 160: # 161: # Article.published.featured.latest_article 162: # Article.featured.titles 163: def scope(name, body, &block) => 164: unless body.respond_to?(:call) 165: raise ArgumentError, "The scope body needs to be callable." 166: end 167: 168: if dangerous_class_method?(name) 169: raise ArgumentError, "You tried to define a scope named \"#{name}\" " \ [1] pry(Article)> name => :published_at_yesterday [2] pry(Article)> body => #<Proc:0x0000000127da5b88@/Users/name/workspace/advanced/4916_name/app/models/article.rb:86 (lambda)> [3] pry(Article)> &block SyntaxError: unexpected &, expecting end-of-input &block ^ [3] pry(Article)> block => nil
上記から分かることは、第一引数のnameにスコープ名、第二引数のbodyにprocオブジェクトが入っていることが分かります。第三引数&blockにはnilが入っていました。 第三引数に値を渡すには以下のコード例になります。
class Shirt < ActiveRecord::Base scope :red, -> { where(color: 'red') } do def dom_id 'red_shirts' end end end
do~endそのものが&blockに渡ります。
&blockの&とは… ブロックを引数として明示的に受け取る
スコープのブロックは第2引数のbody
に渡り第3引数はnil
でしたが第3引数について触れます。&を仮引数の前につけるとブロックをメソッドの実引数として明示的に受け取ることができます。また、そのブロックを実行する場合はcallメソッドを使います。
スコープを定義する際に使われる->
って何?
lambdaリテラルのことです。ここでは、スコープ名という関数を使いたいので、lambdaリテラルを使って、スコープメソッドを定義しているというイメージです。
引数の持たせ方のコード例 ラムダリテラルを使用した場合は引数をブロックの外で()で仮引数を定義できます。lambdaを記述する書き方ではブロック内にブロック引数で仮引数を定義する必要があります。
-> (a) { a + b } lambda { |a| a + b }
ラムダリテラルを使用した場合は引数の()を省略できます。
-> a { a + b }
lambdaとは?
lambdaとは、->構文またはlambdaメソッドで作られたProcオブジェクトです。Procオブジェクトとは、ブロックをオブジェクトとして扱えるようにしたオブジェクトです。オブジェクトとして扱えるので、変数に入れて別のメソッドに渡すことができます。
ブロックをオブジェクトとして扱うために、procオブジェクトにする=> procオブジェクトを作ります。
1.day.ago
昨日の日付を取得できます。
[1] pry(main)> 1.day.ago => Thu, 10 Feb 2022 23:39:38.257665000 UTC +00:00 [2] pry(main)> 1.day.ago.class => ActiveSupport::TimeWithZone
[2] pry(main)> 1.week.ago.beginning_of_day..Time.zone.now.end_of_day => Sat, 05 Feb 2022 00:00:00 JST +09:00..Sat, 12 Feb 2022 23:59:59 JST +09:00 先週の土曜日の0時〜今日(土曜日)の終わり23時59分
all_day
RailsのActiveSupportに定義されているメソッドで、日付を範囲で取得することができます。
Rangeクラスになります。ActiveSupportとは、Railsの拡張機能のことです。
ActiveSupportを使用することで様々なpresent?やblank?などのメソッドを使うことが出来るようになります。 今日の日付で、00:00:00から23:59:59までを取得範囲とします。
all_dayの前に取得したい日付を指定するとその日付の00:00:00から23:59:59までを取得します。
[11] pry(main)> Time.now.all_day => 2022-02-12 00:00:00 +0900..2022-02-12 23:59:59 +0900
実際の取得例 | 取得したい日付オブジェクト + all_day |
---|---|
今日 | Time.zone.now.all_day |
昨日 | 1.day.ago.all_day |
1週間前 | 1.week.ago.all_day |
1か月前 | 1.month.ago.all_day |
begining_of_dayとend_of_day
begining_of_dayを使うことで、時間部分をその日の始まりに設定した日付を取得できます。end_of_dayは時間部分をその日の終わりに設定した日付を取得できます。
[5] pry(main)> 1.day.ago.beginning_of_day => Fri, 11 Feb 2022 00:00:00 JST +09:00 [6] pry(main)> 1.day.ago.end_of_day => Fri, 11 Feb 2022 23:59:59 JST +09:00 [7] pry(main)> 1.day.ago.beginning_of_day..1.day.ago.end_of_day => Fri, 11 Feb 2022 00:00:00 JST +09:00..Fri, 11 Feb 2022 23:59:59 JST +09:00
Active SupportはRuby on Railsのコンポーネントであり、Ruby言語の拡張やユーティリティを提供します。 Active Supportは言語レベルで基本部分を底上げして豊かなものにし、Railsアプリケーションの開発とRuby on Railsそれ自体の開発に役立てるべく作られています。
以下はActiveSupportによって拡張されたメソッドの例です。 Rubyでは使えません。
- blank?
- present?
- empty?
- nil?
TimeとTimeWithZoneどちらを使うべきかについて
まず両者の明確な違いを記します。
Timeクラス
Rubyのクラスです。
TimeWithZone
RailsのActive Supportの拡張クラスです。Rubyでは、使用できません。
Railsの実装を見ていると日時関連の処理は TimeWithZone を積極的に使おうとしているように思います。 TimeWithZone はタイムゾーンをRuby標準のTimeクラスよりも器用に扱えるので、国際的なwebアプリケーションをターゲットにするのであれば、TimeWithZoneクラスを積極的に使うのは確かに理にかなっています。 なので、我々も 極力 TimeWithZone を使うようにした方が良い 、と考えることができます。
RubyとRailsにおけるTime, Date, DateTime, TimeWithZoneの違い
最終的にどちらを使えばいいの?という結論につきましては、上記にもあるようにRailsを使用する場合は、Timeクラスではなく、TimeWithZoneを使用するのをオススメします。
まとめ
今日は4人で勉強会をしたRailsの内容を深掘りしました。