letter_opener_db 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 793c69840ecc16b1839cd9b35387adbf43b3d35a93d4d579021aebc72e8237cc
4
+ data.tar.gz: 77af71136e1929d5e4f538eb77107429e6c2c74d31f3911ff0965220e53e923a
5
+ SHA512:
6
+ metadata.gz: 708be12697fe937481224d13c01085b2534bda89df9586551df87a6805327bb5d9f07129478adc808ff7e717ffc9fee2813f8d3d21fb06c3d8da29430f0b22c8
7
+ data.tar.gz: 3158a1c06a1417b38d665fb69bf5689d5227fc5b45ec95f129d5b92d9ffcf838ca79b68acdb11d6aead30f8550457d5a56b98aa57b722948ad742898bca7ae73
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Seiya Takahashi.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # LetterOpenerDb
2
+
3
+ **LetterOpenerDb** is a Ruby gem that intercepts outgoing emails in your Rails application and stores them in a database for easy viewing, searching, and debugging. Inspired by [letter_opener](https://github.com/ryanb/letter_opener), this gem provides a convenient web interface instead of relying on local file system storage.
4
+
5
+ ## Motivation
6
+
7
+ While the original **letter_opener** gem saves emails as files, it has several limitations:
8
+
9
+ 1. **No Search Functionality**: Storing emails on the file system makes them difficult to search.
10
+ 2. **Server Scalability Issues**: If you run multiple servers (e.g., on a staging environment), emails are scattered across different file systems, making it impossible to view all captured emails in one place.
11
+
12
+ To address these issues, **LetterOpenerDb** saves the emails in a database, enabling:
13
+
14
+ - **Search** by subject, body, or other fields
15
+ - **Centralized Access** to all emails, even in multi-server environments
16
+
17
+ ## Features
18
+
19
+ - **Database Storage**
20
+ All emails sent by ActionMailer are recorded in the database.
21
+ - **Web Interface**
22
+ Easily browse and inspect sent emails through an embedded Rails engine.
23
+ - **Simple Search**
24
+ Search by text in the subject or body of emails.
25
+ - **Rails Engine**
26
+ Includes models, controllers, and views for quick installation and easy maintenance.
27
+
28
+ ## Installation
29
+
30
+ Add this line to your application's Gemfile, pointing to your Git repository (private or public) or a local path:
31
+
32
+ ```ruby
33
+ gem 'letter_opener_db'
34
+ ```
35
+
36
+ ### Then execute:
37
+
38
+ `bundle install`
39
+
40
+ ### Setup
41
+
42
+ 1. Migrations
43
+ Generate and run the migrations to create the letter_opener_db_mail_records table:
44
+
45
+ ```sh
46
+ rails generate letter_opener_db:install
47
+ rails db:migrate
48
+ ```
49
+
50
+ 2. Delivery Method
51
+ In your config/environments/development.rb (and/or config/environments/test.rb), set:
52
+
53
+ ```ruby
54
+ config.action_mailer.delivery_method = :letter_opener_db
55
+ ```
56
+
57
+ 3. Mount the Engine
58
+ In your main config/routes.rb, add:
59
+
60
+ ```ruby
61
+ mount LetterOpenerDb::Engine, at: '/letter_opener_db'
62
+ ```
63
+
64
+ You can choose any path you prefer (e.g., '/mails').
65
+
66
+ ## Usage
67
+
68
+ - Send Emails as you normally would in development or test environments.
69
+ - Access the emails at http://localhost:3000/letter_opener_db/mail_records (or your chosen mount path).
70
+ - Browse and Search
71
+ - See all captured emails, sorted by send time.
72
+ - Click on a subject to view details (recipients, subject, body, etc.).
73
+ - Use the simple search box to filter emails by subject or body text.
74
+
75
+ ## Development
76
+
77
+ 1. Clone or Fork the repository.
78
+ 2. Edit the gem’s files in the lib and app directories as needed.
79
+ 3. Test changes by running: `bundle exec rspec`
80
+
81
+ 4. Optionally, add this gem as a path reference in another Rails app to test integration:
82
+
83
+ ```ruby
84
+ gem 'letter_opener_db', path: '../letter_opener_db'
85
+ ```
86
+
87
+ ## Contributing
88
+
89
+ Contributions are welcome! To submit a feature or fix:
90
+
91
+ 1. Fork this repository.
92
+ 2. Create a new branch (git checkout -b feature/my-feature).
93
+ 3. Commit your changes (git commit -m 'Add my feature').
94
+ 4. Push the branch (git push origin feature/my-feature).
95
+ 5. Open a Pull Request with a clear description of your changes.
96
+
97
+ ## License
98
+
99
+ This project is released under the MIT License.
data/README_JA.md ADDED
@@ -0,0 +1,95 @@
1
+ # LetterOpenerDb
2
+
3
+ **LetterOpenerDb** は、Rails アプリケーションで送信されるメールをフックし、ファイルシステムではなくデータベースに保存して、簡単に閲覧・検索・デバッグできるようにする Ruby gem です。
4
+ [letter_opener](https://github.com/ryanb/letter_opener) から着想を得ていますが、ファイルシステムに依存せず、Web インターフェースでメールの内容を確認できるようにしています。
5
+
6
+ ## 作成の背景 (Motivation)
7
+
8
+ オリジナルの **letter_opener** gem はメールをファイルとして保存しますが、以下のような制限があります:
9
+
10
+ 1. **検索ができない**: ファイルシステムに保存したメールを検索するのは容易ではありません。
11
+ 2. **サーバーを増やした場合の問題**: ステージング環境などで複数台のサーバーを起動すると、メールが各サーバーのファイルシステムに分散してしまい、すべてのメールを一元的に閲覧できなくなります。
12
+
13
+ こうした問題を解決するため、**LetterOpenerDb** ではメールをデータベースに保存し、下記が可能になります:
14
+
15
+ - **件名や本文等の検索**
16
+ - **マルチサーバー環境でも一括管理** して全メールを閲覧
17
+
18
+ ## 特徴 (Features)
19
+
20
+ - **データベース保存**
21
+ ActionMailer が送信したすべてのメールをデータベースに保存します。
22
+ - **Web インターフェース**
23
+ Rails エンジンとして組み込み、ブラウザで送信メールを簡単に閲覧できます。
24
+ - **シンプルな検索機能**
25
+ 件名や本文をテキスト検索できるため、メールを素早く見つけられます。
26
+ - **Rails エンジン**
27
+ マイグレーション、コントローラ、ビューを含むため、インストールが簡単です。
28
+
29
+ ## インストール (Installation)
30
+
31
+ アプリケーションの `Gemfile` に以下の行を追加します。
32
+ (プライベートまたはパブリックの Git リポジトリ、あるいはローカルパスを指定可能です)
33
+
34
+ ```ruby
35
+ gem 'letter_opener_db'
36
+ ```
37
+
38
+ ### その後実行:
39
+
40
+ `bundle install`
41
+
42
+ ### セットアップ (Setup)
43
+
44
+ 1. マイグレーション
45
+ letter_opener_db_mail_records テーブルを作成するため、以下を実行します:
46
+
47
+ ```sh
48
+ rails generate letter_opener_db:install
49
+ rails db:migrate
50
+ ```
51
+
52
+ 2. メール送信方法の設定 (Delivery Method)
53
+
54
+ config/environments/development.rb (または config/environments/test.rb) に以下を追記します:
55
+
56
+ ```ruby
57
+ config.action_mailer.delivery_method = :letter_opener_db
58
+ ```
59
+
60
+ 3. エンジンのマウント (Mount the Engine)
61
+
62
+ config/routes.rb に以下を追加します:
63
+
64
+ ```ruby
65
+ mount LetterOpenerDb::Engine, at: '/letter_opener_db'
66
+ ```
67
+
68
+ '/mails' など、お好みのパスを指定することも可能です。
69
+
70
+ ## 使い方 (Usage)
71
+
72
+ - 開発やテスト環境で、通常どおりメールを送信します。
73
+ - http://localhost:3000/letter_opener_db/mail_records (または設定したパス) にアクセスすると、保存されたメールを閲覧できます。
74
+ - 一覧・検索
75
+ - 送信したメールが時系列で表示されます。
76
+ - 件名をクリックすると、宛先や本文を含む詳細情報が表示されます。
77
+ - 件名や本文で検索することが可能です。
78
+
79
+ ## 開発 (Development)
80
+
81
+ 1. リポジトリをクローンまたはフォークします。
82
+ 2. lib ディレクトリや app ディレクトリ内のファイルを必要に応じて編集します。
83
+ 3. 下記コマンドで変更内容をテストします:
84
+ `bundle exec rspec`
85
+ 4. 別の Rails アプリにローカルパスで参照して動作確認も可能です:
86
+
87
+ `gem 'letter_opener_db', path: '../letter_opener_db'`
88
+
89
+ ## コントリビュート (Contributing)
90
+
91
+ 機能追加や修正の提案は歓迎します!手順は以下のとおりです: 1. このリポジトリをフォークしてください。 2. 新しいブランチを作成します (git checkout -b feature/my-feature)。 3. 変更をコミットします (git commit -m 'Add my feature')。 4. ブランチをプッシュします (git push origin feature/my-feature)。 5. 変更内容を明確に説明した Pull Request を作成してください。
92
+
93
+ ## ライセンス (License)
94
+
95
+ このプロジェクトは MIT License のもとで公開されています。
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,38 @@
1
+ module LetterOpenerDb
2
+ class MailRecordsController < ApplicationController
3
+ DEFAULT_PER_PAGE = 25.freeze
4
+ DEFAULT_PAGE = 1.freeze
5
+
6
+ def index
7
+ @page = (params[:page] || DEFAULT_PAGE).to_i
8
+ @per = (params[:per] || DEFAULT_PER_PAGE).to_i
9
+
10
+ mail_records = MailRecord.search_by_text(params[:q])
11
+
12
+ @total_count = mail_records.count
13
+
14
+ offset = (@page - 1) * @per
15
+
16
+ @mail_records = mail_records
17
+ .order(sent_at: sort_order)
18
+ .limit(@per)
19
+ .offset(offset)
20
+ end
21
+
22
+ def show
23
+ @mail_record = MailRecord.find(params[:id])
24
+ end
25
+
26
+ def destroy
27
+ @mail_record = MailRecord.find(params[:id])
28
+ @mail_record.destroy
29
+ redirect_to mail_records_path
30
+ end
31
+
32
+ private
33
+
34
+ def sort_order
35
+ params[:sort] == "asc" ? :asc : :desc
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,37 @@
1
+ module LetterOpenerDb
2
+ class MailRecord < ApplicationRecord
3
+ validates :to, presence: true
4
+ validates :subject, presence: true
5
+
6
+ scope :search_by_text, ->(keyword) {
7
+ if keyword.present?
8
+ where(
9
+ "subject LIKE :q OR html_part LIKE :q OR text_part LIKE :q
10
+ OR \"to\" = :keyword OR \"from\" = :keyword",
11
+ q: "%#{keyword}%",
12
+ keyword: keyword
13
+ )
14
+ else
15
+ all
16
+ end
17
+ }
18
+
19
+ def body_html
20
+ return "" if html_part.blank?
21
+
22
+ _, content = html_part.split("\r\n\r\n", 2)
23
+ content.to_s.strip
24
+ end
25
+
26
+ def body_text
27
+ return "" if text_part.blank?
28
+
29
+ _, content = text_part.split("\r\n\r\n", 2)
30
+ content.to_s.strip
31
+ end
32
+
33
+ def body_preview
34
+ body_text[0, 30]
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,217 @@
1
+ <style>
2
+ /* Overall layout */
3
+ body {
4
+ font-family: sans-serif;
5
+ margin: 20px;
6
+ background-color: #f8f8f8;
7
+ }
8
+
9
+ .lo-db-container {
10
+ max-width: 900px;
11
+ margin: 0 auto;
12
+ background-color: #fff;
13
+ padding: 16px;
14
+ border-radius: 6px;
15
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
16
+ }
17
+
18
+ h1 {
19
+ margin-bottom: 16px;
20
+ color: #333;
21
+ }
22
+
23
+ /* Search form area */
24
+ .lo-db-search-row {
25
+ display: flex;
26
+ justify-content: space-between;
27
+ align-items: center;
28
+ margin-bottom: 16px;
29
+ }
30
+ .lo-db-search-form {
31
+ display: inline-flex;
32
+ align-items: center;
33
+ }
34
+ .lo-db-search-form input[type="text"] {
35
+ padding: 6px 8px;
36
+ font-size: 14px;
37
+ border: 1px solid #ccc;
38
+ border-radius: 4px;
39
+ margin-right: 6px;
40
+ }
41
+ .lo-db-search-form select {
42
+ margin-left: 6px;
43
+ padding: 4px 6px;
44
+ font-size: 14px;
45
+ }
46
+ .lo-db-search-form input[type="submit"] {
47
+ margin-left: 6px;
48
+ padding: 6px 12px;
49
+ font-size: 14px;
50
+ border: none;
51
+ border-radius: 4px;
52
+ background-color: #333;
53
+ color: #fff;
54
+ cursor: pointer;
55
+ }
56
+ .lo-db-search-form input[type="submit"]:hover {
57
+ background-color: #555;
58
+ }
59
+
60
+ .lo-db-total-count {
61
+ font-size: 14px;
62
+ }
63
+
64
+ /* Table */
65
+ table.lo-db-table {
66
+ width: 100%;
67
+ border-collapse: collapse;
68
+ }
69
+ table.lo-db-table thead {
70
+ background-color: #f3f3f3;
71
+ }
72
+ table.lo-db-table th,
73
+ table.lo-db-table td {
74
+ border: 1px solid #ddd;
75
+ padding: 8px;
76
+ text-align: left;
77
+ vertical-align: middle;
78
+ }
79
+ table.lo-db-table th {
80
+ font-weight: bold;
81
+ color: #333;
82
+ }
83
+ table.lo-db-table tbody tr:nth-child(even) {
84
+ background-color: #fafafa;
85
+ }
86
+ table.lo-db-table a {
87
+ color: #0066cc;
88
+ text-decoration: none;
89
+ }
90
+ table.lo-db-table a:hover {
91
+ text-decoration: underline;
92
+ }
93
+
94
+ /* Pagination */
95
+ .lo-db-pagination {
96
+ margin-top: 36px;
97
+ margin-bottom: 16px;
98
+ display: flex;
99
+ align-items: center;
100
+ justify-content: center;
101
+ gap: 12px;
102
+ }
103
+ .lo-db-pagination .page-info {
104
+ font-weight: bold;
105
+ margin: 0 4px;
106
+ }
107
+ .lo-db-pagination a {
108
+ color: #0066cc;
109
+ text-decoration: none;
110
+ border: 1px solid #ccc;
111
+ padding: 4px 8px;
112
+ border-radius: 4px;
113
+ font-size: 14px;
114
+ background-color: #f9f9f9;
115
+ }
116
+ .lo-db-pagination a:hover {
117
+ background-color: #ddd;
118
+ }
119
+ .lo-db-pagination .disabled-link {
120
+ color: #999;
121
+ border-color: #eee;
122
+ background-color: #fafafa;
123
+ cursor: not-allowed;
124
+ text-decoration: none;
125
+ }
126
+ </style>
127
+
128
+ <div class="lo-db-container">
129
+ <h1>Letter Opener DB</h1>
130
+
131
+ <!-- Search row -->
132
+ <div class="lo-db-search-row">
133
+ <!-- Search form -->
134
+ <%= form_with url: mail_records_path, method: :get, local: true, class: "lo-db-search-form" do |f| %>
135
+ <!-- Keyword -->
136
+ <%= f.text_field :q, value: params[:q] %>
137
+
138
+ <!-- Sort by date: asc or desc -->
139
+ <label for="sort_select" style="margin-left: 8px;">Sort by date</label>
140
+ <%= f.select :sort, [["Newest first", "desc"], ["Oldest first", "asc"]],
141
+ { selected: params[:sort] || "desc" },
142
+ { id: "sort_select" } %>
143
+
144
+ <!-- Per page selection -->
145
+ <label for="per_input" style="margin-left: 8px;">Per Page</label>
146
+ <%= f.select :per, [10, 25, 50, 100].map {|n| [n, n]}, { selected: @per }, { id: "per_input" } %>
147
+
148
+ <%= f.submit "Search" %>
149
+ <% end %>
150
+
151
+ <!-- Total record count -->
152
+ <div class="lo-db-total-count">
153
+ Total: <%= @total_count %> mails
154
+ </div>
155
+ </div>
156
+
157
+ <!-- Table of mail records -->
158
+ <table class="lo-db-table">
159
+ <thead>
160
+ <tr>
161
+ <th>Subject</th>
162
+ <th>To</th>
163
+ <th>From</th>
164
+ <th>Sent At</th>
165
+ <th>Body Preview</th>
166
+ </tr>
167
+ </thead>
168
+ <tbody>
169
+ <% @mail_records.each do |record| %>
170
+ <tr>
171
+ <td>
172
+ <%= link_to record.subject,
173
+ mail_record_path(record,
174
+ sort: params[:sort],
175
+ per: @per,
176
+ q: params[:q],
177
+ page: @page
178
+ ) %>
179
+ </td>
180
+ <td><%= record.to %></td>
181
+ <td><%= record.from %></td>
182
+ <td><%= record.sent_at.strftime("%Y-%m-%d %H:%M:%S") %></td>
183
+ <td><%= record.body_preview %>...</td>
184
+ </tr>
185
+ <% end %>
186
+ </tbody>
187
+ </table>
188
+
189
+ <!-- Pagination: Prev / Next -->
190
+ <div class="lo-db-pagination">
191
+ <% total_pages = (@total_count.to_f / @per).ceil %>
192
+
193
+ <% prev_page = @page - 1 %>
194
+ <% next_page = @page + 1 %>
195
+
196
+ <!-- Prev link -->
197
+ <% if @page > 1 %>
198
+ <%= link_to "Prev",
199
+ mail_records_path(page: prev_page, per: @per, sort: params[:sort], q: params[:q]) %>
200
+ <% else %>
201
+ <a class="disabled-link">Prev</a>
202
+ <% end %>
203
+
204
+ <!-- Page info: "Page X / Y" -->
205
+ <span class="page-info">
206
+ Page <%= @page %> / <%= total_pages %>
207
+ </span>
208
+
209
+ <!-- Next link -->
210
+ <% if @page < total_pages %>
211
+ <%= link_to "Next",
212
+ mail_records_path(page: next_page, per: @per, sort: params[:sort], q: params[:q]) %>
213
+ <% else %>
214
+ <a class="disabled-link">Next</a>
215
+ <% end %>
216
+ </div>
217
+ </div>
@@ -0,0 +1,102 @@
1
+ <style>
2
+ body {
3
+ font-family: sans-serif;
4
+ margin: 20px;
5
+ background-color: #f8f8f8;
6
+ }
7
+
8
+ .lo-db-show-container {
9
+ max-width: 800px;
10
+ margin: 0 auto;
11
+ padding: 16px;
12
+ background-color: #fff;
13
+ border-radius: 6px;
14
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
15
+ position: relative;
16
+ }
17
+
18
+ .lo-db-show-container h1 {
19
+ margin-top: 0;
20
+ color: #333;
21
+ }
22
+
23
+ .lo-db-meta p {
24
+ margin: 0 0 5px;
25
+ }
26
+
27
+ .lo-db-part {
28
+ margin-bottom: 16px;
29
+ padding: 10px;
30
+ border: 1px solid #ccc;
31
+ background-color: #fafafa;
32
+ border-radius: 4px;
33
+ }
34
+
35
+ .lo-db-part h2 {
36
+ margin-top: 0;
37
+ }
38
+
39
+ .lo-db-delete-form {
40
+ position: absolute;
41
+ top: 16px;
42
+ right: 16px;
43
+ }
44
+
45
+ .lo-db-delete-button {
46
+ padding: 6px 12px;
47
+ background-color: #c00;
48
+ color: #fff;
49
+ border: none;
50
+ border-radius: 4px;
51
+ cursor: pointer;
52
+ }
53
+ .lo-db-delete-button:hover {
54
+ background-color: #a00;
55
+ }
56
+
57
+ .lo-db-back-link {
58
+ display: inline-block;
59
+ margin-top: 16px;
60
+ padding: 6px 12px;
61
+ background-color: #333;
62
+ color: #fff;
63
+ text-decoration: none;
64
+ border-radius: 4px;
65
+ }
66
+ .lo-db-back-link:hover {
67
+ background-color: #555;
68
+ }
69
+ </style>
70
+
71
+ <div class="lo-db-show-container">
72
+ <%= form_with url: mail_record_path(@mail_record), method: :delete, local: true, class: "lo-db-delete-form" do %>
73
+ <%= button_tag "Delete",
74
+ class: "lo-db-delete-button" %>
75
+ <% end %>
76
+
77
+ <h1><%= @mail_record.subject %></h1>
78
+
79
+ <div class="lo-db-meta">
80
+ <p><strong>To:</strong> <%= @mail_record.to %></p>
81
+ <p><strong>From:</strong> <%= @mail_record.from %></p>
82
+ <p><strong>Sent At:</strong> <%= @mail_record.sent_at %></p>
83
+ </div>
84
+
85
+ <hr />
86
+
87
+ <% if @mail_record.html_part.present? %>
88
+ <div class="lo-db-part">
89
+ <h2>HTML Part</h2>
90
+ <%= raw @mail_record.body_html %>
91
+ </div>
92
+ <% end %>
93
+
94
+ <% if @mail_record.text_part.present? %>
95
+ <div class="lo-db-part">
96
+ <h2>Text Part</h2>
97
+ <pre><%= @mail_record.body_text %></pre>
98
+ </div>
99
+ <% end %>
100
+
101
+ <%= link_to "Back", mail_records_path, class: "lo-db-back-link" %>
102
+ </div>
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ LetterOpenerDb::Engine.routes.draw do
2
+ resources :mail_records, only: [:index, :show, :destroy]
3
+ end
@@ -0,0 +1,20 @@
1
+ require "rails/generators"
2
+ require "rails/generators/migration"
3
+
4
+ module LetterOpenerDb
5
+ class InstallGenerator < Rails::Generators::Base
6
+ include Rails::Generators::Migration
7
+ source_root File.expand_path('templates', __dir__)
8
+
9
+ def self.next_migration_number(_dirname)
10
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
11
+ end
12
+
13
+ def copy_migrations
14
+ migration_template(
15
+ "create_letter_opener_db_mail_records.rb",
16
+ "db/migrate/create_letter_opener_db_mail_records.rb"
17
+ )
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ class CreateLetterOpenerDbMailRecords < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :letter_opener_db_mail_records do |t|
4
+ t.text :to
5
+ t.text :from
6
+ t.text :subject
7
+ t.text :html_part
8
+ t.text :text_part
9
+ t.datetime :sent_at
10
+
11
+ t.timestamps
12
+ end
13
+
14
+ add_index :letter_opener_db_mail_records,
15
+ [:to, :subject, :html_part, :text_part],
16
+ name: "index_letter_opener_db_mail_records_on_to_and_subject_and_body"
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module LetterOpenerDb
2
+ class DeliveryMethod
3
+ def initialize(values)
4
+ @settings = values
5
+ end
6
+
7
+ def deliver!(mail)
8
+ MailRecord.create!(
9
+ to: mail.to.join(", "),
10
+ from: mail.from.join(", "),
11
+ subject: mail.subject,
12
+ html_part: mail.html_part,
13
+ text_part: mail.text_part,
14
+ sent_at: Time.current
15
+ )
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ module LetterOpenerDb
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace LetterOpenerDb
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ module LetterOpenerDb
2
+ class Railtie < ::Rails::Railtie
3
+ initializer "letter_opener_db.add_delivery_method" do
4
+ ActiveSupport.on_load(:action_mailer) do
5
+ require "letter_opener_db/delivery_method"
6
+ ActionMailer::Base.add_delivery_method :letter_opener_db, LetterOpenerDb::DeliveryMethod
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LetterOpenerDb
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "letter_opener_db/version"
4
+ if defined?(Rails)
5
+ require "letter_opener_db/railtie"
6
+ require "letter_opener_db/engine"
7
+ require "generators/letter_opener_db/install/install_generator"
8
+ require "letter_opener_db/delivery_method"
9
+ end
10
+
11
+ module LetterOpenerDb
12
+ class Error < StandardError; end
13
+ end
@@ -0,0 +1,8 @@
1
+ namespace :letter_opener_db do
2
+ namespace :install do
3
+ desc "Run the LetterOpenerDb install generator (copy migrations)"
4
+ task :migrations => :environment do
5
+ Rails::Generators.invoke("letter_opener_db:install")
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ module LetterOpenerDb
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: letter_opener_db
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Peter Takahashi
8
+ - Seiya Takahashi
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2025-02-22 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A gem that stores ActionMailer emails in the database and allows searching.
15
+ email:
16
+ - seiya4@icloud.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - ".rspec"
22
+ - LICENSE.txt
23
+ - README.md
24
+ - README_JA.md
25
+ - Rakefile
26
+ - app/controllers/letter_opener_db/mail_records_controller.rb
27
+ - app/models/letter_opener_db/mail_record.rb
28
+ - app/views/letter_opener_db/mail_records/index.html.erb
29
+ - app/views/letter_opener_db/mail_records/show.html.erb
30
+ - config/routes.rb
31
+ - lib/generators/letter_opener_db/install/install_generator.rb
32
+ - lib/generators/letter_opener_db/install/templates/create_letter_opener_db_mail_records.rb
33
+ - lib/letter_opener_db.rb
34
+ - lib/letter_opener_db/delivery_method.rb
35
+ - lib/letter_opener_db/engine.rb
36
+ - lib/letter_opener_db/railtie.rb
37
+ - lib/letter_opener_db/version.rb
38
+ - lib/tasks/letter_opener_db.rake
39
+ - sig/letter_opener_db.rbs
40
+ homepage: https://github.com/PeterTakahashi/letter_opener_db
41
+ licenses:
42
+ - MIT
43
+ metadata:
44
+ homepage_uri: https://github.com/PeterTakahashi/letter_opener_db
45
+ source_code_uri: https://github.com/PeterTakahashi/letter_opener_db
46
+ changelog_uri: https://github.com/PeterTakahashi/letter_opener_db/blob/main/CHANGELOG.md
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ - app
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '2.6'
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ requirements: []
63
+ rubygems_version: 3.5.11
64
+ signing_key:
65
+ specification_version: 4
66
+ summary: Save mail sending history to DB (like letter_opener)
67
+ test_files: []