LoginSignup
4
1

More than 3 years have passed since last update.

Rails6 のちょい足しな新機能を試す99(association extension編)

Posted at

はじめに

Rails 6 に追加された新機能を試す第99段。 今回は、 association extension 編です。
Rails 6 では、 define_extensions で定義される module が model 内の module として定義されるようになっています。
実際の例を見た方がわかりやすいです。

Ruby 2.6.5, Rails 6.0.0 で確認しました。

$ rails --version
Rails 6.0.0

今回は、 Author モデル と Book モデルを定義して、rails console で確認します。
Author は Book を複数持ちます( has_many )。

Rails プロジェクトを作る

$ rails new rails_sandbox
cd rails_sandbox

Author モデルを作る

name を持つ Author モデルを作ります。

$ bin/rails g model Author name

Book モデルを作る

title, published, author_id を持つ Book モデルを作ります。

$ bin/rails g model Book title published:boolean author:references

Author モデルを修正する

Author モデルを修正します。
2つの has_many アソシエーションを定義します。
1つ目の has_many では、 ブロックで ordered メソッドを定義します。
2つ目の scope published_booksextending を使って ordered メソッドを利用できるようにします。
extending の引数が BooksAssociationExtension になっていることに注意してください。

app/models/author.rb
class Author < ApplicationRecord
  has_many :books do
    def ordered
      order(:title)
    end
  end

  has_many :published_books, -> { where(published: true).extending(BooksAssociationExtension) }, class_name: 'Book'
end

seed データを作成する

Author と Book の seed データを作成します。

db/seeds.rb
author = Author.create(
  {
    name: 'Dave Thomas'
  }
)

Book.create(
  [
    { title: 'Programming Ruby', author: author, published: true },
    { title: 'Pragmatic Programmer', author: author, published: true },
    { title: 'Agile Web Development with Rails 6', author: author, published: false }
  ]
)

データベースを作成し、 seed データを登録する

$ bin/rails db:create db:migrate db:seed

rails console で確認する

rails console で確認します。

まずは、1つ目の has_many を確認します。

irb(main):001:0> Author.first.books.ordered
  Author Load (0.3ms)  SELECT "authors".* FROM "authors" ORDER BY "authors"."id" ASC LIMIT $1  [["LIMIT", 1]]
  Book Load (0.3ms)  SELECT "books".* FROM "books" WHERE "books"."author_id" = $1 ORDER BY "books"."title" ASC LIMIT $2  [["author_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::AssociationRelation [#<Book id: 3, title: "Agile Web Development with Rails 6", published: false, author_id: 1, created_at: "2019-10-12 09:09:58", updated_at: "2019-10-12 09:09:58">, #<Book id: 2, title: "Pragmatic Programmer", published: true, author_id: 1, created_at: "2019-10-12 09:09:58", updated_at: "2019-10-12 09:09:58">, #<Book id: 1, title: "Programming Ruby", published: true, author_id: 1, created_at: "2019-10-12 09:09:58", updated_at: "2019-10-12 09:09:58">]>

2つ目の has_many を確認します。

irb(main):002:0> Author.first.published_books.ordered
  Author Load (0.8ms)  SELECT "authors".* FROM "authors" ORDER BY "authors"."id" ASC LIMIT $1  [["LIMIT", 1]]
  Book Load (0.8ms)  SELECT "books".* FROM "books" WHERE "books"."author_id" = $1 AND "books"."published" = $2 ORDER BY "books"."title" ASC LIMIT $3  [["author_id", 1], ["published", true], ["LIMIT", 11]]
=> #<ActiveRecord::AssociationRelation [#<Book id: 2, title: "Pragmatic Programmer", published: true, author_id: 1, created_at: "2019-10-12 09:09:58", updated_at: "2019-10-12 09:09:58">, #<Book id: 1, title: "Programming Ruby", published: true, author_id: 1, created_at: "2019-10-12 09:09:58", updated_at: "2019-10-12 09:09:58">]>

Author::BooksAssociationExtension が定義されていることを確認します。

irb(main):003:0> Author::BooksAssociationExtension
=> Author::BooksAssociationExtension

Rails 5 では

Rails 5.2.3 では、 Author::BooksAssociationExtension ではなく、 AuthorBooksAssociationExtension が定義されます。
以下のように extending の引数を AuthorBooksAssociationExtension と書く必要があります。

app/models/author.rb
class Author < ApplicationRecord
  ...
  has_many :published_books, -> { where(published: true).extending(AuthorBooksAssociationExtension) }, class_name: 'Book'
end

Rails 5.2.3 ではグローバルなモジュールとして定義されるのに対し、Rails 6 では、 Author モデルの中のモジュールとして定義されるので、 Author モデルで利用するときは、Author をつけずに、 BooksAssociationExtension と簡潔に書くことができるようになっています。

試したソース

試したソースは以下にあります。
https://github.com/suketa/rails_sandbox/tree/try099_association_extension

参考情報

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1