[React]mapメソッドについてお勉強になった話

[React]mapメソッドについてお勉強になった話

こんにちは。浅野です。2022年最初の投稿です。早いもので、今年も4分の1が終わってしまいました、、、恐ろしいスピードです、、、 さて最近、業務でReactを扱うようになりました。そこで今回は、最近出くわしたエラーとその解決方法を紹介します。 まずは、こんなコードを書きました。 const items = [ { name: "name1", description: "description1" }, { name: "name2", description: "description2" }, ]; export function Hoge() { return ( <dl> {items.map((item, index) => ( <> <dt>{item.name}</dt> <dd>{item.description}</dd> </> ))} </dl> ); } すると、以下のエラーメッセージが出ました。 Warning: Each child in a list should have a unique "key" prop. Reactでmapメソッドを使う際、一意となる値をkeyとして渡さないといけません。今回dtタグにkeyを渡しているのでOKと思ったのですが、ダメでした。keyは、mapメソッドでreturnする親要素につけてあげる必要があったのです。かといって、dtタグとddタグをラップするdivタグを増やすのは、HTMLの構造として適切ではありませんし、場合によってはレイアウト崩れが起きてしまいます。 というところで、解決策は以下でした。 export function Hoge() { return ( <dl> {items.map((item, index) => ( <React.Fragment key={index}> <dt>{item.name}</dt> <dd>{item.description}</dd> </React.Fragment> ))} </dl> ); } <React.Fragment>にkeyを持たせてあげればいいのでした。普段は省略記法である<></>を使用しても問題はないのですが、こういうケースでは、省略できないようです。 Reactの公式サイトでも、まさに今回のケースが紹介されていました。 <></>は他の要素と同じように使うことが可能ですが、key や属性のサポートはありません。(中略)明示的に<React.Fragment>と宣言したフラグメントでは key を持つことができます。これはコレクションをフラグメントの配列に変換するときに有用です。たとえば定義リストを作成する時に利用します: またひとつ賢くなりました。この記事が誰かのエラー回避に繋がれば幸いです!

なぜRuby on Railsではrequireを実施なくてよいのか

なぜRuby on Railsではrequireを実施なくてよいのか

こんにちは。 今年は花粉影響が大きく、外出するのが辛い小林です。 今回はRuby on Rails(以下、Rails)を使用するようになってから、ずっと気になっていたことが(たくさん)あるのですが、それが1つ解決しました!! その喜びを伝えたく、キーボードを執りました。 今回のテーマは、これです。 なぜ、bundlerでインストールしたgemをrequireせずに使用することができるのか? はじめに Rubyの勉強を始めたときにこういうことを覚えますよね? 外部ファイルを使用する場合はrequireにて対象のファイルをロードする 参考:module function Kernel.#require しかし、bundlerとRailsを組み合わせて使用している際に、requireを使用しませんよね? なぜなのでしょうか? なぜ、reuqireを省略することができるのか? 皆さんは、なぜだと思いますか? 実は、requireしなくても呼び出すことができる? いいえ。 それだとrequireの存在意義がなくなってしまいます笑 「requireは同じファイルを複数回ロードしない」ということは、一度ロードされてしまえば、再度requireを実行する必要ない。 つまり、すでにどこかでrequireが実行されている? よいところに目をつけましたね。 それでは、答え合わせをしていきましょう。 答え合わせ 答えは以下のファイルにあります。 config/application.rb config/apprlication.rb このファイル内で以下の記述があります。 Bundler.require(*Rails.groups) 参考:yasslab/sample_apps/blob/main/6_0/ch14/config/application.rb#L7 この処理によってGemfileに記載されているgemが依存関係を含めてロードすることができるようになります。 If you have a lot of dependencies, you might want to say "require all of the gems in my Gemfile". To do this, put the following code immediately following require 'bundler/setup': Bundler.require(:default) 参考:How to use Bundler with Ruby#Setting Up Your Application to Use Bundler ソースコード的な解説をしだすと切りがないので省略しますが、興味がある方は以下を参考にしてください。 参考:bundler/lib/bunder.rb Bundler.requireでGemfile内のgemをロードするのはわかったのですが、そもそもBundler自体もgemなので、どこかでrequireしないといけないのでは? 上記に記載がある通り、require 'bundler/setup'の後に実施するように記載されています。 該当コードを確認すると内部でBundlerをロードしています。 参考:bundler/lib/bundler/setup.rb 最後の疑問です。 config/application.rb内では、require 'bundler/setup'を実施していないではないですか。 config/boot.rb config/application.rb内でrequire_relative 'boot'を実施しています。 config/boot.rbを確認すると、require 'bundler/setup'を実施していることが確認できます。 参考:yasslab / sample_apps sample_apps/6_0_0/ch14/config/boot.rb 参考:Railsの初期化プロセス 注意事項 以下のように:require => falseと指定すると、Bundler.requireを実行しても、ロードされないので、注意してください。 Specify :require => false to prevent bundler from requiring the gem, but still install it and maintain dependencies. gem 'rspec', :require => false gem 'sqlite3' 参考:Gemfiles 最後に 最初のRails案件でプルリクエスト出した際に、「個別のrequireは不要」と指摘されて依頼、ずっと気にかけていたことなので、本当によかったです。 完全に理解しました。(Railsガイドちゃんと読まないと。。。) 他にも気になっているものは多々あるので、引き続き調査していこうと思います。 参考 Railsの初期化プロセス How to use Bundler with Ruby Gemfiles rubygems / bundler bundler/lib/bundler/bundler.rb bundler/lib/bundler/setup.rb

Let's Encryptの証明書自動更新をAWS CLIで実現した話

Let's Encryptの証明書自動更新をAWS CLIで実現した話

連日寒い日が続いていますね。 二十四節気では一年で一番寒いとされる時期のようです。 こんにちは。WYRDの豊田です。 2022年が始まってもう一ヵ月が経とうとしています。遅ればせながら明けましておめでとうございます。 2021年もあっという間に過ぎ去った感じですが、2022年はどんな一年になるでしょうか。 今回のブログでは、この年末年始の余暇を使ってメールサーバーのSSL証明書更新処理を自動化した話を書こうと思います。 なお、今回の記事ではLet's EncryptやAWSに関する基礎的な解説はしていません。 背景 私が運用しているメールサーバーの証明書はLet's Encryptを利用しています。そのため、3ヶ月おきに証明書の更新作業を行う必要があります。 Let's Encryptの証明書更新にある程度詳しい方からの「cronで自動化すればいいのでは?」というツッコミが聞こえてきそうですね。 しかし、このサーバーは通常時80番ポートを開いておらず、HTTP-01チャレンジを行うには、事前に80番ポートを解放してあげる必要があるのです。 ※認証の仕組みについては公式サイトの解説を参照ください つまりSSL証明書を更新するときの手順は以下になります。 AWSコンソールにログイン EC2セキュリティグループで80番ポートを開く EC2インスタンスにログイン 証明書更新コマンド(certbot renew)実行 EC2セキュリティグループで80番ポートを閉じる 手順としてはそれほど複雑ではないですが、3ヶ月おきに手動で実施するとなると結構面倒なので、前々から自動化したいと思っていました。 (DNS-01チャレンジなどの方法も検討しましたが、当時DNSの設定を動的に書き換える方法を思いつかず、断念した覚えがあります) AWS CLIを使えるようにする SSL証明書更新を自動化するには、「AWSコンソールから80番ポートを開かなければならない」点がネックになります。 これを自動化することができれば、自動化できたも同然です。 そこでAWS CLIを使って、コンソールにログインせずに80番ポートを開け閉めできるようにします。 AWSコンソールでの作業 AWS CLIからセキュリティグループの設定を変更するためには、まず専用のユーザー(IAM)を用意します。(名前は適当なものをつけます) 今回は自動化バッチから利用するだけなので、AWS認証情報タイプは「アクセスキー」だけでOKです。 次に作成したユーザーに適用するポリシーを用意します。 あらかじめAWS側が用意しているプリセットポリシーがありますが、余計な権限まで付与してしまう可能性があるので、必要最低限の権限に限定したポリシーを独自に用意した方が良いでしょう。 ということで、今回のユーザーには以下の権限を付与します。 ec2:AuthorizeSecurityGroupIngress # inboundの設定を追加できる権限 ec2:RevokeSecurityGroupIngress # inboundの設定を削除できる権限 ec2:DescribeSecurityGroups # セキュリティグループの設定一覧を取得できる権限 ※この辺りの権限設定は、親子関係(ある権限を付与する時に、自動的に一緒に付与される権限)があったりするので、コンソールからGUIで設定すると楽です これでAWS側での事前準備は終わりです。 クライアント側での作業 次はサーバー側の準備です。 AWS CLIを使ってリクエストするために、名前付きプロファイルを作成します。 $ aws configure --profile ec2-sg-update 4項目ほど入力を求められますが、AWSコンソールでユーザー作成時に発行されたアクセスキーIDやシークレットアクセスキーなどを入力します。 動作確認 ここまで作業が終われば、あとは実際にリクエストを送るだけです。 以下のコマンドで80番ポートを開いたり閉じたりできるはずです。 80番ポートを開く $ aws ec2 authorize-security-group-ingress --group-id <セキュリティグループID> --protocol tcp --port 80 --cidr 0.0.0.0/0 --profile ec2-sg-update 80番ポートを閉じる $ aws ec2 revoke-security-group-ingress --group-id <セキュリティグループID> --protocol tcp --port 80 --cidr 0.0.0.0/0 --profile ec2-sg-update 更新スクリプトを用意する これでCLIベースでポートの解放が行えるようになりました。 あとはスクリプトを用意してcronで定期実行すればOKです。 スクリプトによる更新結果をSlackに通知するなど、もう少しカスタマイズすることで一層便利になりますが、その辺りについても今回は割愛します。 まとめ 長い間、手動で行っていた証明書更新作業を自動化できました。 AWSコンソールにログインしてポチポチせずに、コマンド一発で済むのはやはり楽ですね。 そういえば冒頭で断念したと書いたDNS-01チャレンジもAWS CLIと連携すればいけそうです。 DNS-01チャレンジなら80番ポートを解放することなく証明書の更新ができるので、状況によっては選択肢となるかも?(Let's EncryptはHTTP-01チャレンジを推奨しているようですが)

病院選びに失敗した話とこんな時だからこそ

病院選びに失敗した話とこんな時だからこそ

どうも久しぶりの投稿になります。 体調不良の中ブログを書いている田中です。 段々と寒くなり体調を崩している方も多いと思います。 私も季節の変わり目で体調を崩してしまい、その際に失敗した事 そしてこの記事を読んだ方が、より良い病院選びができる様にと思い、記事を書くことにしました。 今回の私の症状まとめ 咳がでる 熱なし 倦怠感なし このような状態であり、症状としては一般的な風邪の症状でした。 次は上記状態を踏まえた上で私が、選んだ病院のスペックをまとめます。 私が最初に選んだ病院スペック 個人開業の小さな病院 地域の子供やお年寄りが通いやすさから選ぶ病院 自身の症状からコロナではなさそうと判断したため、 私は、上記記載したスペック いわゆる町医者へ向かいました。 ですが私は、この判断を後々後悔する事になります。 失敗したこと コロナのワクチン接種会場になっているケースがある。 現在、個人開業の病院もワクチンの接種会場(一部時間帯)になっているケースがあります。 接種会場になっている場合、診察を受けられない可能性があります。 私の場合は調べたところ通常営業していそうだった為、 病院を訪れたのですが、実際行ってみるとワクチンの接種会場になっていました。ワクチン接種会場になっているかはネット上でも手に入れられます。 医院名で検索すると上記、記載があれば接種会場の可能性があります。 ですが、どの日程でワクチン接種会場になっているのかは ネット上で情報が、手に入らないケースがあります。 (今回私の行った病院は公表されていませんでした。ちゃんと更新して欲しい...) ですので病院へ向かう前に、一度電話して確認してから向かう方が無駄足を踏まなくて済むと思います。 コロナの検査をしない。 ご時世を考えると体調不良=コロナの可能性は考えると思います。 当然、検査はするものと思っていたのですが喉の様子をみて診察は終了。 4日分の風邪薬を出しておしまいでした。 待合室で看護師さんに確認したところ 「熱がある等の症状がない場合、検査はしない」とのことでした。 必ずしも町医者がそうと言い切るものではありませんが、 少なくともそういう意識の病院は今もあります。 こんな時だからこそ その後の話をします。 風邪と診断を受け薬を飲み続けましたが一向に改善しません(むしろ悪化...) 治れば変な心配はしなかったのですが、3日ほど経っても症状は治まらず... その結果、頭をよぎるのは「やばい。感染したかも...」という考えです。 不安になった私は次に総合病院と呼ばれる病院を選びました。 そこでは患者側から何も言わずともとりあえずで検査をしてくださいました。 結果は「陰性」 安心できました。タチの悪い風邪で間違っていなかった様です。 まとめ 結果だけ見れば、町医者も総合病院も診察結果は同じでした。 同じですが、その結果にたどり着く過程が大きく違いました。 このご時世だからこそ コロナじゃなさそうだから、とりあえず検査しなくてもいいやではなく、 コロナかもしれないから、とりあえず検査をしようと判断してくれる病院を選びたい。 感染したかもと思い不安を抱えるよりも とりあえず検査を受けてみて安心を得る方が自分にも周りにも優しいです。 このご時世だからこそ結果に加え、過程を大事にできる病院選びをして欲しい。 そう思い記事にさせていただきました。 感染者数は日々減ってきています。 あと少しの辛抱です。 頑張っていきましょう!! 読んで下さりありがとうございました。 以上で終わりとさせていただきます。

Chrome に追加された Copy link to highlight とは

Chrome に追加された Copy link to highlight とは

最近, Chrome に追加された機能で Copy link to highlight があります。これが結構便利でWebページ内の選択箇所へのリンクを作成してくれます。 このリンクの仕様自体はChrome独自でなくW3CにもText Fragmentsとして書かれてる仕様でChrome 80 以降から利用でき他のブラウザも対応するはずです。Copy link to highlight はこの Text Fragments に沿ったリンクをコピーするものになります。 URL Fragments 拡張するもので URL中にある https://example.com/#id の #id の部分を #:~:test=smth とするとページ上のsmth を表示してくれます。仕様上では表示をどう表現するかは各ブラウザの実装に委ねていますが、何かしらの方法でページ上で指定した文字列を視覚的にわかる効果で表現されるはずです。 このText Fragmentsの構文としては以下のように定義されています。 #:~:text=[prefix-,]textStart[,textEnd][,-suffix] context |-------match-----| context スクエアブラケットで囲まれてるところはオプショナルのパラメータでtextStartのみが必須になります。prefix, textStart, textEnd, と suffix は実際には任意の%エンコーディングされた文字列になります。prefix と suffix は、前後の一致を表現できホワイトスペースを許容します。 各ブラウザでの確認 もう少し詳しく見ていきます. Chrome(96.0.4664.55), Microsoft Edge(96.0.1054.34) の挙動を元にしたものになります。Filefox(94.0.2), Safari(15.1)でも確認しましたが未対応の様です。 2021/11/28時点で https://example.com/ は以下の様に表示されています。 Example Domain This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission. More information… textStart #:~:text=for と指定すると This domain is for の for がハイライトになります Example Domain This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission. prefix-,textStart #:~:text=asking-,for と指定すると asking for の for がハイライトになります Example Domain This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission. textStart,textEnd #:~:text=for,in と指定すると This domain is for use in の for use in がハイライトになります Example Domain This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission. textStart,-suffix #:~:text=examples%20in,-documents と指定すると examples in がハイライトになります Example Domain This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission. textStart,textEnd,-suffix #:~:text=examples,in,-literature と指定すると examples in documents. You may use this domain in がハイライトになります Example Domain This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission. 通常のフラグメントとの併用 通常のフラグメントと併用する場合は #id:~:text=sample の様に :~: の手前に指定できます。 セキュリティ面の考慮 セキュリティ面からの説明も書かれていてトラッキングできない様に考慮されています。今までのフラグメント同様、サーバサイドではフラグメントの情報は取得できません。アクセス分析等の実装では JavaScript で Location のhash で取得していました。Text Fragmentsは更に厳しく、JavaScriptでも取得できないようになっています。 Text Fragment Browser HTTP https://example.com/#id:~:text=for https://example.com/#id https://example.com/ 参考 Text Fragments URLの #:~:text= とは何か?( Text Fragments ) - Qiita