Yanonoblog!

こつこつと

インフラ - CloudTrail (AWS)の概要

背景

インフラの勉強で軽く調べた内容を書き留めておきたいと思いました。

本記事では、主に監査ログに関して調べた内容をまとめていきます。

CloudTrail

概要

AWS CloudTrail は、AWS アカウントの運用とリスクの監査、ガバナンス、コンプライアンスを行えるように支援する AWS のサービスです。

監査証跡(Trail)はAmazon S3に簡単に記録することができます。

AWS CloudTrailは、AWSアカウント内で発生するイベントの履歴(AWSリソースへのアクセス、API呼び出し、マネージメントコンソールの操作など)を保持し、デフォルトで90日間の期間をカバーしています。

具体的に使える場面

開発メンバーや他のユーザーが誤った操作を行った場合や、セキュリティインシデントが発生した場合など、問題のトラブルシューティングや原因の特定に役立ちます。

CloudTrailはアカウント内のアクションの詳細な履歴を提供するため、誰が何を行ったのか、いつ行われたのかなど、重要な情報を追跡できます。

始め方

始め方は簡単です。

  • AWS Management Consoleにサインインし、CloudTrailのサービスページに移動
    • 「証跡を作成」をクリック

image

  • 「クイック証跡の作成」で証跡の詳細を入力
    • 証跡の識別名を指定、バケットの選択もしくは作成

image

これにより、管理イベントのログ記録が開始されます。ログは設定したS3バケットに送信されます。

証跡の詳細ページでは、ログの状態やイベントの詳細を確認することができます。

料金

機能によっては無料で利用できます。例えば以下の機能などです。

イベント履歴のログ記録

AWSのサービス全体の管理イベントがデフォルトでログに記録されます。CloudTrailコンソールやlookup-events APIを使用して、直近90日間のイベント履歴を表示、検索、ダウンロードすることができます。

追跡の作成

進行中の管理イベントのコピーを1つ無料でAmazon S3バケットに配信することができます。

無料枠でも受けられる恩恵

重要な管理イベントのコピーを安全にバックアップでき、万が一の際にデータの損失を防ぐことができるため、イベントの長期的な保存や法的要件の遵守にも役立ちます。

追跡データをS3バケットに保存することで、監査やコンプライアンス要件を満たすための証拠として活用できます。

あとは先程解説した”具体的に使える場面”のところです。

サービス全体の管理イベントが記録されるため、アカウントの活動や変更履歴を追跡し監査することができます。

特定のイベントの詳細やタイムスタンプを確認することで、アカウントの操作や変更の履歴がわかります。

参考

続く…

コメント

本記事の内容は以上になります!

書籍の続きのアウトプットも随時更新したいと思います。


プログラミングスクールのご紹介 (卒業生より)

お世話になったプログラミングスクールであるRUNTEQです♪

https://runteq.jp/r/ohtFwbjW

こちらのリンクを経由すると1万円引きになります。

RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。

もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。

https://twitter.com/outputky

React - Constantsの扱い方

背景

フロントのリファクタリングを行った際に軽く調べた内容を書き留めておきたいと思いました。

本記事では、一括更新時のReactにおけるConstantsに関する説明を簡単に解説していきます。

Constantsとは

ReactにはConstantsと呼ばれる、変数や値を定義する方法があります。

コード内で使用される値を一元管理でき、変更が必要になった場合にも、一箇所で変更するだけで済むため、コードの保守性を高めることができます。

課題 - 定数管理がまとめて管理されていないと可読性が悪い

定数がコンポーネントファイルにベタ書きされているとファイルごとに定数の定義がバラバラになり、WETなコーディングになってしまいます。

constantsという同じ定数を複数のファイルで共有することができます。また、可読性も向上するため、メンテナンス性が高まります。

使用方法

具体的には、以下のように定数を定義します。

export const API_URL = 'https://example.com/api';
export const MAX_ITEMS = 10;

このように定数を定義すると、他のファイルでこれらの値を使用する場合には、以下のようにimportして使用できます。

import { API_URL, MAX_ITEMS } from './constants';

fetch(`${API_URL}/users?max=${MAX_ITEMS}`);

スタイルにも活用できる

スタイルに関する定数を定義することで、コンポーネントごとの色の違いをなくすことができます。

この例では、style_constants.jsというファイルを作成し、そこに以下のような定数を定義します。

export const COLORS = {
  PRIMARY: "#0088cc",
  SECONDARY: "#0055cc",
  TERTIARY: "#0011cc",
  LIGHT: "#f2f2f2",
  DARK: "#333333"
}

export const FONT_SIZES = {
  SMALL: "12px",
  MEDIUM: "16px",
  LARGE: "20px"
}

export const SPACING = {
  SMALL: "8px",
  MEDIUM: "16px",
  LARGE: "24px"
}

定数としてCSSの各種プロパティを定義することで、コンポーネントのスタイリングに利用することができます。例えばCOLORS.PRIMARYのように定数を参照することで、コンポーネント内で一貫したスタイリングを実現できます。

React以外でも一般的に使用される

ReactのConstantsは、主にReactコンポーネントで使用される定数や値を一元管理するために利用されます。

React以外でもJavaScriptのプログラム全般でConstantsを利用することはできますが、Reactコンポーネントで使用される定数や値を一元管理するための手法として、Constantsは特に有用です。

Railsエンジニアにとっても、Constantsはおなじみの概念であるかと思います。

Railsにも定数を定義する方法があり、その定数を利用して、例えばエラーメッセージを表示するコンポーネントを作成することができます。

ReactのConstantsも同様に、定数を一元管理することでコードの保守性を高めることができます。

おわりに

コメント

本記事の内容は以上になります!

参考になったり学びのきっかけになりますと幸いです。

間違いがありましたら修正いたしますので、ご指摘ください。

興味があれば他の記事も更新していきますので是非ご覧になってください♪


プログラミングスクールのご紹介 (卒業生より)

お世話になったプログラミングスクールであるRUNTEQです♪

https://runteq.jp/r/ohtFwbjW

こちらのリンクを経由すると1万円引きになります。

RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。

もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。

https://twitter.com/outputky

インフラ - CloudWatch (AWS)の概要

背景

インフラの勉強で軽く調べた内容を書き留めておきたいと思いました。

本記事では、主に監査ログに関して調べた内容をまとめていきます。

監査ログ

システムやアプリケーションの操作やイベントの履歴を記録するログのことを指します。監査ログはセキュリティやコンプライアンスの観点から重要です。

監査ログの使用用途について

監査トレイルの確保

監査ログはシステムやアプリケーションの操作履歴を詳細に記録するため、不正行為やセキュリティインシデントの追跡や特定に役立ちます。

監査トレイルとして使用され、必要な場合に調査や証拠の提供に役立ちます。

リアルタイムのモニタリング

監査ログを適切に収集しリアルタイムで監視することで、アプリケーションやシステムの異常な操作やイベントを検知することができます。

これにより、セキュリティ侵害や違反の早期発見と対応が可能となります。

コンプライアンスの遵守

監査ログはセキュリティ規制やコンプライアンス要件(例:GDPRPCI DSSなど)を満たすために必要な情報源として使用されます。

監査機関や規制当局からの要求に応じて、監査ログの提供やレポートの作成が求められることもあります。

CloudWatch (AWS)

AWSのモニタリングおよび管理サービスです。

CloudWatchを使用すると、AWSリソースのパフォーマンス監視、ログの収集と分析、アラートの作成、自動スケーリングの設定など、さまざまな管理タスクを実行することができます。

CloudWatch Logs - ログの管理

CloudWatchは、AWSリソースから生成されるログデータを収集・保存し、クエリや分析や可視化ができるログ管理サービスを提供しています。

ログデータの収集やフィルタリング、保持期間の設定などを行い、問題のトラブルシューティングやセキュリティ監視などの目的で活用することができます。

導入方法
  1. ロググループの作成: CloudWatch Logsで管理するログデータのカテゴリごとにロググループを作成します。(アプリケーションログ用のロググループやシステムログ用のロググループなど)
  2. ログストリームの設定: ロググループ内にログストリームを作成します。ログストリームは、ログデータの送信元を識別するためのキーとして使用されます

ログからどのような情報が得られるか

エラーと障害の詳細

アプリケーションやシステムがエラーや障害に遭遇した際に、ログにエラーメッセージやスタックトレースが記録されます。

これにより、問題の原因や発生箇所を特定することができます。

パフォーマンスの監視と最適化

ログには、アプリケーションやシステムのパフォーマンスに関する情報が含まれています。

レスポンスタイムやリソースの使用量などのメトリクスがログに記録されます。

これにより、ボトルネックやパフォーマンスの低下を特定し、最適化のための手掛かりを得ることができます。

ユーザーの行動分析

アプリケーションログには、ユーザーのアクションやイベントに関する情報が記録されます。

ログからユーザーの行動パターンや傾向を分析することで、ユーザーのニーズや要求に応じた機能の改善や新機能の開発が可能となります。

セキュリティ監視と侵入検知

セキュリティログには、不正アクセスや攻撃の試行などの情報が記録されます。

ログを監視し、異常なアクティビティやセキュリティイベントを検出することで、セキュリティ対策の強化や侵入の早期発見が可能となります。

CloudWatchアラーム

CloudWatchでは事前に定義されたしきい値を監視し、設定されたアラームと自動アクションを使用して、運用パフォーマンスを向上させることができるサービスです。

CloudWatchアラームは、先程解説したCloudWatch Logsに収集されたログデータを監視し、事前に定義されたしきい値に基づいてアラートを生成することができます。

Slackに通知する

CloudWatchアラームを使用して、Slackに通知を送信することも可能です。

image

CPU使用率がしきい値(80.0)を超えたためにアラームがトリガーされたことを示しています。

リソースの異常な動作やパフォーマンスの問題を監視し、アラートを出すことができます。

導入方法
  1. Slackのワークスペースで、Incoming Webhooksを有効化します。これにより、Webhook URLが生成されます。
  2. AWS Management Consoleにログインし、CloudWatchのサービスページに移動します。
  3. ナビゲーションメニューの「アラーム」セクションを選択します。
  4. アラームを作成または編集します。適切なメトリックスを選択し、条件やしきい値を設定します。
  5. 「アクション」タブに移動し、「アクションの追加」をクリックします。
  6. 「アクションタイプ」を「SNS通知」に設定し、「SNSトピック」を選択します。
  7. SNSトピック」を作成するか、既存のトピックを選択します。
  8. SNSトピックのサブスクリプションにSlackのWebhook URLを登録します。

これにより、CloudWatchアラームがトリガーされたときにSNSトピックが通知を受け取り、SNSトピックがSlackのWebhook URLにメッセージを送信します。Slackチャンネルでアラートを受信することができます。

参考

続く…

コメント

本記事の内容は以上になります!

書籍の続きのアウトプットも随時更新したいと思います。


プログラミングスクールのご紹介 (卒業生より)

お世話になったプログラミングスクールであるRUNTEQです♪

https://runteq.jp/r/ohtFwbjW

こちらのリンクを経由すると1万円引きになります。

RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。

もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。

https://twitter.com/outputky

React (JavaScript) - someメソッドの概要と具体的な活用例

背景

フロントのリファクタリングを行った際に軽く調べた内容を書き留めておきたいと思いました。

本記事では、配列操作に関する説明を簡単に解説していきます。

コードに関してはフェイクをいれてますので、ご了承ください。

Array.prototype.some()

概要

配列内の要素のうち、少なくとも1つの要素が指定された条件を満たすかどうかを判定するメソッドです。

構文
array.some(callback)
  • array: 条件を判定する配列
  • callback: 各要素に対して実行されるコールバック関数。要素ごとに呼び出され、条件を満たすかどうかを判定する。

戻り値

  • true: 条件を満たす要素が少なくとも1つ存在する場合
  • false: 条件を満たす要素が存在しない場合
簡単な例

2で割り切れる偶数が一つでも存在するならばtrueを返す例です。

const numbers = [1, 2, 3, 4, 5];

const hasEvenNumber = numbers.some((number) => number % 2 === 0);

console.log(hasEvenNumber); // true

some()メソッドのコールバック関数では、各要素を偶数判定しており、配列内に偶数の要素が存在するため、戻り値はtrueとなります。

実用例 - some

要件

紹介する例では「プランのコンテンツ内の項目が一つでも存在する場合にのみ、コンポーネントを表示する」

という要件を実現するためのコードです。

hasPlanContentsを定義 - /hooks/hoge/userPlan.ts

IDの配列を渡すと現在のユーザーが持つプランがダッシュボード用のプランコンテンツを持っているかどうかを判定する関数です。

const hasPlanContents = useMemo(
    () => (planContentIds: number[]) => {
      if (!currentUserPlan) return false;
      return currentUserPlan.planContents.some((planContent) =>
        planContentIds.includes(planContent.planContentId)
      );
    },
    [currentUserPlan]
  );
someの解説

currentUserPlan.planContentsは現在のユーザーが持つplanContentオブジェクトを指します。

someメソッドのコールバックではincludesを使用して関数の引数のID配列とユーザーが持つplanContentオブジェクト内のplanContentIdを含んでいるかを要素一つずつに対して真偽値を返されます。

someはincludesでtrueが返されればtrueを返します。

一致する要素が見つからなければ、全ての要素をチェックした後にfalseを返します。

つまり、sumeとincludesを併用することで配列と配列のマッチ判定ができます。

このように、someメソッドを使用することで配列の要素の中に特定の条件を満たす要素が存在するかどうかを効率的に判定することができます。

hasDashboardPlanContentsを定義 - /pages/home/Dashboard.tsx

ダッシュボード内でプランのコンテンツ内の項目が一つでも存在する場合にのみ、見出しのコンポーネントを表示します。

planContentIds変数には、特定のプランコンテンツのIDが配列として定義されています。constantsから固定項目のIDを呼び出しています。

該当のプランコンテンツIDをhasPlanContents関数に渡して呼び出して一つでも表示するプランがある場合はtrueが返るため、見出しコンポーネントが表示されるようになっています。

export const Dashboard = () => {
  const { hasPlanContents } = hogeHooks()

  const planContentIds: number[] = [
    planContent.A_PLAN_ID,
    planContent.B_PLAN_ID,
    planContent.C_PLAN_ID,
  ]

  const hasDashboardPlanContents = hasPlanContents(planContentIds)

  return (
    <Container title="">
      <Inner>
        <MainContents />
        {hasDashboardPlanContents && <HogeComponent />}
      </Inner>
    </Container>
  )
}

最後に、ContainerInnerというコンポーネントを使って表示を構築しています。

hasDashboardPlanContentstrueの場合にのみ、HogeComponentが表示されます。

続く…

コメント

本記事の内容は以上になります!

書籍の続きのアウトプットも随時更新したいと思います。


プログラミングスクールのご紹介 (卒業生より)

お世話になったプログラミングスクールであるRUNTEQです♪

https://runteq.jp/r/ohtFwbjW

こちらのリンクを経由すると1万円引きになります。

RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。

もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。

https://twitter.com/outputky

React (JavaScript) - mapとflatMap

背景

フロントのリファクタリングを行った際に軽く調べた内容を書き留めておきたいと思いました。

本記事では、配列操作に関する説明を簡単に解説していきます。

コードに関してはフェイクをいれてますので、ご了承ください。

Array.prototype.flatMap()

概要

配列をフラット化して新しい配列を作成するメソッドの1つです。

flatMapメソッドは、配列内の各要素に対して、コールバック関数を実行し、その結果をフラット化した配列として返します。

つまり

多次元配列を一つの配列に展開することができます。

多次元配列

以下の例は配列の中に配列が入れ子になっている多次元配列となります。

厳密にいうと配列の中にオブジェクトが格納されており、オブジェクトのプロパティに別の配列が格納されています。

const dummyData: DummyData = [
  {
    "id": 1,
    "name": "Alice",
    "details": [
      {"id": 1, "value": "A"},
      {"id": 2, "value": "B"},
      {"id": 3, "value": "C"}
    ]
  },
  {
    "id": 2,
    "name": "Bob",
    "details": [
      {"id": 1, "value": "D"},
      {"id": 2, "value": "E"},
      {"id": 3, "value": "F"}
    ]
  }
];
構文 - flatMap

先程定義した多次元配列に対してflatMap()を使用すると、detailsプロパティの配列をフラット化して、新しい配列を作成できます。

const flatDetails:Dummy[] = dummyData.flatMap(data => data.details);

flatMapを使って操作した場合の返り値は、次のようになります。

AliceのdetailsとBobのdetailsをまとめた配列に展開されていることがわかりますね。

  {"id": 1, "name": "Alice", "value": "A"},
    {"id": 1, "name": "Alice", "value": "B"},
    {"id": 1, "name": "Alice", "value": "C"},
    {"id": 2, "name": "Bob", "value": "D"},
    {"id": 2, "name": "Bob", "value": "E"},
    {"id": 2, "name": "Bob", "value": "F"}
]

flatMapは、各要素に対してコールバック関数を適用し、それぞれの結果を1つの配列にまとめた新しい配列を返します。

この例では、dummyDataの各要素はオブジェクトであり、その中にdetailsという配列があるため、flatMapを使ってdetailsを展開し、新しいオブジェクトの配列に変換しています。

Array.prototype.map()

概要

Array.prototype.map()は、配列の要素を1つずつ取り出してコールバック関数を実行し、新しい配列を作成するメソッドです。

map()メソッドを使うことで、元の配列の要素を変換したり、新しいプロパティを追加したりすることができます。

構文 - map

先程と同じ多次元配列を使ってdataを定義します。

const data = [
  {
    "id": 1,
    "name": "Alice",
    "values": [
      {"id": 1, "value": "A"},
      {"id": 2, "value": "B"},
      {"id": 3, "value": "C"}
    ]
  },
  {
    "id": 2,
    "name": "Bob",
    "values": [
      {"id": 1, "value": "D"},
      {"id": 2, "value": "E"},
      {"id": 3, "value": "F"}
    ]
  }
];

map()を使用すると、各要素のvaluesプロパティが取り出され、新しい配列が作成されます。

const extractedValues = data.map(item => item.values);

実行結果は以下のようになります。

[
  [
    {"id": 1, "value": "A"},
    {"id": 2, "value": "B"},
    {"id": 3, "value": "C"}
  ],
  [
    {"id": 1, "value": "D"},
    {"id": 2, "value": "E"},
    {"id": 3, "value": "F"}
  ]
]

flatMap()とmap()の違い

dummyData配列の各要素のdetailsプロパティを取り出して新しい配列を生成していますが違いについて改めて記載します。

// Array.prototype.map()を使用した場合
const mappedData = dummyData.map(item => item.details);
console.log(mappedData);
// 出力: [[{id: 1, value: "A"}, {id: 2, value: "B"}, {id: 3, value: "C"}], [{id: 1, value: "D"}, {id: 2, value: "E"}, {id: 3, value: "F"}]]

// Array.prototype.flatMap()を使用した場合
const flatMappedData = dummyData.flatMap(item => item.details);
console.log(flatMappedData);
// 出力: [{id: 1, value: "A"}, {id: 2, value: "B"}, {id: 3, value: "C"}, {id: 1, value: "D"}, {id: 2, value: "E"}, {id: 3, value: "F"}]

map()メソッドを使用すると2次元配列が生成され、各要素は配列となります。

flatMap()メソッドを使用するとフラット化された1次元配列が生成され、配列の要素が展開されます。

続く…

コメント

本記事の内容は以上になります!

書籍の続きのアウトプットも随時更新したいと思います。


プログラミングスクールのご紹介 (卒業生より)

お世話になったプログラミングスクールであるRUNTEQです♪

https://runteq.jp/r/ohtFwbjW

こちらのリンクを経由すると1万円引きになります。

RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。

もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。

https://twitter.com/outputky

Rails - group_byメソッドの仕組みと活用例

背景

バックエンドの実装を行った際にgroup_byメソッドについて色々調べたため内容を書き留めておきたいと思いました。

本記事では、group_byメソッドの活用方法を具体的なViewを作りつつ解説していきます。

情報に関しては適当にフェイクを入れていますので、ご注意ください

概要

RubyのEnumerableモジュールに含まれるgroup_byメソッドは、配列内の要素を指定した条件でグループ化することができるメソッドです。

group_byメソッドは配列、ハッシュ、範囲オブジェクトなど、Enumerableモジュールをincludeしているクラスのインスタンス全てで使用可能です。

例として以下の果物の名前と色が格納されたhashの配列があります。

fruits = [
  { name: "apple", color: "red" },
  { name: "banana", color: "yellow" },
  { name: "grape", color: "purple" },
  { name: "orange", color: "orange" },
  { name: "watermelon", color: "green" },
  { name: "strawberry", color: "red" }
]
解説 - group_byでグループ化

この配列をgroup_byメソッドを使ってcolorキーでグループ化します。

fruits_by_color = fruits.group_by { |fruit| fruit[:color] }

上記のコードでは、ブロックに渡される引数fruitには、配列内の各要素(ハッシュ)が順に代入されます。

一回目の処理のポイントです。

  • 一つ目のハッシュのcolorキーのバリューである”red”を取得
  • ”red”をキーとするハッシュにブロックの引数であるハッシュが追加される
  • 上記を繰り返し処理で順番にcolorキーを基準としたハッシュの配列を作成し、colorキーが同じ場合は配列に追加されることでグルーピングされる
  • これによりブロックの戻り値が同じ要素同士がグループ化されます。

    ここでは、fruit[:color]の値でグループ化しているため、同じ色の果物が一つの配列にまとめられます。

    group_byで得られる結果値

    上記の結果、以下の形式になります。

    {
      "red": [
        { name: "apple", color: "red" },
        { name: "strawberry", color: "red" }
      ],
      "yellow": [
        { name: "banana", color: "yellow" }
      ],
      "purple": [
        { name: "grape", color: "purple" }
      ],
      "orange": [
        { name: "orange", color: "orange" }
      ],
      "green": [
        { name: "watermelon", color: "green" }
      ]
    }
    

    グループ化された結果は、以下のように表示することができます。

    fruits_by_color.each do |color, fruits|
      puts "#{color}: #{fruits.map { |fruit| fruit[:name] }.join(', ')}"
    end
    

    上記のコードでは、グループ化された各要素のキー(color)と、それに対応する値(同じcolorの果物の配列)を、ブロック変数colorとfruitsに代入しています。

    mapメソッドで各果物の名前の配列を取得し、joinメソッドでチェーンしてカンマ区切りの文字列に変換しています。

    出力結果は下のようになります。

    red: apple, strawberry
    yellow: banana
    purple: grape
    orange: orange
    green: watermelon
    

    group_byメソッドは、グループ化したい条件が複数ある場合にも使えます。以下は、colorとsizeの両方でグループ化する例です。

    fruits_by_color_and_size = fruits.group_by { |fruit| [fruit[:color], fruit[:size]] }
    

    出力結果は以下のようになります。

    [
      [["red", "small"]], 
      [], 
      [["red", "medium"]], 
      [
        { name: "banana", color: "yellow", size: "small" }
      ], 
      [["purple", "medium"]], 
      [
        { name: "orange", color: "orange", size: "large" }
      ], 
      [["green", "large"]], 
      [
        { name: "strawberry", color: "red", size: "medium" },
        { name: "watermelon", color: "green", size: "large" }
      ]
    ]
    

    実用例

    今回のケースを利用して都道府県を複数選択出来るUIを作成します。

    実現するUI

    このようなUIを実現する例です。

    image

    都道府県のハッシュを利用してフォームを作成する際に県名に合わせて見出しとして地方名を列挙する際に非常に便利です。

    適当ですがcontrollerでこのようなRubyのコードを書きます。

    実際はデータベースから取り出したレコードを利用するとは思いますが今回はベタ書きです。

    def index
        @prefectures = [
          { name: "北海道", region: "北海道" },
          { name: "青森県", region: "東北" },
          { name: "岩手県", region: "東北" },
          { name: "宮城県", region: "東北" },
          { name: "秋田県", region: "東北" },
          { name: "山形県", region: "東北" },
          { name: "福島県", region: "東北" },
          { name: "茨城県", region: "関東" },
          { name: "栃木県", region: "関東" },
          { name: "群馬県", region: "関東" },
          { name: "埼玉県", region: "関東" },
          { name: "千葉県", region: "関東" },
          { name: "東京都", region: "関東" },
          { name: "神奈川県", region: "関東" },
          { name: "新潟県", region: "中部" },
          { name: "富山県", region: "中部" },
          { name: "石川県", region: "中部" },
          { name: "福井県", region: "中部" },
          { name: "山梨県", region: "中部" },
          { name: "長野県", region: "中部" },
          { name: "岐阜県", region: "中部" },
          { name: "静岡県", region: "中部" },
          { name: "愛知県", region: "中部" },
          { name: "三重県", region: "中部" },
          { name: "滋賀県", region: "近畿" },
          { name: "京都府", region: "近畿" },
          { name: "大阪府", region: "近畿" },
          { name: "兵庫県", region: "近畿" },
          { name: "奈良県", region: "近畿" },
          { name: "和歌山県", region: "近畿" },
          { name: "鳥取県", region: "中国" },
          { name: "島根県", region: "中国" },
          { name: "岡山県", region: "中国" },
          { name: "広島県", region: "中国" },
          { name: "山口県", region: "中国" },
          { name: "徳島県", region: "四国" },
          { name: "香川県", region: "四国" },
          { name: "愛媛県", region: "四国" },
          { name: "高知県", region: "四国" },
          { name: "福岡県", region: "九州" },
          { name: "佐賀県", region: "九州" },
          { name: "長崎県", region: "九州" },
          { name: "熊本県", region: "九州" },
          { name: "大分県", region: "九州" },
          { name: "宮崎県", region: "九州" },
          { name: "鹿児島県", region: "九州" },
          { name: "沖縄県", region: "九州" }
        ]
    
        @prefecture_by_region = @prefectures.group_by { |prefecture| prefecture[:region] }
      end
    

    上記ではgroup_byを用いて地方名であるregionのグループを作成してインスタンス変数に代入しています。

    あとは以下のようにeach文を書いてデザインを付け加えてあげると完成です!

    <div class="m-4">
      <h5 class="border-bottom border-3 pb-1 fw-bold">
        県名を選択する
      </h5>
      <div class="row my-2">
        <% @prefecture_by_region.each do |region, prefecture| %>
          <div class="col-md-2 menu-group m-3">
            <h6 class="border-bottom border-gray pb-1 fw-bold" style="border-left:8px solid #87cefa; padding:2px 8px; background-color: white;">
              <%= region %>
            </h6>
            <div class="m-2">
              <% prefecture.each do |prefecture| %>
                  <%= check_box_tag "prefectures[]", prefecture[:name], false, style: 'transform: scale(1.3);', class: 'checks m-2' %>
                  <%= label_tag prefecture[:name], prefecture[:name], style: 'transform: scale(1.1);', class: 'ml-2 m-1' %><br>
              <% end %>
            </div>
          </div>
        <% end %>
      </div>
    </div>
    

    これにもう少し地図の画像デザインなどを加えたりボックス背景を地方ごとにつけてあげるとUIとしては様になってきますね。

    メソッド自体も活用できると便利なのではないでしょうか。

    おわりに

    コメント

    本記事の内容は以上になります!

    参考になったり学びのきっかけになりますと幸いです。

    間違いがありましたら修正いたしますので、ご指摘ください。

    興味があれば他の記事も更新していきますので是非ご覧になってください♪


    プログラミングスクールのご紹介 (卒業生より)

    お世話になったプログラミングスクールであるRUNTEQです♪

    https://runteq.jp/r/ohtFwbjW

    こちらのリンクを経由すると1万円引きになります。

    RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。

    もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。

    https://twitter.com/outputky

    Rails - JSONの解説とjbuilderでのAPI構築

    はじめに

    本記事では「パーフェクト Ruby on Rails」で学んだ内容と別途気になって調べた内容や知識も含めアウトプットしています。

    書籍に記載されている内容を順序立ててまとめるというよりは、整理しておきたい周辺の知識と深ぼった内容を雑多に書いています。

    Rails APIJSONを返す

    Railsではrenderメソッドなどを使用してビューのHTMLテンプレートを生成して返すこともできますが、APIサーバとして機能させ、JSON形式でのレスポンスを返すことも可能です。

    Railsでは、簡単にJSONレスポンスを生成できる仕組みが用意されています。

    JSONの構築

    renderメソッド呼び出し時にJSONへオブジェクトを変換することができますが、より複雑なJSONデータを構築する場合は、HTMLテンプレートのようにJSONデータを構築する方法ができ、APIとして使用する場合はこの方法が一般的です。

    jbuilder

    Railsでは、Active Model SerializersやJbuilderといったGemを使用して、JSONデータを構築することができます。

    これらのGemを使用すると、宣言的に複雑なJSONレスポンスを作成することができます。

    拡張子

    Jbuilderで整形されたJSONデータを構築するためのファイルの拡張子は、.json.jbuilderです。この拡張子は、RailsによってJbuilderテンプレートとして認識されます。

    コード例

    app/controllers/api/v1/users_controller.rb

    リクエストによってApi::V1::Settings::UsersControllerindexアクション内の処理が実行され、@usersに適切なデータが設定されたあとビューレンダリングのフェーズに入ります。

    # app/controllers/api/v1/users_controller.rb
    
    class Api::V1::UsersController < Api::Base::ApplicationController
      skip_before_action :authenticate!
    
      def index
        @users = User.all
      end
    end
    
    app/views/api/v1/users/index.json.jbuilder

    Railsは自動的にビューファイルを探し、適切なJbuilderテンプレートを特定します。

    デフォルトの検索パスは、app/viewsディレクトリ内のコントローラーに対応するサブディレクトリです。

    この場合、app/views/api/v1/users/index.json.jbuilderJbuilderテンプレートとしての候補となります。

    # app/views/api/v1/users/index.json.jbuilder
    
    if @user.blank?
      json.status :error
      json.message I18n.t("errors.no_data")
    else
      json.status :success
      json.set! :data do
        json.(@user.decorate, :name, :email)
        if @user.plan.present?
          json.plan do
            json.id @user.plan.id
            json.name @user.plan.name
            end
          end
        end
      end
    end
    

    特定されたJbuilderテンプレートが読み込まれ、コントローラー内で定義されたインスタンス変数やローカル変数を使用して、JSONデータの構築が行われます。

    Jbuilderテンプレート内で定義されたJSONデータの構築処理が完了し、レスポンスとして返されます。

    上記の流れにより、indexアクションに対応するJbuilderテンプレートが特定され、コントローラー内で設定された変数を使用してJSONデータが構築され、最終的にJSONデータがレスポンスとしてクライアントに返されます。

    部分テンプレート

    jsonもerbと同様に部分テンプレートも使用することができます。

    app/views/api/v1/users/_user.json.jbuilder

    ユーザー情報を含む部分テンプレート _user.json.jbuilder を作成します。

    json.(@user.decorate, :name, :email)
    

    上記のテンプレートでは、@userオブジェクトのnameemail属性をJSONに追加しています。

    app/views/api/v1/users/index.json.jbuilder

    元のテンプレートである app/views/api/v1/plans/index.json.jbuilder を以下のように修正します。

    json.partial! メソッドを使用して、部分テンプレート _user.json.jbuilder を読み込んでいます。引数として user: @user を渡しています。

    if @user.blank?
      json.status :error
      json.message I18n.t("errors.no_data")
    else
      json.status :success
      json.set! :data do
        json.partial! 'api/v1/plans/user', user: @user
        if @user.plan.present?
          json.plan do
            json.id @user.plan.id
            json.name @user.plan.name
          end
        end
      end
    end
    
    解説

    json.partial! の第1引数は、部分テンプレートのパスを指定します。

    'api/v1/plans/user' と指定することで、_user.json.jbuilder を参照します。

    json.partial! の第2引数は、部分テンプレート内で使われる変数を指定します。ここでは user: @user を渡しているので、部分テンプレート内では user としてアクセスできます。

    index.json.jbuilder では部分テンプレート _user.json.jbuilder を使用して、ユーザー情報を含むJSONデータが構築されます。

    部分テンプレートを利用することで、同じユーザー情報のJSONデータを複数のテンプレートで再利用することができ、部分テンプレートを使うことでコードの可読性や保守性も向上します。

    参考

    続く…

    コメント

    本記事の内容は以上になります!

    書籍の続きのアウトプットも随時更新したいと思います。


    プログラミングスクールのご紹介 (卒業生より)

    お世話になったプログラミングスクールであるRUNTEQです♪

    https://runteq.jp/r/ohtFwbjW

    こちらのリンクを経由すると1万円引きになります。

    RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。

    もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。

    https://twitter.com/outputky