はじめに
日本には四季折々の旬の食材がありますが、こんな経験はありませんか?
- 「今の時期、何が旬なんだっけ?」
- 「スーパーで見かけたけど、旬かどうか分からない」
- 「旬の食材を取り寄せたいけど、探すのが面倒」
そんな悩みを解決するために、**食べナウ(tabenow)**というサービスを作りました。野菜・果物・魚介の旬カレンダーをDBに持ち、毎週金曜日の朝に旬の食材と楽天のおすすめ商品をメールでお届けします。
単純に自分が欲しかったんです。
🔗 サービスURL: https://tabenow.com
食べナウの特徴
🗓️ 173品の旬カレンダー
野菜30品・果物20品以上・魚介20品以上、合計173品の旬データをDBに格納しています。各食材には旬の開始月・終了月・最盛月(peak_month)を設定し、月跨ぎ(例: 11月〜2月)にも対応しています。
scope :in_season, ->(month) {
where("season_start_month <= season_end_month AND ? BETWEEN season_start_month AND season_end_month", month)
.or(where("season_start_month > season_end_month AND (? >= season_start_month OR ? <= season_end_month)", month, month))
}
11月〜2月のように年をまたぐ旬のケースを、OR条件で正しく処理しています。
🍅 毎週金曜の旬食材ダイジェストメール
- カテゴリ別3品ずつ: 旬の野菜・旬の果物・旬の魚介から各3品を選出
- 最盛月を優先選出: peak_monthが現在月の食材を優先的にピックアップ
- 月内重複回避: 同月内で既に紹介した食材は次週の候補から除外
- 楽天の商品リンク付き: 各食材にレビュー数順でおすすめ商品を自動検索
- ダークモード対応: HTMLメールはlight/dark両対応
🏡 ふるさと納税で先取り
メールの末尾には「ふるさと納税で先取り」セクションがあります。2ヶ月先に旬を迎える食材を楽天ふるさと納税で検索し、先取りでお取り寄せできる商品を紹介しています。
🤖 PLaMo APIで紹介文を自動生成
各食材の紹介文は、Preferred Networks社の日本語特化LLM PLaMo 2.0 Prime で自動生成しています。OpenAI互換のAPIなので、Net::HTTPで直接リクエストを送るだけで使えます。
class DescriptionService
BASE_URL = "https://api.platform.preferredai.jp/v1"
MODEL = "plamo-2.0-prime"
def generate_issue_descriptions(items)
items_text = items.map { |item|
"- #{item.name}(#{CATEGORY_LABELS[item.category]}、#{item.season_start_month}月〜#{item.season_end_month}月)"
}.join("\n")
prompt = "以下の旬の食材それぞれについて、今の時期に食べる魅力を1〜2文で簡潔に紹介してください。\n" \
"JSON形式で「{\"食材名\": \"紹介文\"}」として返してください。\n\n#{items_text}"
text = chat(prompt)
JSON.parse(text.match(/\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}/m)[0])
end
end
バッチ生成時はJSON形式でまとめて返してもらうことで、API呼び出し回数を1回に抑えています。
週次ジョブの全体フロー
WeeklySeasonalDigestJob (毎週金曜6:00 AM JST)
→ SeasonalItem.in_season(month) : 今月の旬食材をDBから取得
→ pick_items : カテゴリ別3品ずつ選出(最盛月優先・月内重複回避)
→ DescriptionService : PLaMo APIで紹介文を自動生成
→ RakutenIchibaService : raku-cliで楽天市場APIから商品検索
→ find_furusato_items : 2ヶ月先の旬食材でふるさと納税検索
→ EmailIssue.create! : 号を作成
→ SeasonalDigestMailer : 全confirmed購読者にdeliver_later
Solid Queueのrecurring.ymlで毎週金曜のcronスケジュールとして設定しています。
production:
weekly_seasonal_digest:
class: WeeklySeasonalDigestJob
queue: default
schedule: "0 6 * * 5 Asia/Tokyo"
自作CLIツールの活用
raku-cli
楽天APIをコマンドラインから操作するGoで書いたCLI。食べナウでは楽天市場の商品検索とふるさと納税商品の検索に使用しています。
🔗 GitHub: https://github.com/dugabot0/raku-cli
class RakutenIchibaService
RAKU_CLI = File.join(ENV["HOME"], "bin", "raku-cli")
def search(keyword, hits: 5, genre_id: nil)
args = ["ichiba", "items", "--keyword", keyword,
"--hits", hits.to_s, "--sort", "-reviewCount",
"--ng-keyword", "ふるさと納税 詰め合わせ"]
args += ["--genre-id", genre_id.to_s] if genre_id
output = run_cli(*args)
# ... 商品データをパース
end
end
カテゴリ別のジャンルID(野菜: 200990、果物: 100246、魚介: 100236)で絞り込み、レビュー数順でソート。同一ショップの重複を排除するロジックも入っています。
マネタイズ
楽天アフィリエイトで収益化しています。
- 通常商品: 各旬食材の楽天市場おすすめ商品
- ふるさと納税: 2ヶ月先の旬食材をふるさと納税で先取り
ふるさと納税は単価が高いため、アフィリエイト収益としても期待できます。
技術スタック
| 分野 | 技術 |
|---|---|
| バックエンド | Rails 8.0.4 |
| データベース | SQLite3(本番含む) |
| フロントエンド | Import Maps + Turbo + Stimulus |
| キャッシュ | Solid Cache |
| ジョブ処理 | Solid Queue |
| メール | Action Mailer(HTML/テキスト両対応) |
| 紹介文生成 | PLaMo 2.0 Prime(OpenAI互換API) |
| 商品検索 | raku-cli(自作Go CLI) |
| デプロイ | Kamal + Docker |
姉妹プロジェクトのyomitechと技術スタック・設計パターンを共有しています。
yomitechとの共通パターン
食べナウはyomitech(読テク)と同じ設計パターンで作られています。
- 週次メール配信: EmailIssueモデルで号を管理し、購読者にdeliver_later
- トークンベースの購読管理: ユーザーアカウント不要、メールアドレスのみで登録・確認・解除
- raku-cliによる楽天API連携: 書籍検索(yomitech)→ 市場商品検索(食べナウ)
- Kamal + Docker デプロイ: 同一の本番インフラ
- SQLite3本番運用: Rails 8のSolidスタック
一度パターンが確立すると、2つ目以降のサービスは驚くほど早く作れます。AIに同じように作ってというだけですから。差分を言えばOK。
おわりに
食べナウは「日本の旬をもっと身近に」をコンセプトに作ったサービスです。
173品の旬カレンダーデータをベースに、PLaMo APIで紹介文を生成し、raku-cliで楽天商品を自動検索。毎週金曜の朝、旬の食材情報がメールで届きます。
メールアドレスを登録するだけで、毎週金曜の朝に旬食材ダイジェストが届きます。ぜひお試しください!
🔗 食べナウ: https://tabenow.com
🔗 yomitech: https://yomitech.app
🔗 raku-cli: https://github.com/dugabot0/raku-cli