はじめに
こんにちは、すずゆーと申します。
突然ですが皆様は飯テロをしたことはありますでしょうか。
私はSNSに美味しいご飯をアップするのが大好きです。
アップした写真に対してフォロワーさんからの反応を楽しむのが大好きです。
しかし、SNSだとせっかくアップしても本当に見てもらいたい人に見てもらえない時があったり...
そんな中、LINEなら確実に相手に届くし見てもらえるじゃん!ということで私の悪戯心を具現化したアプリを開発しました。
記事を読む上での注意点
当記事はプログラミング学習を開始して日の浅い業界未経験者が書いたものになりますので、技術的な内容などは誤りを含む可能性があります。予めご了承ください。
サービス名
飯テログ
URL: https://meshitelog.com
GitHub: https://github.com/suzuyu0115/meshitelog
飯テログは、LINEAPIを通じて好きな飯画像を好きな時間に好きな相手に飯テロできる、
ユーザー投稿型の飯テロサービスです。
LINEベースのアプリケーションのため、スマホからの使用をおすすめしております。
開発背景
私は一般男性と比較すると痩せ型体型にあり、もっと太りたいという願望を持っていました。
しかし、なかなか食欲が湧かず、太りたくても太れないという状況にありました。
そこで、食欲を促進してくれるサービスがあればいいなと考え、当アプリの開発に至りました。
飯テロは、「第三者から、不意に食欲を刺激させる」ということが必要になるため、多くの人が頻繁に利用するツールであるLINEで通知が届くようにし、飯テロを避けられないように工夫しました。また、飯テロの投稿が届く時間を指定できたり、送信相手をランダムに設定できる機能なども実装しております。
サービス概要
LINEログイン機能
ログイン機能にはLIFF(LINE Front-end Framework)を使用しております。
飯テログ公式アカウントに友達追加をしていただき、あいさつメッセージのURLを踏んでいただくだけでユーザー登録が完結します。
↓トップ画面の友だち追加ボタンから公式アカウントを友だち追加
↓メッセージのURLを押下することで登録完了!
LIFFとは
LIFFとは、LINE Front-end Frameworkの頭文字を取ったもので、LINEが提供するウェブアプリのプラットフォームになります。
LIFFとはLINEアプリ上で動作するブラウザのことです。
LINEのトーク画面でURLを開くと、ChromeやSafariなどの外部ブラウザが開きますが、LIFFアプリのURLを開くと、LINEアプリ内部でブラウザが開きます。
またLIFFアプリは、他のブラウザで使用することもでき、登録しているメールアドレスやユーザーIDなど、LINEの情報を取得できるアプリとなります。
こちらでは細かい解説は省きますが、下記の記事がとても参考になりましのでLIFFに興味を持たれた方は拝見してみてください。
飯一覧機能
飯一覧では、ユーザーの飯投稿が表示されます。
新着順、人気順のソートの他、あなたへのおすすめでは各ユーザーそれぞれに適したおすすめの飯がレコメンドされます。
レコメンド機能について
class User < ApplicationRecord
...
def similar_users
# このユーザーがいいねした投稿をいいねしているユーザーを取得
user_ids = Bookmark.where(post_id: bookmark_posts.ids).pluck(:user_id)
User.where(id: user_ids)
end
def recommended_posts
# 類似ユーザーがいいねした投稿の中から、このユーザーがまだいいねしていない投稿を取得
post_ids = Bookmark.where(user_id: similar_users.ids).pluck(:post_id)
Post.where(id: post_ids).where.not(id: bookmark_posts.ids)
end
end
レコメンド機能は、自分と同じ投稿をいいねしているユーザーのいいね履歴を参照し、その履歴の中から自身がいいねしていない投稿を表示させるロジックを組んでいます。
飯投稿機能
飯名、コメント、飯画像を添えて飯投稿をすることができます。
投稿フォームにはモデルバリデーションの他にJSを用いたフロントのバリデーションを施し、飯名、コメントを記載しないと投稿ボタンが押下できない仕様にしています。
飯テロ機能
飯テロを送りたいユーザーを選択することで、そのユーザーのLINEに向けて飯テロをすることができます。
送り相手は任意に複数人選択できるほか、全ユーザー、ランダムなユーザー10人に向けて飯テロすることができます。
また、投稿日時を指定することで相手に届く時間を指定できるため、お腹の空いている深夜帯などの時間目掛けての飯テロも可能です。
送り相手にはFlexMwssage形式に整形されて飯テロが送信されます。
FlexMessageとは
LINEMessagingAPIのフォーマットの一つで、送信メッセージのレイアウトを自由にカスタマイズすることができる機能です。
Flex Messageは、通常のLINEメッセージに比べ、より豊かでインタラクティブなレイアウトが可能なメッセージです。通常のLINEメッセージでは、テキスト、画像、動画など1種類のソースしか配信されません。しかし、Flex Messageでは、CSS Flexible Box(CSS Flexbox) (opens new window)の仕様に基づいて、レイアウトを自由にカスタマイズできます。
以下のリンクからFlexMessageのシミュレーションができます。(LINE Developersコンソールへのログインが必要です)
https://developers.line.biz/flex-simulator/
検索機能
飯名とタグ名から投稿の検索ができます。
検索のユーザビリティ向上のため、飯名検索にはインクリメンタルサーチ、タグ名検索フォームはオートコンプリートを搭載しました。
X(旧Twitter)シェア機能
投稿されている飯は、Xシェアボタンからシェアが可能です。
OGP画像は動的に生成されるようにしているため、投稿の飯画像がOGP画像としてそのまま表示されます。
そのため、飯テログに登録していない不特定多数に向けて視覚的な飯テロを行うこともできます。
苦労した点
送信相手の選択とLINEへの紐付け
送信相手を指定しての投稿、且つその送信相手へLINE通知として送信するロジックの実装が個人的には苦労したポイントでしたので、備忘録を兼ねて簡単に記載します。
1.中間テーブルの作成
まずは、UsersテーブルとPostsテーブルの中間テーブルdeliveries
テーブルを作成し、多対多のアソシエーションを敷きました。
こちらを追加することで投稿をDeliveries
を通じて複数のユーザーに向けて送信できるようにしました。
class CreateDeliveries < ActiveRecord::Migration[7.0]
def change
create_table :deliveries do |t|
t.references :user, null: false, foreign_key: true
t.references :post, null: false, foreign_key: true
t.timestamps
end
end
end
$ bundle exec rails db:migrate
2.LINE Developersへの登録
LINEのAPIを使用するためには、LINEDevelopersへの登録しました。
参考記事が多く、冗長になってしまうため具体的な登録方法等は割愛します。
https://developers.line.biz/ja/
3.FlexMessageの構築
# nicknameがあればnicknameを、なければnameを返す
def sender_name
user.nickname || user.name
end
# 各投稿詳細ページのURLを返す
def post_url
"#{ROOT_URL}/posts/#{id}"
end
def notify_line
# 予約投稿か否かを判定
return unless published?
line_client = LineClient.new
flex_contents = {
type: "bubble",
header: {
type: 'box',
layout: 'vertical',
contents: [
{
type: 'text',
text: "飯が届きました!",
weight: "bold",
size: "xl",
wrap: true
}
]
},
hero: {
type: "image",
url: food_image.url,
size: "full",
aspectRatio: "20:13",
aspectMode: "cover",
action: {
type: "uri",
uri: post_url
}
},
body: {
type: "box",
layout: "vertical",
contents: [
{
type: "text",
text: title,
weight: "bold",
size: "xl",
wrap: true
},
{
type: "box",
layout: "vertical",
margin: "lg",
spacing: "sm",
contents: [
{
type: "box",
layout: "baseline",
spacing: "sm",
contents: [
{
type: "text",
text: "#{sender_name} さんより",
wrap: true,
color: "#666666",
size: "sm",
flex: 5
}
]
},
{
type: "box",
layout: "baseline",
spacing: "sm",
contents: [
{
type: "text",
text: content,
wrap: true,
color: "#666666",
size: "md",
flex: 5
}
]
}
]
}
]
},
footer: {
type: "box",
layout: "vertical",
spacing: "sm",
contents: [
{
type: "button",
style: "link",
height: "sm",
action: {
type: "uri",
label: "詳細を見る",
uri: post_url
}
},
{
type: "box",
layout: "vertical",
contents: [],
margin: "sm"
}
],
flex: 0
}
}
deliveries.each do |delivery|
line_client.push_flex_message(delivery.user.line_user_id, "飯が届きました!: #{title}", flex_contents)
end
end
notify_line
メソッドは、投稿が公開された際にLINEユーザーに通知を送信する役割を担っています。
このメソッド内のflex_contents
ハッシュ内でFlexMessageの中身を構築しています。
そして、deliveries
に格納されているLINEユーザーに対して、push_flex_message
メソッドを使用してFlexメッセージを送信します。push_flex_message
については下記に後述します。
4.FlexMessageを送信する
require 'line/bot'
class LineClient
def initialize
@client = Line::Bot::Client.new do |config|
config.channel_secret = ENV.fetch("LINE_MESSAGING_CHANNEL_SECRET", nil)
config.channel_token = ENV.fetch("LINE_MESSAGING_CHANNEL_TOKEN", nil)
end
end
# フレックスメッセージ送信
def push_flex_message(user_id, alt_text, contents)
message = {
type: 'flex',
altText: alt_text,
contents:
}
@client.push_message(user_id, message)
end
end
こちらではLINEMessagingAPIを使用するためのコードを記載しています。
LINE_MESSAGING_CHANNEL_SECRET
とLINE_MESSAGING_CHANNEL_TOKEN
はMessagingAPIにアクセスするための重要な環境変数になるので、使用する際はdotenv-rails
などを使って厳密に保管することをおすすめします。
push_flex_message
メソッドは、notify_line
メソッドからuser_id(LINEユーザーのID)
、alt_text(代替テキスト)
、および contents(Flexメッセージの内容)
の引数を受け取り、
@client.push_message
メソッドを使用して指定されたユーザーに対してFlexメッセージを送信します。
要約すると、notify_line
メソッド内で具体的なFlexメッセージの内容を構築したものを、push_flex_message
メソッドで送信するロジックを構築しています。
主な使用技術
バックエンド
- Ruby(3.2.2)
- Rails(7.0.5)
- Redis(4.0)
- Sidekiq
フロントエンド
- JavaScript
- jQuery
- Bootstrap(5.3.0)
- Hotwire
- LINE Front-end Framework(LIFF)
インフラ
- Heroku
- mkcert
データベース
- PostgreSQL
API
- LINEMessagingAPI
ER図
最後に
初めてのWebアプリ作成でしたが、とても学びになることが多かったです。
記事に起こすのも初めてでしたが、頭で理解できていることを読み手に理解しやすいように文字にするのがとても難しく、書きながらアウトプットの大変さを痛感しています。
この記事を読んで「自分も飯テロしてみたい!」と思っていただけましたら、ぜひ私のアプリを触っていただけると大変嬉しいです✨
拙い文章でしたが、最後までお読みいただき誠にありがとうございました!