factory_botでvalidationをskipしたいときの方法

こんにちは!kossyです!



今回はテストデータを生成するGemであるfactory_botを使う際に、validationをskipする方法について、
ブログに残してみたいと思います。



環境

Ruby 2.6.6
Rails 6.0.3
macOS Catalina



to_createメソッドを使う

答えを先に言ってしまうと、下記のようにfactoriesファイルに定義してしまえばOKです。(Fakerを使っています)

FactoryBot.define do
  factory :admin do
    name { Faker::Name.name }
    email { Faker::Internet.email }
    password { Faker::Internet.password }

    trait :skip_validation do
      to_create { |instance| instance.save(validate: false) }
    end
  end
end

呼び出す際は以下のように記述します。

create(:admin, :skip_validation)

traitは処理をグループ化して、createの第二引数以降にシンボルで呼び出すことで、traitで定義した属性を適用することができます。
今回のケースの場合、to_createメソッドにブロック引数を渡し、そのブロックの中でインスタンスのsaveメソッドを呼び出す際にvalidationを適用しないようにしています。


大いに参考にさせていただいたサイト

この場を借りて御礼を申し上げます。
FactoryGirl でバリデーションもコールバックも無効にしたい - Qiita

RailsでSQLのログを改行無しで出力する「squish」メソッド

こんにちは!kossyです!




今回は、RailsSQLのログを改行無しで出力する「squish」メソッドについて、ブログに残してみたいと思います。




環境
Ruby 2.6.6
Rails 6.0.3
Docker for Mac



使い方

Employeeモデルにlength_of_serviceというscopeが生えているとします。

  scope :length_of_service, -> () {
    query = <<-SQL
      SELECT id, last_name, first_name,
      (COALESCE(retired_at, current_date) - hired_at) / 365 as length_of_service
      FROM employees
      ORDER BY id ASC
    SQL

    find_by_sql(query)
  }

実行結果は以下です。

$ Employee.length_of_service


  Employee Load (27.3ms)        SELECT id, last_name, first_name,
      (COALESCE(retired_at, current_date) - hired_at) / 365 as length_of_service
      FROM employees
      ORDER BY id ASC

このscopeにsquishメソッドを用いてみます。

  scope :length_of_service, -> () {
    query = <<-SQL.squish # 追加
      SELECT id, last_name, first_name,
      (COALESCE(retired_at, current_date) - hired_at) / 365 as length_of_service
      FROM employees
      ORDER BY id ASC
    SQL

    find_by_sql(query)
  }
$ Employee.length_of_service
  Employee Load (9.7ms)  SELECT id, last_name, first_name, (COALESCE(retired_at, current_date) - hired_at) / 365 as length_of_service FROM employees ORDER BY id ASC

改行が取り除かれて、一行で出力されるようになりました。

railsguides.jp

処理そのものは、冒頭と末尾のホワイトスペースを除去し連続したホワイトスペースを1つに減らすとのことなので、
SQLの改行を消去する以外でも使い道はありそうです。


大いに参考にさせていただいたサイト

この場を借りて御礼を申し上げます。

String#squish で長い SQL 文字列を 1 行にする - Qiita

Nginx起動時に Job for nginx.service failed because the control process exited with error codeが出る場合の対処法

こんにちは!kossyです!




今回はNginxの起動時に Job for nginx.service failed because the control process exited with error codeが出る場合の対処法についてブログに残してみたいと思います。





sudo nginx -t の実行

sudo nginx -tを実行すると、不具合の原因を表示することができます。

以下は特に問題がなかった場合です。

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

問題がある場合は、問題のある箇所を教えてくれます。

nginx: [emerg] host not found in upstream "puma_sample_rails.conf" in /etc/nginx/conf.d/sample_rails.conf:25
nginx: configuration file /etc/nginx/nginx.conf test failed

hostが見つからないとのことなので、正しくhostを指定すればOKです。



大いに参考にさせていただいたサイト

この場を借りて御礼を申し上げます。

Nginxでよく使われるコマンド10選 | TECH+

Shrine::Error: must call Shrine::Attacher#url with the name of the version の解消

こんにちは!kossyです!




今回はファイルアップロードを可能にするGem「Shrine」で発生するエラーの解消について、
ブログに残してみたいと思います。




環境
Ruby 2.6.6
Rails 6.0.3
MacOS catalina
shrine 3.3.0




small, medium, largeのいずれかを指定する必要があった。

私のプロジェクトのShrineの設定は下記です。

# config/initializers/shrine.rb

require "shrine"
require "shrine/storage/file_system"
require 'shrine/storage/s3'

if Rails.env.production?
  s3_options = {
    access_key_id:     Rails.application.credentials.s3[:ACCESS_KEY_ID],
    secret_access_key: Rails.application.credentials.s3[:SECRET_ACCESS_KEY],
    region:            Rails.application.credentials.s3[:REGION],
    bucket:            Rails.application.credentials.s3[:BUCKET]
  }

  Shrine.storages = {
    cache: Shrine::Storage::S3.new(prefix: 'cache', **s3_options),
    store: Shrine::Storage::S3.new(prefix: 'store', **s3_options)
  }
else
  Shrine.storages = {
      cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"),
      store: Shrine::Storage::FileSystem.new("public", prefix: "uploads/store")
  }
end

# 使用するプラグインの宣言
Shrine.plugin :activerecord
Shrine.plugin :cached_attachment_data
# app/uploaders/file_uploader.rb

require "image_processing/mini_magick"

class FileUploader < Shrine
  plugin :processing # allows hooking into promoting
  plugin :versions   # enable Shrine to handle a hash of files
  plugin :delete_raw # delete processed files after uploading
  plugin :validation_helpers

  process(:store) do |io, context|
    versions = { original: io } # retain original

    io.download do |original|
      pipeline = ImageProcessing::MiniMagick.source(original)

      versions[:large]  = pipeline.resize_to_limit!(800, 800)
      versions[:medium] = pipeline.resize_to_limit!(500, 500)
      versions[:small]  = pipeline.resize_to_limit!(300, 300)
    end

    versions # return the hash of processed files
  end

  Attacher.validate do
    validate_max_size 5 * 1024 * 1024, message: '5MBを超えるファイルはアップロードできません。'
    validate_mime_type_inclusion %w(image/jpeg image/png application/pdf)
  end
end
# app/models/release_note_files.rb

class ReleaseNoteFile < ApplicationRecord
  # include modules, gems
  include FileUploader::Attachment(:file)

  # Association
  belongs_to :release_note
end

この状態で、file_urlをReleaseNoteFileインスタンスに呼び出すと、

$ ReleaseNoteFile.last.file_url
Shrine::Error: must call Shrine::Attacher#url with the name of the version

タイトルに記載したエラーが発生しました。

この場合、file_urlの引数にsmallかmediumかlargeを渡せばOKです。

$ ReleaseNoteFile.last.file_url(:small)
=> "/uploads/store/c628d7499afe0a7b57b1a8d2c2a00ff2.png"

$ ReleaseNoteFile.last.file_url(:medium)
=> "/uploads/store/151d7b5445b2dc480ea2b2faecb2dc28.png"

$ ReleaseNoteFile.last.file_url(:large)
=> "/uploads/store/338b8d8ff961827891036af049075a38.png"

これでエラーの解消ができました。(凡ミスですね、、、ドキュメントをちゃんと読みましょう。)



大いに参考にさせていただいたサイト

この場を借りて御礼を申し上げます。

Shrine::Error (must call Shrine::Attacher#url with the name of the version) · Issue #225 · shrinerb/shrine · GitHub

URIを簡単に扱えるGem「addressable」Gemの使い方

こんにちは!kossyです!




今回はURIを簡単に扱えるGem「addressable」Gemの使い方について、ブログに残してみたいと思います。





環境
Ruby 2.6.6
addressable 2.7.0



基本的な使い方

docs.ruby-lang.org

$ url = "https://www.yahoo.co.jp/"
=> "https://www.yahoo.co.jp/"

$  uri = Addressable::URI.parse(url)
=> #<Addressable::URI:0x2ab0974eb32c URI:https://www.yahoo.co.jp/>

# URIクラスのインスタンスメソッドの数
$ URI.parse(url).methods.size
=> 146

# Addressable::URIクラスのインスタンスメソッドの数
$ uri.methods.size
=> 164

$ uri.scheme
=> "https"

$ uri.host
=> "www.yahoo.co.jp"

$ uri.path
=> "/"

# Ruby標準のURIクラスには定義されてない
$ uri.domain
=> "yahoo.co.jp"

# Ruby標準のURIクラスには定義されてない
$ uri.origin
=> "https://www.yahoo.co.jp"

インスタンスメソッドの数はAddressable::URIクラスの方が多かったです。

domainやoriginといったメソッドはAddressable::URI独自のメソッドのようです。

queryを操作する

$ url = "https://news.yahoo.co.jp/search?p=%E3%82%B3%E3%83%AD%E3%83%8A&ei=utf-8"
=> "https://news.yahoo.co.jp/search?p=%E3%82%B3%E3%83%AD%E3%83%8A&ei=utf-8"

$ uri = Addressable::URI.parse(url)
=> #<Addressable::URI:0x3fad86027a4c URI:https://news.yahoo.co.jp/search?p=%E3%82%B3%E3%83%AD%E3%83%8A&ei=utf-8>

$ uri.query
=> "p=%E3%82%B3%E3%83%AD%E3%83%8A&ei=utf-8"

# クエリ文字列を取得する
$ uri.query_values
=> {"p"=>"コロナ", "ei"=>"utf-8"}

# クエリ文字列を全クリアする
$ uri.query_values = nil
=> nil

$ uri
=> #<Addressable::URI:0x3fad86027a4c URI:https://news.yahoo.co.jp/search>

フラグメントを取得する

fragmentメソッドを使うと#以下のフラグを取得することができます。

$ url = "https://news.yahoo.co.jp/search?p=%E3%82%B3%E3%83%AD%E3%83%8A&ei=utf-8#flag"
=> "https://news.yahoo.co.jp/search?p=%E3%82%B3%E3%83%AD%E3%83%8A&ei=utf-8#flag"

$ uri = Addressable::URI.parse(url)
=> #<Addressable::URI:0x2ab097388f84 URI:https://news.yahoo.co.jp/search?p=%E3%82%B3%E3%83%AD%E3%83%8A&ei=utf-8#flag>

$ uri.fragment
=> "flag"

まとめ

調査したところ日本語のURIにも対応できるみたいです。

Rubyは便利ライブラリがたくさんあって良きですね。




大いに参考にさせていただいた記事

この場を借りてお礼を申し上げます。

RubyでAddressable gemを使ってURIの取り扱いを楽にしよう | class Techブログ
rubyでドメインの扱いを幸せにするための記事 - Qiita
Rubyで日本語のURI(URL)をパーズするなら Addressable::URI を使おう - Qiita

APIのドキュメントを生成するGem「autodoc」の使い方

こんにちは!kossyです!





今回はAPIのドキュメントを自動で生成するGemである「autodoc」の使い方について、
ブログに残してみたいと思います。



github.com



環境
Ruby 2.6.6
Rails 6.0.3
MacOS Catalina
autodoc 0.7.5



導入

導入は至って簡単です。

# Gemfile

group :test do
  gem 'autodoc'
end

# terminal

$ bundle install

任意のRequestSpecにautodoc: trueを追記します。

# spec/requests/recipes_spec.rb
describe "Recipes" do
  describe "POST /recipes", autodoc: true do
    it "creates a new recipe" do
      post "/recipes", name: "alice", type: 1
      response.status.should == 201
    end
  end
end

この状態で、terminalでautodoc=1 bundle exec rspec spec/requestsを実行します。

$ autodoc=1 bundle exec rspec spec/requests

このコマンドを実行することで、ルートディレクトリにdoc/recipes.mdが作成されます。


mdファイル生成先を変更したい場合

デフォルトではdoc/配下に出力されるドキュメントですが、生成先を変更することができます。

  # spec/rails_helper.rb
  
RSpec.configure do |config|
  # 省略

  # for Autodoc
  Autodoc.configuration.path = 'docs/api'

spec/rails_helper.rbでAutodoc.configuration.path = 'docs/api'と指定することで、ルートディレクトリのdocs配下のapiディレクトリにmdファイルが生成されるようになります。


ドキュメントの出力形式を変更したい

デフォルトではHttpRequestのBody部が出力されないので、Request Bodyも出力されるようにerbファイルを作成します。

# spec/autodoc/templates/document.md.erb

## <%= title %>
<%= description %>
<%= parameters_section %>
#### Request
```
<%= method %> <%= request.path %><%= request_query %>
```
<% if request_body_section.present? %>
<% if request_body_section.strip == 'multipart/form-data' %>
```
<%= request.env['rack.request.form_hash'].inspect %>
```
<% else %>
```json
{<% URI.decode_www_form(request_body_section.strip).each do |arr| %>
  <%= arr[0] %>: "<%= arr[1] %>",
<% end %>}
```
<% end %>
<% end %>
#### Response
```
<%= response_http_version %> <%= response.status %>
<%= response_header %><%= response_body_section %>
```

あとは spec/rails_helper.rb でドキュメント生成時に利用するerbファイルを指定してあげるだけです。

  # spec/rails_helper.rb
  
RSpec.configure do |config|
  # 省略

  # for Autodoc
  Autodoc.configuration.path = 'docs/api'

  # 追加
  Autodoc.configuration.template = File.read(File.expand_path('../autodoc/templates/document.md.erb', __FILE__))

これで出力されるmdファイルは以下のようになります。

## POST /supervisor/ips
IPアドレス制限を設定できること.

#### Request
```
POST /supervisor/ips
```


```json
{
  content: "127.0.0.1",
}
```


#### Response
```
HTTP/1.1 200
Cache-Control: max-age=0, private, must-revalidate
Content-Length: 99
Content-Type: application/json; charset=utf-8
ETag: W/"545ba7565213c5da92a1067d90ba1f71"
Referrer-Policy: strict-origin-when-cross-origin
Vary: Origin
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Frame-Options: SAMEORIGIN
X-Permitted-Cross-Domain-Policies: none
X-Request-Id: 8cc8356f-9a61-4ed6-9184-8fc26c11db76
X-Runtime: 0.034126
X-XSS-Protection: 1; mode=block
access-token: TNJu5tShW-QUuezNUPXcEQ
client: QyIMw5NVQ-xj0cn4ePV9zg
expiry: 1618410677
token-type: Bearer
uid: carol_kulas@example.net
{
  "content_str": "127.0.0.1",
  "setted_at": "2021-03-31T23:31:17.000+09:00",
  "full_name": "吉田 高志"
}
```
## PATCH /supervisor/ips/:uuid
IPアドレス制限を更新できること.

#### Request

```
PATCH /supervisor/ips/eb926dcc-c949-46e8-88ef-38ba1c3aed15
```


```json
{
  content: "127.0.0.2",
}
```


#### Response
```
HTTP/1.1 200
Cache-Control: max-age=0, private, must-revalidate
Content-Length: 99
Content-Type: application/json; charset=utf-8
ETag: W/"a21894b45232cf04cdc8f632057cb475"
Referrer-Policy: strict-origin-when-cross-origin
Vary: Origin
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Frame-Options: SAMEORIGIN
X-Permitted-Cross-Domain-Policies: none
X-Request-Id: 122913ac-1a7b-49bf-8400-ca9acbb1c1d9
X-Runtime: 0.056721
X-XSS-Protection: 1; mode=block
access-token: SkYvm3g9Bs2s9uq6v7s3Dw
client: uLPcyFrr1LRKpi2M_tNLBQ
expiry: 1618410677
token-type: Bearer
uid: ursula@example.org

{
  "content_str": "127.0.0.2",
  "setted_at": "2021-03-31T23:31:17.000+09:00",
  "full_name": "吉田 高志"
}
```

導入も簡単でカスタマイズも容易なのでおすすめです。

Railsでbulk_insertを行う際に uuid_generate_v4() が走らない問題の対処法

こんにちは!kossyです!




今回はRailsPostgreSQLを使っていて、bulk_insertを行う際に uuid_generate_v4() が走らない問題の対処法について、
ブログに残してみたいと思います。





環境
Ruby 2.6.6
Rails 6.0.3
PostgreSQL 12系



Securerandomモジュールのuuidメソッドを使う

docs.ruby-lang.org

RailsActiveRecord-importを用いてbulk_insertを行う場合、直接SQLを実行するため、uuidを自動挿入する uuid_generate_v4()関数が走りません。

この場合、インスタンスの生成時に Securerandomモジュールのuuidメソッドが生成する値をattrに代入すればOKです。

以下は簡単なサンプルコードです。

now = Time.zone.now

users = []
rows.each do |row|
  users << User.new(uuid: Securerandom.uuid, name: row[:name], row[:email], row[:password], created_at: now, updated_at: now)
end

User.import books

まとめ

bulk_insertを行う時は、カラムのdefault値に特別な関数を当てているケースに注意しましょう。

ページネーションを行うGem「Pagy」を使ってみる

こんにちは!kossyです!



今回はkaminariやwill_paginateよりもパフォーマンスがいいとされているGem「Pagy」を使ってみたので、
ブログに残してみたいと思います。





GitHub - ddnexus/pagy: The ultimate pagination ruby gem




導入

導入は至って簡単です。

# Gemfile

gem 'pagy'



# Your Terminal

$ bundle install

pagyをinstallし、任意のcontroller内でPagy::Backendをincludeすることで、pagyメソッドが使えるようになります。

class PostsController < ApplicationController
  include Pagy::Backend

  def index
    @posts = Post.all

    @pagy, @posts = pagy(@posts)
  end
end

あとはこのインスタンス変数をviewで呼び出すだけです。

# views/posts/index.html.erb

<%== pagy_nav(@pagy) %>

設定ファイル

github.com

上記ページにconfigファイルがありますので、設定を加えたい場合は
config/pagy.rbを作成して各種設定を加えていけばOKです。

いくつかの項目について調べてみました。

Instance Variable

# Instance variables
# See https://ddnexus.github.io/pagy/api/pagy#instance-variables
# Pagy::VARS[:page]   = 1                                  # default
# Pagy::VARS[:items]  = 20                                 # default
# Pagy::VARS[:outset] = 0                                  # default

APIリファレンスを一部訳してみます。

A few variables are particularly important for the calculation of the pagination, and therefore are validated and used to initialize a few instance variables.

The only mandatory instance variable to be passed is the :count of the collection to paginate: all the other variables are optional and have sensible defaults. Of course you will also have to pass the page or you will always get the default page number 1. They are all integers:

いくつかの変数は、ページネーションの計算にとって特に重要であるため、
検証され、いくつかのインスタンス変数を初期化するために使用されます。

渡される必須のインスタンス変数は、ページ付けするコレクションのcountだけです。
他のすべての変数はオプションであり、適切なデフォルトがあります。
もちろん、ページを渡す必要もあります。そうしない場合、常にデフォルトのページ番号1が取得されます。
これらはすべて整数です。

出典: Pagy | The Ultimate Pagination Ruby Gem

・Pagy::VARS[:page]はデフォルトのページ番号
・Pagy::VARS[:items] は1ページに表示する件数
・Pagy::VARS[:outset]は初期オフセット

ですね。いじるとしたらitemsくらいなような気もします。

Other Variable

# Other Variables
# See https://ddnexus.github.io/pagy/api/pagy#other-variables
# Pagy::VARS[:size]       = [1,4,4,1]                       # default
# Pagy::VARS[:page_param] = :page                           # default
# Pagy::VARS[:params]     = {}                              # default
# Pagy::VARS[:fragment]   = '#fragment'                     # example
# Pagy::VARS[:link_extra] = 'data-remote="true"'            # example
# Pagy::VARS[:i18n_key]   = 'pagy.item_name'                # default
# Pagy::VARS[:cycle]      = true                            # example

・Pagy::VARS[:size]は表示するページリンクのサイズで、左から、「最初のページ、現在のページの前、現在のページの後、最後のページ」
・Pagy::VARS[:page_param]はURLで使用されるページパラメータ名
・Pagy::VARS[:params]はURLに追加する任意のパラメータ
・Pagy::VARS[:fragment]はURLに追加する任意のフラグメント文字列
・Pagy::VARS[:link_extra]はページリンクに追加された追加の属性文字列
・Pagy::VARS[:i18n_key]はヘルパーのために用いるi18nキー
・Pagy::VARS[:cycle]無限ループにするかどうか

他のオプションについてもAPIドキュメントに記載がありましたので、
一読されることをお勧めします。

Basic Concepts | Pagy

ページネーションを行うGem「kaminari」のソースコードを読んでみた

こんにちは!kossyです!




さて、今回はページネーション機能を実現するRubyのGemである「kaminari」のソースコードを読んでみたので、
ブログに残してみたいと思います。

github.com

環境

Ruby 2.6.6
Rails 6.0.3
MacOS catalina




kaminariとは

偉大なる本家リポジトリ
github.com

ページネーションを実現するGemで、Railsだけでなくsinatra等のフレームワークでも用いることができます。

後述しますが、bundle installを行うだけで、ActiveRecordを継承したクラスにkaminariのメソッドが生えるようになります。

kaminariをinstallすることで各種メソッドが定義される仕組みについて

Gemfileに以下を追加し、bundle installをすると、

gem 'kaminari'

$ bundle install

以下の2つのモジュールがActiveRecordを継承したクラスにincludeされます。

Kaminari::ConfigurationMethods
Kaminari::ActiveRecordModelExtension

試しにお手元のkaminariがinstallされたアプリケーションで、 rails c を実行し、

$ rails c

# Userモデルが定義されていると仮定しています。

$ User.ancestors

と実行してみてください。すると、先ほど挙げた2つのモジュール名が表示されるかと思います。

bundle installするだけでこの2つのモジュールをincludeしている仕組みはどのように実現されているのでしょうか。

ソースコードを読む

まずはモジュール名からいかにもActiveRecordの拡張を行っていそうな「Kaminari::ActiveRecordModelExtension」から読んでみます。

github.com

おそらくpageメソッドを定義しているであろうこの箇所がキモですね。

    included do
      include Kaminari::ConfigurationMethods

      # Fetch the values at the specified page number
      #   Model.page(5)
      eval <<-RUBY, nil, __FILE__, __LINE__ + 1
        def self.#{Kaminari.config.page_method_name}(num = nil)
          per_page = max_per_page && (default_per_page > max_per_page) ? max_per_page : default_per_page
          limit(per_page).offset(per_page * ((num = num.to_i - 1) < 0 ? 0 : num)).extending do
            include Kaminari::ActiveRecordRelationMethods
            include Kaminari::PageScopeMethods
          end
        end
      RUBY
    end

Kaminari.config.page_method_nameはコンソールで実行できそうなので実行してみます。

$ rails c

$ Kaminari.config.page_method_name
=> :page

:pageが返ってきたということで、

def self.page

というメソッドがモデルに定義されることがわかりました。

定義されるタイミングについては下記ブログが詳しく解説されていました。

kaminariのactiverecord拡張部分を読む - u1f419

Kaminari::ConfigurationMethodsも確認してみます。

kaminari/configuration_methods.rb at master · kaminari/kaminari · GitHub

rails g kaminari:configとターミナルで実行することで、config/initializers/kaminari_config.rb が作成されるのですが、
そのファイルに記載された初期値かモデルで上書きした値を使うかを制御するメソッドが定義されていました。

kaminari_configの中身はこちら。

kaminari/kaminari_config.rb at master · kaminari/kaminari · GitHub


Kaminari::PageScopeMethodsをincludeすることで定義される各種メソッドの一部も見てみます。

perメソッド

    # Specify the <tt>per_page</tt> value for the preceding <tt>page</tt> scope
    #   Model.page(3).per(10)
    def per(num, max_per_page: nil)
      max_per_page ||= ((defined?(@_max_per_page) && @_max_per_page) || self.max_per_page)
      @_per = (num || default_per_page).to_i
      if (n = num.to_i) < 0 || !(/^\d/ =~ num.to_s)
        self
      elsif n.zero?
        limit(n)
      elsif max_per_page && (max_per_page < n)
        limit(max_per_page).offset(offset_value / limit_value * max_per_page)
      else
        limit(n).offset(offset_value / limit_value * n)
      end
    end

ActiveRecordのクエリメソッドであるlimitとoffsetを用いて、条件に応じてlimitとoffsetに渡す引数を変えることで
1ページあたりに表示する件数を制御していました。思ったよりも泥臭く愚直に実装されていますね。Gemを読み込んでいくと泥臭い処理が見られて良きです。

total_pagesメソッド

    # Total number of pages
    def total_pages
      count_without_padding = total_count
      count_without_padding -= @_padding if defined?(@_padding) && @_padding
      count_without_padding = 0 if count_without_padding < 0

      total_pages_count = (count_without_padding.to_f / limit_value).ceil
      max_pages && (max_pages < total_pages_count) ? max_pages : total_pages_count
    rescue FloatDomainError
      raise ZeroPerPageOperation, "The number of total pages was incalculable. Perhaps you called .per(0)?"
    end

kaminari_config.rbに定義された値を見に行きつつ、トータルのページ数を算出するメソッドでした。

まとめ

ページネーションという一般的な機能を抽象化してActiveRecordのQueryに載せるのが見事だと思いました。

勝手にpageはperなどのメソッドが生えてしまうので、それが嫌な方は自前で定義するかPagyという同じくページネーションを実現するGemを用いるのがいいかなと思います。

GitHub - ddnexus/pagy: The ultimate pagination ruby gem

dependabotのconfig.ymlの内容を精査する

こんにちは!kossyです!




さて、今回はdependabotのconfig.ymlの内容を精査するサイトを見つけたので、ブログに残してみたいと思います。




間違いを指摘してくれる

dependabot.com

上記のサイトでconfig.ymlの内容を精査してくれます。

version: 1
update_configs:
  - package_manager: 'ruby:bundler'
    directory: '/'
    update_schedule: 'weekly'
    allowed_updates:
      - match:
        update_type: 'all'
    version_requirement_updates: 'off'

上記のコードを精査してもらいます。
その結果がこちら。

f:id:kossy-web-engineer:20210423193520p:plain

update_type周りに不具合があるとのこと。
インデントがずれていました。

修正して再度精査してもらった結果がこちら。

f:id:kossy-web-engineer:20210423193621p:plain

問題がない場合は Looks good 👍 の表示が出ます。

config.ymlの設定を行う時は一度このサイトで精査してもらうといいと思います。