動かざることバグの如し

近づきたいよ 君の理想に

Railsで特定のレコードを先頭にしてソートする方法

環境

やりたいこと

例えばRailsのUsersモデルで10件レコードを取得し、emailが"hoge@example.com"のレコードを先頭にしたいみたいな状況

この場合はRubyで並び替えてもいいが、MySQLのORDER BYで特定のレコードのみを先頭にすることができる。

やりかた

下記のように書くと、emailが"hoge@example.com"のレコードが先頭になります。

users = User.limit(10).order("case when email = 'hoge@example.com' then 0 else 1 end")

この場合、case文を使ってemailが"hoge@example.com"のときは0、そうでないときは1を返すようにしています。そして、0と1で昇順に並び替えることで、emailが"hoge@example.com"のレコードが先頭になります。

もし、他のカラムでも並び替えたい場合は、orderメソッドに続けて指定することができます。例えば、idで降順に並び替えたい場合は、下記のように書きます。

users = User.limit(10).order("case when email = 'hoge@example.com' then 0 else 1 end, id DESC")

このようにorderメソッドを使って特定の値で並び替えることができます。

参考リンク

RailsでCookieのSameSite属性を指定する方法

CookieのSameSite属性とは

CookieのSameSite属性は、Webサイトのセキュリティを向上させるために導入された機能です。

SameSite属性を指定することで、Cookieがどのような場合に送信されるかを制御することができます。

SameSite属性には、以下の3つの値があります。

  • Strict: SameSite属性が指定された場合、Cookieは同一オリジンからのリクエストにのみ送信されます。
  • Lax: SameSite属性が指定された場合、Cookieは同一オリジンからのリクエストに加えて、外部ドメインからのGETリクエストにも送信されます。
  • None: SameSite属性が指定されなかった場合、Cookieはすべてのリクエストに送信されます。

RailsでSameSite属性を指定する方法

Railsでは、CookieのSameSite属性を指定するために、cookiesメソッドを使用します。以下は、SameSite属性をStrictに指定する例です。

cookies[:user_id] = {
  value: current_user.id,
  same_site: :strict
}

同様に、Laxに指定する場合は:lax、Noneに指定する場合は:noneを指定します。

cookies[:user_id] = {
  value: current_user.id,
  same_site: :lax
}
cookies[:user_id] = {
  value: current_user.id,
  same_site: :none
}

以上が、Railsで個別でCookieのSameSite属性を指定する方法です。セキュリティを向上させるために、適切なSameSite属性を指定するようにしましょう。

一括で設定したい場合は以下

config.action_dispatch.cookies_same_site_protection = :strict

これにより、すべてのCookieにSameSite属性が設定され、Strictモードが有効になります。

Rails 5.1以前を使用している場合は、Rackのmiddlewareを使用してSameSite属性を設定する必要があります。config/application.rbファイルに以下のコードを追加します。

config.middleware.insert_before(ActionDispatch::Cookies, Rack::SameSite, :none)

これにより、すべてのCookieにSameSite属性が設定され、Noneモードが有効になります。

参考リンク

dragon ash気になった曲まとめ

曲名 リリース年 初収録CD名 歌詞のテーマ
百合の咲く場所で 2001 LILY OF DA VALLEY 新しい時代への期待と不安、仲間との絆
静かな日々の階段を 2000 Lily's e.p. 生きることの苦しさと希望、夢への挑戦
Just I'll say 1999 Viva La Revolution 恋人と別れた後の寂しさと後悔
TIME OF YOUR LIFE 2002 Life goes on 自分らしく生きることをメッセージにした曲
Lily 2001 LILY OF DA VALLEY 愛する人への想いを歌ったバラード
My Friend 1999 Viva La Revolution 友情や仲間をテーマにしたナンバー

JSの最強日付フォーマットは「toLocaleDateString」

toLocaleDateStringメソッドとは

JavaScriptには、日付を文字列に変換するためのtoLocaleDateStringメソッドがあります。このメソッドは、ブラウザのロケールに基づいて、日付を指定されたフォーマットに変換します。

例えば、以下のように使用することができます。

const date = new Date();
const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
console.log(date.toLocaleDateString('ja-JP', options));
// 2023年5月20日土曜日

toLocaleDateStringメソッドのオプション

toLocaleDateStringメソッドには、フォーマットをカスタマイズするためのオプションがあります。以下は、よく使用されるオプションの例です。

  • weekday: 曜日を表す文字列を指定します。
  • year: 年を表す文字列を指定します。
  • month: 月を表す文字列を指定します。
  • day: 日を表す文字列を指定します。

これらのオプションは、必要に応じて組み合わせて使用することができます。また、ロケールによっては、他にも使用可能なオプションがあります。

フォーマット例

曜日

例: 2023年5月20日 (金)

const date = new Date();
const options = { year: 'numeric', month: 'long', day: 'numeric', weekday: 'long' };
const formattedDate = date.toLocaleDateString('ja-JP', options);
console.log(formattedDate);

ゼロ詰めした月日

例: 2023年05月20日

const date = new Date();
const options = { year: 'numeric', month: '2-digit', day: '2-digit' };
const formattedDate = date.toLocaleDateString('ja-JP', options);
console.log(formattedDate);

年を省略した日付:'M月d日'

例: 5月20日

const date = new Date();
const options = { month: 'long', day: 'numeric' };
const formattedDate = date.toLocaleDateString('ja-JP', options);
console.log(formattedDate);

年月日の数字のみ

例: 2023/5/20

const date = new Date();
const options = { year: 'numeric', month: 'numeric', day: 'numeric' };
const formattedDate = date.toLocaleDateString('ja-JP', options);
console.log(formattedDate);

和暦

例: 平成35年5月20日

const date = new Date();
const options = { era: 'long', year: 'numeric', month: 'numeric', day: 'numeric' };
const formattedDate = date.toLocaleDateString('ja-JP', options);
console.log(formattedDate);

秒まで含む

例: 2023年5月20日 13:45:30

const date = new Date();
const options = { year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric' };
const formattedDate = date.toLocaleDateString('ja-JP', options);
console.log(formattedDate);

YouTube登録しているチャンネルの全一覧をCSVエクスポートしたい

やりたいこと

自分の登録しているYouTubeの全チャンネルをCSVエクスポートしたい

用意するもの

事前準備

google-api-python-clientが必要

pip install google-api-python-client

Pythonコード

import csv
from googleapiclient.discovery import build

# YouTube Data APIのAPIキーを設定します
API_KEY = "**********"

# ユーザー名またはチャンネルIDを指定します
channel_id = "**********"

youtube = build('youtube', 'v3', developerKey=API_KEY)

subscription_response = youtube.subscriptions().list(
    part='snippet',
    channelId=channel_id,
    maxResults=50  # 一度に取得できる最大数は50です
).execute()

with open('subscriptions.csv', 'w', newline='', encoding='utf-8') as file:
    writer = csv.writer(file)
    writer.writerow(['Channel URL', 'Channel Title'])  # ヘッダーを書き込みます

    for item in subscription_response['items']:
        title = item['snippet']['title']
        subscribed_channel_id = item['snippet']['resourceId']['channelId']
        # description = item['snippet']['description']
        url = f"https://www.youtube.com/channel/{item['snippet']['resourceId']['channelId']}"
        writer.writerow([url, title])

そうすると以下のようなCSVが生成できる。

Channel Title,Channel URL
テレビ愛媛ニュース,https://www.youtube.com/channel/UCISf7aH1HqBtTD9jPgzIfVA
テレビ大阪ニュース,https://www.youtube.com/channel/UCd6GEK664CTEWRZda7Fu7Lg

が、 maxResults=50 にもあるようにAPIでは1リクエストで50チャンネルしか取得できない。

もっと取得したい場合は pageToken を利用してループさせる必要がある。

import csv
from googleapiclient.discovery import build

# YouTube Data APIのAPIキーを設定します
API_KEY = "**********"

# ユーザー名またはチャンネルIDを指定します
channel_id = "**********"

youtube = build('youtube', 'v3', developerKey=API_KEY)

def get_subscriptions(pageToken=''):
    return youtube.subscriptions().list(
        part='snippet',
        channelId=channel_id,
        maxResults=50,  # 一度に取得する最大数を50に設定します(APIの制限)
        pageToken=pageToken  # 次のページへ進むためのトークン
    ).execute()

with open('subscriptions.csv', 'w', newline='', encoding='utf-8') as file:
    writer = csv.writer(file)
    writer.writerow(['Channel Title', 'Channel URL'])

    pageToken = ''
    while True:
        result = get_subscriptions(pageToken)
        for item in result['items']:
          title = item['snippet']['title']
          url = f"https://www.youtube.com/channel/{item['snippet']['resourceId']['channelId']}"]
          # description = item['snippet']['description']
          writer.writerow([title, url])

        if 'nextPageToken' in result:
            pageToken = result['nextPageToken']
        else:
            break

これで50件以上100件だろうが200件でも取得できる。やったね