- 投稿日:2020-07-11T20:21:34+09:00
Railsでのorderメソッドの説明
ツイート機能やタイムライン機能をwebアプリケーションに実装した時、新しく投稿すると下に表示されてしまいます。
その順序を並び替えるのに「orderメソッド」を使用します。その使い方を説明します。
orderメソッド
テーブルから取得してきたインスタンス群を並び替えることができるメソッドです。
引数に「テーブルカラム名、並び替える順序」を記述して変化させる。
書き方例
def index @tweets = Tweet.order("created_at DESC") end上の記述でツイートを作成順に逆から並べると言う意味になります。
並び替える順序
- ASC : 昇順
- DESC : 降順
- 投稿日:2020-07-11T19:43:06+09:00
Rails 6 + Vue(単一コンポーネント) + vue-router + Vuetify だけどMPA(SPAではない) - Multi SPA
構成
ひとつのRailsアプリケーション上に、単一コンポーネントで構成されたSPAを配置します。
まずはひとつのSPAをおくことを目標にしますが、同様に複数のSPAを置くことを意図しています。(よって完全なSPAではありません。またMulti-SPAとなります。)構成のイメージ:
- /shared
- /private
- /private/episode/:id/schedule
- ここをSPAにする
Rails
Rails は、MVCなMPAアプリケーションをつくります。
Rails 6 webpacker を利用して vue を用います。webpacker と Vue の導入については説明を省きます。Layout
SPA 用の layout を設けて、コントローラ(あるいはアクション)で切り替えます。ここでは
application_spa
とします。application_spa は後述します。コントローラ#アクション schedule で layout を指定すると下記のようになります。これで episode_controller の schedule だけ application_spa を利用することになりました。
episode_controller.rbdef schedule respond_to do |format| format.html { render :schedule, :layout => 'application_spa' } end endのちに指定する vue-router と、ここで SPA対象となるRails controller#actionは、同じURLで同じSPAを使う必要があります。(そうでない場合、ひとつのURLで別のものが表示されてしまいます)
Vue 周りの構成
Vue を SFC(単一ファイルコンポーネント)で利用します。SFCなVueからは axios で API を利用します。Vuetify, vue-router, axios については説明を省略します。
この先の手順は Vue のSingle File Components 利用における Vuetify, vue-router, axios と同じです。
用意するもの:
- Vuejs
- vue-router
- Vuetify
- axios使わないもの:
- Nuxt.jsRails View
action view
View への routing は、Railsの routes.rb でaction schedule に向けられているとします。それにより
schedule.html.haml
が用いられるため、layout と schedule.html.haml をSPA用にします。
schedule.html.haml
は、content_for を利用して、 layout で使用する javascript_pack_tag と stylesheet_pack_tag を切り替えられるようにします。切り替えられるようにする理由は、複数のSPAを作成する予定のためです(つまりMulti-SPAです)。view/../schedule.html.haml- content_for :pack, 'schedules' #schedules
#schedules
の指定は、のちほどJavaScriptで利用します。layout
layoutは、 view で指定されたcontent_forによってJSファイルを読み込むようにします。stylesheet_pack_tag も指定しないと Vuetify のデザインが当たらないので注意しましょう。
layout/application_spa.html.haml!!! 5 %html %head %title= "" = csrf_meta_tags = yield :meta = stylesheet_pack_tag "#{yield :pack}" = javascript_pack_tag "#{yield :pack}" %body = yieldRails側のViewは以上です。大変シンプルですね。
Vue の呼び出し
javascript_pack_tag が呼び出す schedule.js が起点(エントリーポイント)となります。(よく見かける application.js を呼び出す部分に相当します。)
schedule.js
Rails View で指定した ID #schedules を使います。
packs/schedule.js// 様々なimport や Vue.use の記述は省略 document.addEventListener('DOMContentLoaded', () => { const app = new Vue({ el: '#schedules', // schedule.html.haml で指定したもの vuetify, // import した vuetify router, // import した vue-router render: h => h(App) }).$mount() })app.vue
schedule.js が
render: h => h(App)
で指定した app.vue は、router-view
を呼びます。記述には pug を用いています。packs/app.vue<template lang="pug"> v-app v-app-bar( dark ) v-toolbar-title Service Name is Unknown v-main v-container v-layout( wrap ) router-view </template>router-view に割り当てられたコンポーネントは、次の router の設定で行っています。
vue router
vue 側の router の設定です。
アプリケーションが/
から始まらないため、mode: 'history'
を忘れないようにします。
この先、複数のSPAを作成するため、router も複数にします。そのため、 pack 配下に router/ を作成します。 router を schedule.js へ書かずに別ファイルとし packs/router/schedule.js として管理します。packs/router/schedule.jsimport VueRouter from 'vue-router'; import Schedule from '@/../components/schedule.vue'; const routes = [{ path: '/episode/:id/schedule', component: Schedule, // 増えた path は、Rails 側も対応 }]; export default new VueRouter({ base: '/private/', mode: 'history', routes });
base: '/private/'
を指定して、アプリケーションの階層を /private 配下にしています。指定すると $route.path に含まれません。 router-link で :to を用いる際にも含まれなくなります。この router/schedule.js は schedule.js から import されています。
axios
SFC 内で axios を用いてAPIにアクセスします。CSRF_TOKENはこちらを参照しました。
.vue の中では、methods で axios を用います。
遷移を伴う一覧をrouters-list
で記述しました。しかし、同じpathに一致する更新は、APIで取得した値を取り直してくれません。 そこで watch により変更を監視します。 vue-router公式ではbeforeRouteUpdate
も使えると記載があります。今回は
beforeRouteUpdate
を利用しました。@/../components/schedule.vue// template は省略 // props や data は省略 methods: { getEpisode: function (event) { this.axios .get('/api/v1/episodes/' + this.$route.params.id + '') .then(response => (this.episode = response.data)) // catch error 省略 } }, beforeRouteUpdate(to, from, next){ this.getEpisode() next() }, // watch を使う場合1 // watch: { // $route (to, from) { // this.getEpisode() // } // }, // // watch を使う場合2 // watch: { // '$route': 'getEpisode' // }, // mounted () { this.getEpisode() },Vue側は以上です。これで
/private/episode/:id/schedule
を起点としたSPAができました。まとめ
Rails の layout をSPA用に分け、Railsで完結するアプリケーションと、Vue によるSPAを並存させました。Railsアプリケーション全体からみると、部分的にSPAを提供できます。
複数SPAを目的にした理由
ここでは、SPAを複数置くことを考えました。どの単位に分けると良いのかは、まだ明確な指針を持っていません。そのため、複数SPAを意図した理由についても簡単に記載します。
Vueのroutingで対応ができる範囲で複数のSPAに分けるのは、あまり意味はないだろうと考えています。エントリーポイントが schedule.js になるのかどうかの違いしかないためです。
一方で、起点ごとに異なるコンポーネントを利用する場合や、vue-router の path が遷移で繋がらない場合は、エントリーポイントを分ける意味があると考えました。
今回、構築したRailsアプリケーションのうち、スケジュール管理部分をVueのSPAにしたいと思いました。それだけでひとつのアプリケーションになり得る単位です。
また、同じアプリケーションを Episode 以外のモデルでも利用するため、再利用性の高いアプリケーションにしたいと考えました。そのためSPAによってModelを横断して取り扱えるようにしようと考えました。今後、schedule 以外のエントリーポイントが増えることを想定しました。schedule 同様に、単独でひとつのアプリケーションになり得る単位です。たとえばログ管理を考えています。
その際に、SPAを統合するイメージが湧かず、別々に切りたいと考えました。Railsが管理する単位では1つのサービスですが、クライアント側に期待する単位では、それぞれ完結しています。たとえばスケジュール管理とログ管理はまったく別の操作性を期待しています。ログとスケジュールを同時に管理したいこともありません。
以上が、複数SPAを考えた理由です。
エントリーポイント間の差分
仮に
schedule
以外にlog
を増やしたいとしましょう。Rails側の作業はわずかです。
SPAにしたい箇所を、layoutapplication_spa
指定することと、log.html.haml view の中で #logs を使うこと、です。Vue は、packs/schedule.js と同等のエントリーポイントとして
packs/logs.js
を用意し、el: '#logs'
とします。(もちろん他のelementでも構いません。)
また packs/logs.js は、log 用の routerpacks/router/logs.js
を読み込みます。axios や app.vue, Vuetify は作業が不要です。
つまり、複数のエントリーポイント間の差分は、対応する router/*.js の path と、利用するコンポーネント群の違いになります。
おわり
以上、Rails の layout をSPA用に分け、エントリーポイントを複数にすることで、Vue によるSPAを複数作成することができました。
- 投稿日:2020-07-11T18:58:33+09:00
高卒フリーターから、Web系自社開発企業のエンジニアになるまで
はじめに
一浪して入った大学を中退し、webエンジニアを目指して学習を開始してから約半年間、
晴れてweb系自社開発企業様からサーバーサイドエンジニアとして内定を頂けたので、学習過程や、就職活動で得た知見を共有したいと思います。
就職活動中の方のご参考になれば幸いです!僕のスペックは以下の通りです。
今年23歳/高卒/フリーター/社会人経験なし
謙遜ではなく、どう考えても高スペックではありません。
こんな僕が内定を得るためには、そう選択肢はありません。やるべきことは決まっていました。モダンな技術を使用したポートフォリオを作ること。
以下、学習手順と、就職活動内容を書きます。
目次
- ポートフォリオ紹介
- ProgateにてHello World (2020/1月)
- ドットインストールを貪る (2020/2月)
- モダンな技術にチャレンジ(Docker,AWS) (2020/3月)
- ポートフォリオ作成 (2020/4月~6月)
- いざ、就職活動へ (2020/6月~7月)
- 就活を終えての所感
ポートフォリオ紹介
これが僕が作成したポートフォリオになります。
概要
「美味しい」を共有するをモットーに、お食事招待、レストラン検索や料理に関する記事投稿ができるSNSアプリです。
クラウドアーキテクチャ
言語・使用技術
- インフラ
- AWS(ECS-FARGATE/ALB/Route53/VPC/RDS)
- Terraform (本番環境インフラをコードで管理)
- CircleCI (CI/CD)
- Docker/docker-compose
- バックエンド
- Ruby 2.6.3
- Rails(API) 5.2.3
- Mysql 5.7.30
- フロントエンド
- Nuxt.js(SSR) 2.0.0
- element-ui (CSSフレームワーク)
高評価を頂いた点
- トップページ等のデザインが凝ってあり、印象が良い。
- UI/UXが整っている。
- SSR、CI/CD、Terraform等の高度な技術を取り入れている。
補足説明
完成8割段階で就職活動を開始し内定を得られたので、まだまだ改善点が多く、ポートフォリオのレベルとしては高いとは言えないと思います。あくまで必要最低限レベルくらいだったと思います...。
1、ProgateにてHello World (2020/1月)
学習した講座
1 HTML/CSS
2 Javascript
3 Ruby
4 Ruby on rails
5 SQL
6 Command Line
7 Git
「プログラミングを学べば、バイト代くらいは余裕で稼げます」
こんな煽り文句を鵜呑みにした僕は、Progateにて学習を開始します。
各種基本文法をざっくり習得し、「プログラミングってこんな感じなんだな」程度の知見を得ます。
まだ個人でサービスを開発するレベルには程遠い感じでした。2、ドットインストールを貪る (2020/2月)
学習した講座
1 詳解HTML 基礎文法編
2 詳解CSS 基礎文法編
3 詳解JavaScript 基礎文法編
4 詳解JavaScript オブジェクト編
5 詳解JavaScript DOM編
6 ローカル開発環境の構築
7 Ruby on Rails 5 入門
8 Active Record 入門
9 Sinatora 入門
10 Mysql 入門
11 シェルスクリプト 入門
12 その他自分が面白そうと思った講座
ローカル開発環境の構築をハンズオンで行い、自分のローカル上でアプリケーションを開発できるようになりました。
「自分で0からwebアプリを作れる」ということに無限大の可能性を感じ、プログラミングにどっぷりハマります。この段階でプログラミングを小遣い稼ぎではなく、職として学んで行くことを決意しました。
上記の講座以外にも自分で興味を持った講座を貪ってました(寄り道しすぎたのは反省点です...)。
この期間で基礎を徹底的にインプットしまくったおかげで、新しい言語や応用の技術に挑戦するとき、「基礎×基礎」で何でも理解できるという自信がつきました。
まぁ要するに「俺にわからないことはない」という過信ですね。
以降難しい技術の学習が楽しいものと思えるようになったのはこの期間のおかげです。しかし、その過信も次のフェーズで打ち砕かれます。
3、モダンな技術にチャレンジ(Docker,AWS) (2020/3月)
この期間が一番辛かった時期だったと思います。
ローカルで開発したwebアプリを公開したいと思い、AWSの学習を開始しました。
しかし、ここでインフラの壁にぶち当たります。どの入門系書籍や記事を見ても「チョットナニイッテルカワカラナイ」
インフラを理解するにはコンピューターサイエンスの幅広い知識が必要となり、
今までの知見では太刀打ちできません。
吐かれるエラー文も意味がわからず、ググっても解決方法が見つからない...。よって最低限の知識を得るために「キタミ式 基本情報処理技術者試験」を購入し、ざっくり通読しました。
基本ソフトウェア、ネットワーク、セキュリティの知見を得たことで、AWSの各種サービスの役割を理解できるようになりました。世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで
次にこの記事をハンズオンでやったおかげで初めてRailsのデプロイに成功しました。さらにDockerを用いた開発手法のメリットも理解できるようになり、「Docker/Kubernetes 実践コンテナ開発入門」を購入し、Dockerにも挑戦しました。
ローカルのRailsアプリをDocker化することに成功したところで、必要な知識はもう十分という実感を得ました。
満を辞してポートフォリオ作成に取り掛かります。4、ポートフォリオ作成 (2020/4月~6月)
参考にした教材や記事
1 Vue,Nuxt超入門
2 Webサイト デザイン集
3 Github 超入門
4 いまさらだけどCircleCIに入門したので分かりやすくまとめてみた
5 初心者でもできる! ECS × ECR × CircleCIでRailsアプリケーションをコンテナデプロイ
6 AWS,FargateとTerraformで最強&簡単なインフラ環境を目指す
この時期は毎日が楽しかったです。
夢中でコード書いて、気づいたら夜が明けていたこともありました(真似しないでください)。
やはりプログラミングが好きなんだなと再実感しました。フロントエンドも何かしらのフレームワークを使い、凝ってみたいと思い、Nuxt.jsを採用し、RailsをAPIサーバーとして連携させる構成にしました。
Nuxtに関しては未学習だったため、教材や公式ドキュメントを見てキャッチアップしながらポートフォリオを作成していきました。あとポートフォリオのトップページやログイン直後の画面はめちゃくちゃ凝っておくことをお勧めします。
採用担当者様からサイトの第一印象でその後の評価も決まるとのアドバイスをいただきました。CI/CDやTerraformの構築に関しては、Qiita等で同様の環境での実装例を調べ、サンプルソースコードで理解できない箇所は公式ドキュメントを参考にしていました。
5、いざ、就職活動へ (2020/6月~7月)
はやく働きたいという焦りから、ポートフォリオ完成の8割の段階でWantedlyへの応募を開始し、就職活動しながらポートフォリオをブラッシュアップしていきました。
実際この選択は失敗だったなと反省しております。
なぜなら応募して返信があった場合、その会社様についての企業研究や面接対策を優先しないといけないため、ポートフォリオに時間を割くことができなかったからです。ある採用担当者様から、「技術力は認めるけど、ちょっと機能が不十分ですね...」とのご指摘を頂く羽目になりました。
「焦り」はこんな簡単なことすら気付けなくしてしまう。恐ろしいですね。
今回希望する企業様から内定を頂けたのは本当に幸いでした。
皆様には100%完成した段階で応募をかけ始めることをお勧めします。結果的に12社応募し、ご返事いただけたのは4社でした。
それと面接対策として僕がやっていたのは
業務未経験のWeb系エンジニア志望者が面接で聞かれる頻出質問とその対策
こちらの動画を参考に、質問における返答のテンプレ集を作成しました。
聞かれる質問の8割ぐらいはこの動画と同様のものでしたので、結果的に大成功でした。そして焦りと後悔の葛藤の中、Twitterへの直営業を考えていた矢先、
第一希望として応募させていただきた企業様から内定の連絡をいただきました。6、就活を終えての所感
「高卒フリーターの業務未経験でもwebエンジニアになれます!」なんて言うのは胡散臭いので気が引けますが、しっかりとしたプロセスを踏めば内定をもらえるというのを証明できたと思います。
学習順序を間違えなかったのが挫折しなかった一番の要因だと思います。
この半年間ここまでの熱量を注げたのはそれくらいプログラミングが好きだったからです。
生半可じゃ確実に無理でした。
今後ともこの熱量を絶やさずWebエンジニアとして成長していきたいと思います。最後までお読みいただきありがとうございました!。
- 投稿日:2020-07-11T18:08:12+09:00
未経験が受託企業に入って1年経ったので、学んだスキル全部書いてみる
はじめに
2019年6月にキャリアをスタートさせました。
Railsエンジニアとして1年でいろいろなことを学んできたので、簡単にまとめていきます。いろいろなキャリアの積み方があるのでどれほど成長できてるのかは不明ですが、ほんの一例としてご参考ください。
※表現のおかしい点等ありましたら、ご指摘頂けますと嬉しいです。前回:未経験が受託企業に入って半年経ったので、学んだスキル全部書いてみる
簡単な経歴
・一般大卒
パソコンスキルはitunesで音楽入れる程度
・某アパレルチェーンで3年勤務
内2年管理職
パソコンスキルはWordで毎週報告書を書く程度
・2018/12〜 Mac購入
某オンラインスクールで勉強開始
・2019/3〜 独学開始、都内もくもく会に週1参加、Menta契約、アプリ作成
・2019/6〜 就職
・2020/7 現在(2年目)半年〜1年で学んだこと
1)技術関連
Ruby/Rails
4ヶ月くらいは毎日触っていました。
入社当初よりだいぶ読むのに抵抗が無くなったなと思ってましたが、初めて別PJに移ると、同じRailsでもすんなり読めない箇所が結構出てきたので、まだまだ甘いんだなと痛感しました。業務フロー的にすごく複雑な機能の設計〜開発を担当し、作りながらお客様と何度も要件を擦り合わせ、完成後も改めてメンバーへ共有するのにはとても苦労した覚えがあります。
また、これまでは機能の追加や改修、0から開発などやってきましたが、次案件では主に
Capybara
Selenium
を使ったスクレイピング
をやりました。
Jobの仕組みや各サイトごとの要素取得のコツ、そして今まで以上にbyebugの貴重さを学びました。SQL(ActiveRecord)
実際に使ってもらうお客様の1部署が多忙で、システムを使っての作業まで回らないということがよくあり、最初のうちはこちらで「毎月◯日に叩くコマンド」というのを複数用意して実行していました(もうやりたくない)。
基本的には某テーブルに溜まっている先月分のデータのステータスを、条件に当てはまれば全て「未→承認」に変える、というものでしたが、先方の業務フローがいまいち不明瞭だったり、イレギュラーがあまりにも多く、実際のデータに弾かれて一発で終わるなんてまあありませんでした。
そのため「叩く→止まる(トランザクションで戻る)→要件確認して都度コード修正」が毎回しばらく続きました。こんな書き方があるのか、というところまで色々と試しながら書いていけたかなと思います。
Git
わざわざ書くことではないかもですが、日常的に
git stash
git log --oneline
を使うようになりました。
また、コンフリクトが発生しても、焦らずに冷静に対応できるようになりました(経験って怖い)。WordPress
Rails案件と掛け持ちして、20%くらいの時間を割いてやってました。
テーマ選定(Cocoon,OnePress等5テーマで試作)から、実際のお客様の要望に合わせたサイト製作、複数プラグイン導入、
Lightsail
でのサーバー利用、Route 53
でのドメイン作成、Letsencrypt
を使用したSSL化、Google Analytics
などの周辺設定 等、一通り経験できました。直接PHPをいじっての細かいカスタマイズはまだまだできないですが、テーマに乗っかればそこそこのサイトなら作れるようになりました。
0から新規サービス立ち上げ
こちらはとても良い経験になりました。
同PJ内ではありますが、新規サービスの要件定義〜設計〜開発〜テスト〜リリースまで一貫して行いました。
コンセプトは同じでもユーザー層が変わったため、画面が業務用のB向け→C向けに変わったのが印象的でした。タイトなスケジュールの中、Railsはもちろん、Deviseの詳細設定や別サービスとのDB共有、Viewの細かい調整やまで行いました。
Pure CSS
に慣れてなく、初めてフロントが嫌になりました(当時)。AWS
実務では主に
CloudFront
AWS WAF
Elastic Load Balancer
ACM
Route 53
あたりを触りました。
まったく分からない中でなんとか模索しつつ、何日も日を跨ぎながらやった記憶があります。
セキュリティの仕組みと知識が大まかにつきました。
他にもCloudWatch
Trusted Advisor
GuardDuty
あたりも触りました。
気付いたらコンソール画面への抵抗も無くなっていました。
だいぶ時間を使ってたので、コードが書きたいなあと思うことも多かったです。個人では
AWS SAA
という資格に合格しました。
実務で触ったあとにかなりの実力不足を痛感したので、せめて最低ラインまで浅く広く知識を得たいと思い学習し始めました。
結果、半年前の目標を達成できた形になりました。AWS認定ソリューションアーキテクトアソシエイト(AWS SAA)合格記
↑ 詳細はこちらに書いてますので、よかったら読んでみてください。ステージング/本番環境へのデプロイ
新規サービス立ち上げ時も、相変わらず毎週のようにデプロイ作業を行なっていました。
本番が落ちるなんていつものことでした(まだリリース前だったので勘弁)。
焦りながら必死でバグを見つけて修正していたので、デプロイする日は胃がキリキリしていました。開発環境がガラッと変わると、本番へ反映させてもcssがうまく反映されずなんだこりゃと思うことがありましたが、単純に
rails assets:precompile
を忘れてただけということがありました。今まで先人の用意したデプロイ一括コマンドにあやかって叩いてたので、甘えてたなと思うと同時に、そういえば自分の独学時代もHerokuにだけcss反映されずによく困ってたなwとか思い出して、懐かしんでました。
2)顧客対応
タスク/スケジュール管理
PLを任されていた関係で、雨のように降り注いでくる要望の全てを、お客様用へは
ガントチャート
、社内ではTrello
でまとめて管理していました。
ガントチャート
はGoogleスプレッドシート
から使用していました。
エクセルができないまま使い始めたので、大学時代にちゃんとやっとけば後悔しました。
Googleスプレッドシートを爆速で活用するための基本&応用の関数10選
Trello
は自分で提案して導入し、時間の限られる中でチームで効率よくタスクが見渡せるように工夫しました。
カスタマイズがしやすかったので、カードごとの工数表示やボードごとの自動工数計算など、必要なものはどんどん取り入れてました。
小規模チームのタスクをTrelloで管理する業務効率化
半年前にもありましたが、対応部署の増加や繁忙期が重なるなどでやりとりに苦戦するようになり、さらなる工夫が求められました。
・毎週のMTGを必要がない限り無くした
・部署ごとのチャットでの問い合わせで、問題に対する情報が足りず何往復もすることが多かったため、必須項目を絞り込みGoogleフォーム問い合わせ
+スプレッドシート自動更新
+slack通知
で大幅な時短化をさせた
・なるべく常にYESで答えていたが、多すぎるタスク量と開発の優先順位を考えてNOも使うようにした(でも相手の気を損ねないようにする)などを行いました。
[補足]次の1年でやりたいこと
今後学びたいスキルを書いていきます。
開発に力を入れたいです。※ アドバイス等頂けると嬉しいです。
Rails
上でも書いてますが案件が代わり改めて基礎力が低いことを通感しました。
原点に戻って、基礎からサッと復習したいなと思います。
Ruby on Rails チュートリアル
プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで
現場で使える Ruby on Rails 5速習実践ガイドあとは別PJだけでなく、社外で書かれてるコードを読むのも勉強になるので、githubで公開されてるコード等を積極的に読みたいです。
AWSをいじる
資格こそ取ったものの、実際に触るとなると全然できる自信がありません。
いわゆる「頭でっかち」状態だと思います。自分でVPC周りを組み立ててみたり、LambdaやSQSなどよく使われているであろうサービスにも慣れておきたいです。
できればコンテナサービス周りにも手を出してみたいです(先にDockerの勉強も必要ですが…)JavaScript
実務であまりJavaScriptを触っておらず、エンジニアとして結構な弱点だと感じています。
Vue.jsやReactなどに焦点をおかず、まずはじっくり生JavaScriptに慣れていこうと思います。改訂新版JavaScript本格入門 ~モダンスタイルによる基礎から現場での応用まで
JavaScript Primer
まずはこの辺りを参考にする予定です。IT基礎
知識不足を日々感じます。
まずは基本情報
でIT基礎を網羅的に頭に叩き込みます。
時期もちょうど良いので、秋の試験まで受けてしまおうかなと。その後
Linux
SQL
あたりも、王道めな技術書をざっと読んで早く頭に入れてしまいたいです。チームリーダー
一度経験させて頂きましたが、やや特殊な案件だった(笑)ため、普通の案件で経験してみたいです
相手が強いエンジニアの方でもきちんとコミュニケーションできるように、早くITスキルを高めていきます。突破力
ググり力こそ上がりましたが、基礎知識不足のせいか諦めて社内の人を頼ることも多々ありました。
ベースの力をつけるのはもちろん、その上で分からないことも粘り強く最後まで諦めないようにして、突破できる力をつけたいです。
ただ仕事なので、これ以上無駄だと判断したらタイミングよく見切るクセもつけたいです。なるべく意識してるのですが、この境目がなかなか難しいです。
- 投稿日:2020-07-11T15:53:51+09:00
Ruby on Rails 遷移元によって条件を変更させる2パターン
プログラミングスクールのチーム開発でECサイトを作成している際、
どこのリンク先から遷移したかでインスタンス変数を変えたい・・・
というような場面がありました。
その時に2パターンの方法があったので、備忘録として残します。【環境】
Ruby: 2.5.7
Rails: 5.2.4
使用した中で関係するgem:devise(顧客、管理者を作成)前提条件
- 管理者側のページで注文一覧を表示する際、下記のように設定したい。
- トップページから遷移 => 本日作成された注文一覧
- 顧客の詳細ページから遷移 => その顧客の注文一覧
- ヘッダーの注文一覧ボタンから遷移 => 全ての注文一覧
テーブル
schema.rbcreate_table "orders", force: :cascade do |t| t.integer "user_id", null: false (略) t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "users", force: :cascade do |t| (略) endモデル(アソシエーション)
user.rbhas_many :orders, dependent: :destroyorder.rbbelongs_to :userルート
namespace :admins do get '', to: 'products#top' resources :users, only: [:index, :show, :edit , :update] resources :orders, only: [:index, :show, :update] end実装パターン①:遷移元をコントローラで取得する
参考にした記事:Railsで遷移元のコントローラーとアクションを取得する
admins/orders_controller.rbdef index path = Rails.application.routes.recognize_path(request.referer) # path[:controller]で遷移元コントローラーを、path[:action]でアクションを取得 if path[:controller] == "admins/products" && path[:action] == "top" @orders = Order.where(created_at: Date.today) elsif path[:controller] == "admins/users" && path[:action] == "show" @orders = Order.where(user_id: path[:id]) else @orders = Order.all end endこれで、3パターンの変数を持たせることができました。
ただ、この内容だと【トップ画面からヘッダーの注文履歴ボタンを押した】際、
トップ画面から遷移したと判断されてしまいます。
そのため、最終的には下記の方法で実装を行いました。実装パターン②:リンク元にパラメーターを付ける
遷移元のリンクページには下記の通りパラメータを持たせました。
admins/products/top.html.erb<%= link_to "本日の注文件数", admins_orders_path(order_sort: 0) %>admins/users/show.html.erb<%= link_to "注文一覧", admins_orders_path(order_sort: 1) %>そしてコントローラ側では、持ってきたパラメーターで変数を振り分け
admins/orders_controller.rbdef index case params[:order_sort] when "0" @orders = Order.where(created_at: Date.today) when "1" @user = User.find(params[:user_id]) @orders = @user.orders else @orders = Order.all end endこれによって①の問題は解消されました。
まとめ
- ①の方法であればコントローラ側で一目見れば分岐条件がわかりやすいと思うが、状況に応じた実装が求められる。
- ①の方法を応用すれば、updateやdestroyアクションのリダイレクト先などを分岐させることも可能。
- 投稿日:2020-07-11T15:33:39+09:00
TECH CAMP学習 個人アプリ作成③
ユーザー情報編集機能の追加
まずはターミナルにて以下のコードを入力します。
terminal.$ rails g controller users続いてルーティングで下記を入力します。
routes.rbdevise_for :users root "photos#index" resources :users, only: [:edit, :update]resourcesの意味は日本語では資源をいう意味で、usersの中で編集と更新の機能を利用するという解釈でよいと思います。
続いてコントローラーを編集します。
users_controller.rbdef edit end def update if current_user.update(user_params) redirect_to root_path else render :edit end end private def user_params params.require(:user).permit(:name, :email) end①current_userはdeviseのヘルパーメソッドで、ログイン中のユーザー情報を取得できます。
②redirect_toは本来受け取ってるパスとは別のパスへ転送します。上記ではroot_pathに転送するということです。
③上記が失敗した場合、renderはeditを呼び出します。
④privateはプライベートメソッドで、クラス外から呼び出すことのできないメソッドです。
メリットしては
・classの外部から呼び出されたら困るメソッドを隔離
・可読性、classの外部から呼び出されたメソッドを探すときにprivate以下の部分は目を通さなくてよくなる。
⑤user_params以下はストロングパラメーターで、指定したキーを持つパラメーターのみを受け取るようにするものです。
⑥ストロングパラメーターの中でuserを要求(require)して:name,:emailの許可(permit)を得る。詳細を確認するにはupdateの直後にbinding.pryを使用する。
- 投稿日:2020-07-11T15:07:00+09:00
Rails5でECサイトを作る⑦ ~Address、Genreモデル編~
はじめに
架空のベーカリーで買い物できるECサイトを作るシリーズ、Rails5でECサイトを作る⑥の続きです。
今回はアプリ本体の実装に戻り、購入したパンの送り先住所を管理するAddressモデルと、商品をまとめるGenreモデルの周辺を作っていきます。ソースコード
https://github.com/Sn16799/bakeryFUMIZUKI
Modelのアソシエーション
Address
controller
app/controllers/addresses_controller.rbclass AddressesController < ApplicationController before_action :authenticate_customer! before_action :set_customer def edit @address = Address.find(params[:id]) if @address.customer_id != current_customer.id redirect_back(fallback_location: root_path) flash[:danger] = 'お探しのページにアクセスできません。' end end def index @address = Address.new @addresses = @customer.addresses end def create @address = @customer.addresses.build(address_params) if @address.save flash[:success] = '新しい住所を登録しました!' redirect_to addresses_path else @addresses = @customer.addresses flash[:danger] = '入力内容をご確認ください。各入力欄は2文字以上で記入されていますか?' render :index end end def update @address = Address.find(params[:id]) if @address.update(address_params) flash[:success] = '住所情報を更新しました!' redirect_to addresses_path else flash[:danger] = '入力内容をご確認ください。各入力欄は2文字以上で記入されていますか?' render :edit end end def destroy @address = Address.find(params[:id]) @address.destroy flash[:info] = '登録した住所を削除しました。' redirect_to addresses_path end private def set_customer @customer = current_customer end def address_params params.require(:address).permit(:post_code, :address, :addressee) end endindex画面
app/views/addresses/index.html.erb<div class="col-lg-10 offset-lg-1 offset-1 space"> <div class="container-fluid"> <h2> <span style="display: inline-block;">配送先</span> <span style="display: inline-block;">登録/一覧</span> </h2> </div> <!-- 新規住所フォーム --> <div class="container space"> <h3>新しく住所を登録</h3> <%= form_with(model: @address, local: true, class: 'container-fluid') do |f| %> <div class="form-group"> <%= f.label :郵便番号(ハイフンなし) %> <%= f.text_field :post_code, class: 'form-control' %> </div> <div class="form-group"> <%= f.label :住所 %> <%= f.text_field :address, class: 'form-control' %> </div> <div class="form-group"> <%= f.label :宛名 %> <%= f.text_field :addressee, class: 'form-control' %> </div> <div class="action w-25 offset-lg-11"> <%= f.submit '登録する', class: 'btn btn-danger' %> </div> <% end %> </div> <!-- 住所一覧 --> <div class="container space"> <h3>住所一覧</h3> <div class="row"> <div class="col-lg-3"> <strong>郵便番号</strong> </div> <div class="col-lg-3"> <strong>住所</strong> </div> <div class="col-lg-3"> <strong>宛名</strong> </div> </div> <% @addresses.each do |address| %> <div class="row"> <div class="col-lg-3"> <%= address.post_code %> </div> <div class="col-lg-3"> <%= address.address %> </div> <div class="col-lg-3"> <%= address.addressee %> </div> <div class="col-lg-3"> <%= link_to "編集する", edit_address_path(address), class:"btn btn-danger" %> <%= link_to "削除する", address_path(address), method: :delete, class:"btn btn-danger" %> </div> </div> <% end %> </div> </div>edit画面
app/views/addresses/edit.html.erb<div class="col-lg-10 offset-lg-1 space"> <div class="container"> <h2>配送先編集</h2> <%= form_with(model: @address, local: true) do |f| %> <div class="form-group"> <%= f.label :郵便番号(ハイフンなし) %> <%= f.text_field :post_code, autofocus: true, class: 'form-control' %> </div> <div class="form-group"> <%= f.label :住所 %> <%= f.text_field :address, class: 'form-control' %> </div> <div class="form-group"> <%= f.label :宛名 %> <%= f.text_field :addressee, class: 'form-control' %> </div> <div class="action w-25 offset-lg-11"> <%= f.submit '更新する', class: 'btn btn-danger' %> </div> <% end %> </div> </div>Genre
controller
app/controllers/genres_controoler.rbclass GenresController < ApplicationController def show @genre = Genre.find(params[:id]) @genres = Genre.where(validity: true) @products = @genre.products.page(params[:page]).per(9) end private def genre_params params.require(:genre).permit(:name,:id) end endindex
ファイル名はindexとしていますが、商品ジャンルの一覧画面というものはなく、いくつかのページで部分テンプレートとしてこのファイルを呼び出し、ジャンルごとの絞り込み表示をできるようにします。実質的にはサイドバーです。
app/views/genres/_index.html.erb<div id="sidebar" class="col-lg-2"> <table class='table'> <thead> <tr> <th>ジャンル検索</th> </tr> </thead> <tbody> <% genres.each do |genre| %> <tr> <td><%= link_to genre.name, genre_path(genre) %></td> </tr> <% end %> <tr> <td><%= link_to "⇒ すべての商品を見る", products_path, class: 'dark-blue-letter' %></td> </tr> </tbody> </table> </div>show画面
商品ジャンルの詳細画面は、例えば「食パン」「総菜パン」といったジャンルに属した商品を絞り込み表示する画面にします。
app/views/genres/show.html.erb<div class="col-lg-10 space"> <div class="container"> <h2><%= @genre.name %>一覧(全<%= @genre.products.count %>種)</h2> </div> <div class="container"> <% @genre.products.each do |gp| %> <%= render 'products/box', product: gp %> <% end %> </div> </div> <%= render 'genres/index', genres: @genres %>※部分テンプレート
app/views/products/_box.html.erb<div class="col-lg-4 product-box space"> <%= link_to product_path(product) do %> <div class="row"> <h4><%= product.name %></h4> </div> <div class="row"> <%= attachment_image_tag(product, :image, :fill, 220, 180, fallback: 'no_img.jpg') %> </div> <% end %> <div class="row"> <h4><%= price_include_tax(product.price) %></h4> </div> </div>データベース上は税抜価格しか保存されていないのですが、画面上の表示では税込価格にしたい。そんな時は、ヘルパーメソッドを利用します。
ヘルパー
app/helpers/application_helper.rbdef price_include_tax(price) price = price * 1.08 "#{price.round}円" end後記
AddressもGenreも、いたって標準的なCRUD機能のみなので、ほとんど迷わずにできたと思います。難しくなるのはこれから……。注文機能のあるOrderモデルは、以前作った時にはかなり苦労させられましたが、レスポンシブ対応の画面にして、より簡潔なコードで再現できるのでしょうか? 次回へ続く!
- 投稿日:2020-07-11T14:35:40+09:00
[翻訳]開発者が避けるべき8つのRailsのよくあるミス
原著者Hunny Jummani氏の許諾を得て翻訳・公開しています。
記事: The 8 Most Common Rails Mistakes Developers Should Avoid
原文公開日: 2020年4月22日Ruby on Railsはスケーラブル可能なパワフルなWebフレームワークで、完全なフロントエンドのサポートを持ったエンタープライズ対応のアプリケーションです。設定より規約やMVCパターンのようなRuby on Rails開発のシンプルな点が、高機能のアプリに対して信頼性を高めています。
Railsの開発者は、開発時間を短縮したり余計なコードを書かなくて済むRubyGemsを好んでいます。RubyGemsは標準的なプラクティスに従い、高速にMVPsをビルドし、製品の市場投入時間を短縮しています。
ですが、Railsの開発者は完璧ではありません。Ruby on Railsプロジェクトには固有の誤りはありませんが、一般的にはヒューマンエラーにより問題が発生します。
Ruby on Rails開発者には、経験を積むことでしか乗り越えられない落とし穴があります。この記事では、プロジェクトを頓挫させてしまう可能性がある8つのよくあるRuby on Rails開発のミスにスポットを当てています。Ruby on Rails開発者が避けるべき8つの最もよくあるミス
以下のRails開発者のよくあるミスは、プロジェクトのボトルネックとなることがあります。心配しないでください、将来あなたがこれらのミスをしないための解決方法を提供しています。Ruby on Railsプロジェクトでこれらのミスを避け、お客さんのためにバグのない解決方法を開発するためのためのガイダンスを提供します。
ミス #1: N+1クエリ
アプリケーションに問題が発生することはありませんが、アプリケーションのパフォーマンスに影響を与えます。
例:
users = User.where(is_active: true)
names = users.map { |user| user.profile.name }
レコードに関連づいたクエリを投げている間は、N+1クエリを避けることができます。
例:
users = User.where(is_active: true).includes(:profile)
names = users.map { |user| user.profile.name }
クエリの数を減らしてアプリケーションのパフォーマンスを向上させ、eager loadingを追加するタイミングを知らせてくれるbullet gemを使いましょう。
ミス #2: 設定を安全に保っていない
アプリケーションはGoogle カレンダーやStripe Payment、AWSのような外部サービスを使う可能性があり、そのAPIキーやクレデンシャルは
credentials.yml
やsecrets.yml
ファイルに保存されています。そのファイルは残りのアプリケーションと一緒にソースコードリポジトリに誤ってチェックインされてしまうことがあります。これが起きると、リポジトリにアクセスできる誰もが簡単にアプリケーションのユーザを危険に晒すことができてしまいます。
ミス #3: ロジックをコントローラに詰め込みすぎる
開発者は、コントローラ内のロジックが多すぎます。コントローラを薄くしておきましょう。単一責任の原則に違反してはいけません。
何を含めればいいのでしょうか?
セッションハンドル、モデル選択、パラメータ要求の管理、レンダリング、リダイレクトです。
ミス #4: ロジックをモデルに詰め込みすぎる
開発者は、emailの通知や、あるフォーマットから別のフォーマットへのデータ変換などのロジックを、モデルに詰め込みすぎています。
このコア機能はプレーンなrubyオブジェクトのようなサービスを使用して処理できるので、
ActiveRecord
から削除することができます。)何を含めればいいのでしょうか?
構成 (例:リレーションやバリデーション)
データベースで一握りの属性を更新、保存することをカプセル化するためのシンプルなミューテーションメソッド
内部モデル情報を隠すためのアクセスラッパ
例:
first_name
とlast_name
の組み合わせを表すfull_name洗練されたクエリ。モデルクラス外で
where
メソッドを使ったりクエリを構築してはいけません。ミス #5: 外部サービスの呼び出しによるブロック
Ruby on Railsアプリケーションのサードパーティ提供者は通常、APIの統合を非常に簡単にしてくれますが、速度が遅くなることもあります。
そのため、呼び出しでブロックされないために、Railsアプリケーションからサービスを呼び出すのではなく、コードのいくつかをバックグラウンドジョブに移動させるべきです。
これらのAPIサービスをキューイングするには、Delayed Job、Sidekiqなどを使う必要があります。
ミス #6: 不適切な述語メソッドの使用
述語メソッドはクエスチョンマーク(?) で終わり、論理値を返すメソッドです。
述語メソッドを作る時は、その目的について知っておくことが大切です。
メソッドが実行するものに名前をつけるべきであり、実行するアクションと名前が矛盾してはいけません。
例えば、ユーザが本を持っているかどうか確認するために、以下のようなユーザモデルで述語メソッドを定義すべきです。
def books_available?
self.books.present?
endミス #7: メモ化を使ってない
メモ化はRuby on Rails開発でアクセッサのスピードアップに使用されるテクニックです。
変数の初期化や手間がかかる作業のメソッドの結果をキャッシュします。キャッシュの変数を初期化するためには
||=
を使用します。パラメータの値や関連するレコードから変数を初期化するために使用されます。
例:
def google_calendar_event
@event ||= GoogleCalendarEvent.find_by(event_id: params[:event_id])
end
ミス #8: Ruby on Railsプロジェクトの命名規則に従っていない
開発中は以下のポイントを心に留めておいてください。
テーブル名は、モデルとテーブルを自動的にマップするために複数形にしてください。
モデル名は単数形にしてください。
クラスで予約名を使わないでください。例えば、"Class" は使えませんが、"Klass" は使えます。
コントローラ名は複数形にして、複数の単語を使いたい場合はキャメルケースを使ってください。
複雑さを避けるためにデフォルトのRESTfulのルートに従ってください。
Ruby on Railsは、ウェブアプリケーション開発のためのパワフルで多機能なフレームワークです。Ruby on Railsアプリケーションがいくつかの限界を持つ一方で、デプロイメントやデバッギングをしている間、開発者が注意を払っていないためにミスが起きてしまいます。
上記のミスを避けることで、一流のRuby on Railsアプリケーションを構築できます。Ruby on Railsアプリケーション開発のリーディングカンパニーであるBoTreeでは、アプリケーションからバグを取り除くためのRubyベストプラクティスに従っています。当社の開発者は経験豊富なので、これらの失敗を学んでおり、プロジェクトを頓挫させないようにしています。高速でエラーがない開発のために、当社からRuby on Railsの開発者を雇うことができます。
BoTree Technologie では、25名以上のエンジニアのRuby on Railsチームでエンタープライズアプリケーションを構築しています。
私達は、Python、RPA、AI、Django、Javascript、ReactJSも専門としています。
コンサルティングは無料です。あなたの成長のお手伝いをさせてください。
翻訳を終えて
仕事でRails開発を始めて間もないので、このようなアンチパターンを知ることができ、助かりました。
上記の中でN+1は有名なので知っていましたが、メモ化はその存在自体を全く知りませんでした。
なるべく落とし穴にはまらないように進めていきたいですね。
誤訳等ありましたらご指摘をお願いします。
- 投稿日:2020-07-11T14:26:23+09:00
Webpacker::Manifest::MissingEntryError
画像のエラーを解決するのに手間取りすぎたから、備忘録メモです。
先に結論
僕の場合は
docker-compose run --rm web yarn install
したら解決した環境
【環境】
・Ruby 2.6.6
・Rails 6.0.3.2
・DockerDockerfile
qiita.rbFROM ruby:2.6 # install package to docker container RUN apt-get update -qq && apt-get install -y build-essential libpq-dev \ && apt-get install apt-transport-https \ && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \ && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \ && apt-get update && apt-get install -y yarn \ && curl -sL https://deb.nodesource.com/setup_10.x | bash - \ && apt-get install -y nodejs \ && mkdir /アプリ名 WORKDIR /FANTRA COPY Gemfile /アプリ名/Gemfile COPY Gemfile.lock /アプリ名/Gemfile.lock COPY entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] EXPOSE 3000確認したこと
- webpackerインストールしてるか?
- rails webpacker:install 実行ずみ (実行すると、
conflict config/webpacker.yml
が出る)- yarnインストールしてるか?
- 1.22.4
- nodejsインストールしてるか?
- v10.21.0
必要な物は揃っているはずなのになぜかできない。。。
わかってなかったこと
yarn ないし npm はruby でいうところのbundlerで、ライブラリを管理してくれるnodejsのツールのこと。
bundle install
しないと ruby のライブラリが利用できないのと同じようにyarn install
を実行しないと、 package.json によって指定されている nodejs ライブラリがダウンロードされず実行できないらしい。
webpack はnodejs のライブラリやから、このエラーを解消するためにはyarn install
をbundle install
と同じような取り扱いで実行する必要があるらしい。yarn installをしてみる
qiita.rb$ docker-compose run --rm web yarn install無事にエラーを解決することができました。
メモ
DockerfileのRUNしてるものとかymlの内容とかで実行しないといけないコマンド違ってくるのかな??
- 投稿日:2020-07-11T12:35:15+09:00
[Rails] link_toのリンク先を別タブで表示させたい
Railsでlink_toを使うときに別タブで表示させたいと思い、実装したのでメモとして残しておきます。
手順
まず
link_to
で表示させたい文字列とリンク先URLを指定。<%= link_to "文字列", "リンク先URL" %>別タブで表示させるため、
target: :_blank
を追加<%= link_to "文字列", "リンク先URL", target: :_blank %>これで別タブで開けるようになる。
しかし、これだとパフォーマンスとセキュリティの面で問題が。。。この問題を回避するためには
rel="noopener noreferrer"
をつけるといいみたい。<%= link_to "文字列", "リンク先URL", target: :_blank, rel: "noopener noreferrer" %>これで安心して別タブを開けます。
- 投稿日:2020-07-11T12:04:00+09:00
新規登録時、ActionMailerでメール送信機能
概要
ActionMailerを使って新規登録時にwelcomeメールを送ります。
前提
deviseを用いての、ログイン機能の実装。
導入手順
1. ActionMailerを利用する設定
welcomeメールの送信元はGmailを使う記載方法。
config/environments/development.rb
にてActionMailerの設定方法の記述。development.rbRails.application.configure do #---中略---# config.action_mailer.raise_delivery_errors = true config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { port: 587, address: 'smtp.gmail.com', domain: 'gmail.com', user_name: '送信元アドレス', password: 'アプリパスワード', authentication: :plain, enable_starttls_auto: true }アプリパスワードは2段階認証を設定の上16桁のパスワードを発行し、アプリパスワードに記載する。
以下、参考にさせていただきました。
・Google メールアプリケーション用のパスワードを取得する
・Google 二段階認証設定をONにする方法2. Mailerクラス作成
$ rails g mailer UserNotice3. Mailerクラス編集
app/mailers/user_notice_mailer.rbclass UserNoticeMailer < ApplicationMailer def send_signup_email(user) @user = user mail to: @user.email, subject: "会員登録が完了しました。" end end4. メール本文作成
app/views/user_notice_mailer/send_signup_email.text.erbようこそ <%= @user.name %> 様 この度はアカウント登録頂きましてありがとうございます。5. Userモデル編集
app/models/user.rb#---追加---# after_create :send_welcome_mail def send_welcome_mail UserNoticeMailer.send_signup_email(self).deliver endafter_create を使うことで、Userが新規作成された後にメールを送信するためのメソッドを呼び出すことができます。
以上で、welcomeメールが送信されるはずです。
- 投稿日:2020-07-11T10:52:52+09:00
[Rails]DBにデータが登録されない場合の対処法
はじめに
フォーム入力内容をDBに保存したいがハマったのでアウトプット
環境
Rails 5.0.7.2
ruby 2.5.1
mysql 14.14問題点
フォーム入力内容を保存しようとすると、パラメータに保存されているがDBに保存されない。
対処方法
保存するメソッドの後ろに!をつけて原因を確認。
すると、validation failed:User must exist(エラー内容は異なる場合がありそう)
原因
アソシエーションが組まれている際に、該当の外部キーが入っておらず、バリデーションで弾かれているのが原因。
optional: trueを記述。
goal.rbclass Goal < ApplicationRecord validates :name, presence: true, uniqueness: true validates :time, presence: true, uniqueness: true validates :days, presence: true, uniqueness: true belongs_to :user, optional: true #ここを編集 endoptional: trueとは、belongs_toの外部キーのnilを許可するというもの。
これでDBに保存できると思います。
参考にしてください!
- 投稿日:2020-07-11T10:04:27+09:00
Rails6・unicorn、nginx、postgresのdockerコンテナを別々で立てる
紹介する内容
- dockerコンテナを三つ(Rails6とunicorn一緒に、nginx、postgres)にして立てます
- nginxのUNIX-domain socketとdocker composeのvolume活用します
結論
Rails6コンテナはunicornをforegroundで起動、nginxのUNIX-domain socketをdocker composeのvolumeマウントしたら動きます
- Rails6コンテナはunicornをforegroundで起動させて、nginxの通信を待ちながらコンテナが落ちない(exit 0)ようにします
- nginxのUNIX-domain socketをdocker composeのvolumeを使って、Rails6コンテナのunicornに共有させます
- UNIX-domain socket使いますからportはnginxとpostgresだけ開けば十分です
AWS ECSなどに活用できます
- dockerコンテナを別々に立てる予定のECSに
このコンテナ構成動くか?
の事前試しができますpriでデバックしずらくなりますから、開発環境ならRailsコンテナ一つ立てて
bundle exec rails s
することを推奨します
- binding.pryはかかりますが、ユーザーが値を入力できるところがよく分かりません
- Railsコンテナにdocker attachしてもだめでした
紹介始めます
ディレクトリ構成
全体ソースコードは https://github.com/cheekykorkind/qiita-example/tree/master/rails/6/unicorn-nginx で確認できます
nginx confファイル説明
いろいろ書かれてますが、必要な部分だけ書きます
./docker/nginx/nginx.conf
ファイルです
include /etc/nginx/conf.d/*.conf;
によって、./docker/nginx/web.conf
が読み込めます./docker/nginx/web.conf
ファイルです
- 全てのrequestが
location /
に入りますproxy_pass http://unicorn;
によってupstream unicorn
に行きますunix:/workspace/myapp/tmp/unicorn.todo.sock
に来たらUNIX-domain socketで通信します
- UNIX-domain socketを簡単に説明すると
ファイルを持って通信できる
です。
- ですから、docker composeのマウントだけでnginxとunicornが連携できます
- https://en.wikipedia.org/wiki/Unix_domain_socket
upstream unicorn { server unix:/workspace/myapp/tmp/unicorn.todo.sock fail_timeout=0; } server { listen 80; location / { ...省略 proxy_pass http://unicorn; ...省略 } ...省略 }unicorn設定ファイル説明
./config/unicorn/development.rb
ファイルですlisten "#{RAILS_ROOT}/tmp/unicorn.todo.sock"
をnginxのconfファイルの内容と同じパスを書くことでUNIX-domain socketの通信ができますdocker周り実装説明
./docker-compose.yml
ファイルですbundle exec unicorn -c ./config/unicorn/development.rb
でunicornをforegroundで起動します- UNIX-domain socketの専用volumeを作ります
volumes: nginx_socket: driver: localそして、
nginx_socket:/workspace/myapp/tmp
でdockerコンテナ中でマウントするパスを設定します。
unicornとnginxが同じファイルをマウントできるように各々のコンテナに同じく書きます。試し順番です
- docker composeがあるデレクトリーに移動します
cd qitta-example/rails/6/unicorn-nginx
- dockerコンテナをバックグラウンドで起動します
DOCKER_UID=$(id -u $USER) DOCKER_GID=$(id -g $USER) docker-compose up -d
- 投稿日:2020-07-11T09:54:03+09:00
rake routesでDevise.secret_key was not set. Please add the following to your Devise initializer:がでる
環境
ruby 2.5.1 Rails 5.0.7.2やろうとしたこと
1)
rake routes
早速ターミナルがエラー吐き出しています。
ターミナルを見ます。rake aborted! Devise.secret_key was not set. Please add the following to your Devise initializer: config.secret_key = 'e9216d77fb79ef05XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX’ Please ensure you restarted your application after installing Devise or setting the key.2)ここの文に注目します。
installing
のDevise
のsetting the key
に注目しなよって言っています。Please ensure you restarted your application after installing Devise or setting the key.3)
config/initializers/devise.rb
の以下のコメントアウトを外すBefor
# config.secret_key = '7f2977830281c6192ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ’
After
config.secret_key = '7f2977830281c6192ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ’念のためターミナルで出力された
secret_key
をいれるconfig.secret_key = 'e9216d77fb79ef05XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX’完了done!
- 投稿日:2020-07-11T01:32:38+09:00
[Rails]carrierwaveを使って画像を保存する
タイトルの通りになります。
ゴールは画像を表示させるまでとなります。
gemを導入
初めはgemを入れます。
バージョンを指定しなければ最新のものがインストールされます。Gemfilegem 'carrirewave'ターミナルでいつものよろしくお願いします。
$ bundle installアップローダファイルの生成
次にアップローダファイルを作成しましょう。
$ rails generate uploader Image create app/uploaders/image_uploader.rbこれで
app/uploaders
の中にimage_uploader.rb
が生成されていると思います。ちなみに
Image
の部分はマウントするモデル名だとか,
わかりやすい名前。私はよくImageで生成しています。image_uploader.rbclass ImageUploader < CarrierWave::Uploader::Base # Include RMagick or MiniMagick support: # include CarrierWave::RMagick # include CarrierWave::MiniMagick # process resize_to_fit: [300, 200] # version :thumb do # process :resize_to_fit => [50, 50] # end # 以下省略 endこのファイルの中で画像アップロードに関する設定ができます。例えば、アップロードする画像の拡張子の制限だったり、画像サイズのリサイズだったりいろんなことができます。
モデルに書く
画像アップロードさせたいモデルに先ほど作成したファイルをマウントしてあげましょう。
今回はhogeモデルのimageカラムに画像を登録させたいケースで考えます。
hoge.rbclass hoge < ApplicationRecord mount_uploader :image, ImageUploader end登録するためのFormを作る
各ページ必要な情報を渡してあげます。
hoges_controller.rbclass ArticlesController < ApplicationController def new @article = Article.new end def create @article = Article.new(user_params) if @article.save redirect_to user_path(@article) else render :new end end private def article_params params.require(:article).permit(:image) end end/hoges/new.html<%= form_with model: @hoge, local: true do %> <div class="field"> <%= f.label :image %> <%= f.file_field :image %> <!--画像はfile_field --> <div class="action"> <%= f.submit %> </div> <% end %>アップロードした画像の表示
画像の表示は基本的には、以下のように記述すると表示されます。
<%= image_tag @article.image.url %> <%= image_tag @article.image.to_s %>終わりに
最後まで読んでいただきありがとうございます。
お勉強している方に少しでも力になればと思います。
- 投稿日:2020-07-11T00:36:56+09:00
Ruby on Rails チュートリアル(第4版) 第7章
7.1.1 演習
1.ブラウザから /about にアクセスし、デバッグ情報が表示されていることを確認してください。このページを表示するとき、どのコントローラとアクションが使われていたでしょうか? paramsの内容から確認してみましょう。
controller: static_pages
action: about
2.Railsコンソールを開き、データベースから最初のユーザー情報を取得し、変数userに格納してください。その後、puts user.attributes.to_yamlを実行すると何が表示されますか? ここで表示された結果と、yメソッドを使ったy user.attributesの実行結果を比較してみましょう。>> puts user.attributes.to_yaml --- id: 1 name: Michael Hartl email: mhartl@example.jp created_at: !ruby/object:ActiveSupport::TimeWithZone utc: &1 2020-07-04 13:19:58.704260000 Z zone: &2 !ruby/object:ActiveSupport::TimeZone name: Etc/UTC time: *1 updated_at: !ruby/object:ActiveSupport::TimeWithZone utc: &3 2020-07-04 13:29:40.208038000 Z zone: *2 time: *3 password_digest: "$2a$10$lIblqgEiCfLVJhfbugPd/epzBk4kR7Vi6bMYF8e2Yjb3iIkPwLrS6" => nil>> y user.attributes --- id: 1 name: Michael Hartl email: mhartl@example.jp created_at: !ruby/object:ActiveSupport::TimeWithZone utc: &1 2020-07-04 13:19:58.704260000 Z zone: &2 !ruby/object:ActiveSupport::TimeZone name: Etc/UTC time: *1 updated_at: !ruby/object:ActiveSupport::TimeWithZone utc: &3 2020-07-04 13:29:40.208038000 Z zone: *2 time: *3 password_digest: "$2a$10$lIblqgEiCfLVJhfbugPd/epzBk4kR7Vi6bMYF8e2Yjb3iIkPwLrS6" => nil7.1.2 演習
1.埋め込みRubyを使って、マジックカラム (created_atとupdated_at) の値をshowページに表示してみましょう (リスト 7.4)。
/app/views/users/show.html.erb<%= @user.name %>, <%= @user.email %><%= @user.created_at %><%= @user.updated_at %>2.埋め込みRubyを使って、Time.nowの結果をshowページに表示してみましょう。ページを更新すると、その結果はどう変わっていますか? 確認してみてください。
秒数が進む。日本の時間とはズレているみたい。<%= @user.name %>, <%= @user.email %><%= @user.created_at %><%= @user.updated_at %><%= Time.now %>7.1.3 演習
1.showアクションの中にdebuggerを差し込み (リスト 7.6)、ブラウザから /users/1 にアクセスしてみましょう。その後コンソールに移り、putsメソッドを使ってparamsハッシュの中身をYAML形式で表示してみましょう。ヒント: 7.1.1.1の演習を参考にしてください。その演習ではdebugメソッドで表示したデバッグ情報を、どのようにしてYAML形式で表示していたでしょうか?
(byebug) puts @user.attributes.to_yaml --- id: 1 name: Michael Hartl email: mhartl@example.jp created_at: !ruby/object:ActiveSupport::TimeWithZone utc: &1 2020-07-04 13:19:58.704260000 Z zone: &2 !ruby/object:ActiveSupport::TimeZone name: Etc/UTC time: *1 updated_at: !ruby/object:ActiveSupport::TimeWithZone utc: &3 2020-07-04 13:29:40.208038000 Z zone: *2 time: *3 password_digest: "$2a$10$lIblqgEiCfLVJhfbugPd/epzBk4kR7Vi6bMYF8e2Yjb3iIkPwLrS6" nil2.newアクションの中にdebuggerを差し込み、/users/new にアクセスしてみましょう。@userの内容はどのようになっているでしょうか? 確認してみてください。
(byebug) @user Started GET "/users/new" for 182.168.132.37 at 2020-07-10 13:03:56 +0000 #<User id: 1, name: "Michael Hartl", email: "mhartl@example.jp", created_at: "2020-07-04 13:19:58", updated_at: "2020-07-04 13:29:40", password_digest: "$2a$10$lIblqgEiCfLVJhfbugPd/epzBk4kR7Vi6bMYF8e2Yjb...">7.1.4 演習
1.(任意) Gravatar上にアカウントを作成し、あなたのメールアドレスと適当な画像を紐付けてみてください。メールアドレスをMD5ハッシュ化して、紐付けた画像がちゃんと表示されるかどうか試してみましょう。
省略2.7.1.4で定義したgravatar_forヘルパーをリスト 7.12のように変更して、sizeをオプション引数として受け取れるようにしてみましょう。うまく変更できると、gravatar_for user, size: 50といった呼び出し方ができるようになります。重要: この改善したヘルパーは10.3.1で実際に使います。忘れずに実装しておきましょう。
省略3.オプション引数は今でもRubyコミュニティで一般的に使われていますが、Ruby 2.0から導入された新機能「キーワード引数 (Keyword Arguments)」でも実現することができます。先ほど変更したリスト 7.12を、リスト 7.13のように置き換えてもうまく動くことを確認してみましょう。この2つの実装方法はどういった違いがあるのでしょうか? 考えてみてください。
良く分からなかったのでオプション引数とキーワード引数について調べました。
キーワード引数とオプション引数についてまとめてみた7.2.1 演習
1.試しに、リスト 7.15にある:nameを:nomeに置き換えてみましょう。どんなエラーメッセージが表示されるようになりますか?
undefined method
nome' for #User:0x00007ff659c23830`2.試しに、ブロックの変数fをすべてfoobarに置き換えてみて、結果が変わらないことを確認してみてください。確かに結果は変わりませんが、変数名をfoobarとするのはあまり良い変更ではなさそうですね。その理由について考えてみてください。
考えよう演習は正解が分からないので難しい。
Formの変数名なので関係ないfoobarはあまり良くない、という感じなのかな?7.2.2 演習
1.Learn Enough HTML to Be DangerousではHTMLをすべて手動で書き起こしていますが、なぜformタグを使わなかったのでしょうか? 理由を考えてみてください。
Formタグは便利だけど、勝手に考えてコードを作ってくれる=仕組みをちゃんと理解出来ないから。
なのかな。Rails凄い。7.3.2 演習
1./signup?admin=1 にアクセスし、paramsの中にadmin属性が含まれていることをデバッグ情報から確認してみましょう。
admin: '1'
の記載あり7.3.3 演習
1.最小文字数を5に変更すると、エラーメッセージも自動的に更新されることを確かめてみましょう。
/app/models/user.rbvalidates :password, presence: true, length: { minimum: 5 }
Password is too short (minimum is 5 characters)
2.未送信のユーザー登録フォーム (図 7.12) のURLと、送信済みのユーザー登録フォーム (図 7.18) のURLを比べてみましょう。なぜURLは違っているのでしょうか? 考えてみてください。
newアクション→createアクションに変わったから。7.3.4 演習
1.リスト 7.20で実装したエラーメッセージに対するテストを書いてみてください。どのくらい細かくテストするかはお任せします。リスト 7.25にテンプレートを用意しておいたので、参考にしてください。
考えたけど良く分からずカンニングしてしまいました。
エラーメッセージに対するテスト: Railsチュートリアル備忘録 - 7章
assert_select
でHTMLのタグの中身を確認する
エラーだったときに下記のdivが展開されてるかどうかのテストかな。<div id="error_explanation"> <div class="alert alert-danger">/sample_app/test/integration/users_signup_test.rbassert_select 'div#error_explanation' assert_select 'div.alert'2.ユーザー登録フォームのURLは /signup ですが、無効なユーザー登録データを送付するとURLが /users に変わってしまいます。これはリスト 5.43で追加した名前付きルート (/signup) と、RESTfulなルーティング (リスト 7.3) のデフォルト設定との差異によって生じた結果です。リスト 7.26とリスト 7.27の内容を参考に、この問題を解決してみてください。うまくいけばどちらのURLも /signup になるはずです。あれ、でもテストは greenのままになっていますね...、なぜでしょうか? (考えてみてください)
resources :users のcreateアクションがusers_pathだから。3.リスト 7.25のpost部分を変更して、先ほどの演習課題で作った新しいURL (/signup) に合わせてみましょう。また、テストが greenのままになっている点も確認してください。
/test/integration/users_signup_test.rbpost signup_path, params: { user: { name: "", email: "user@invalid", password: "foo", password_confirmation: "bar" } }4.リスト 7.27のフォームを以前の状態 (リスト 7.20) に戻してみて、テストがやはり greenになっていることを確認してください。これは問題です! なぜなら、現在postが送信されているURLは正しくないのですから。assert_selectを使ったテストをリスト 7.25に追加し、このバグを検知できるようにしてみましょう (テストを追加して redになれば成功です)。その後、変更後のフォーム (リスト 7.27) に戻してみて、テストが green になることを確認してみましょう。ヒント: フォームから送信してテストするのではなく、'form[action="/signup"]'という部分が存在するかどうかに着目してテストしてみましょう。
/sample_app/test/integration/users_signup_test.rbassert_select 'form[action="/signup"]'7.4.1 演習
1.有効な情報を送信し、ユーザーが実際に作成されたことを、Railsコンソールを使って確認してみましょう。
省略
2.リスト 7.28を更新し、redirect_to user_url(@user)とredirect_to @userが同じ結果になることを確認してみましょう。
省略7.4.3 演習
1.コンソールに移り、文字列内の式展開 (4.2.2) でシンボルを呼び出してみましょう。例えば"#{:success}"といったコードを実行すると、どんな値が返ってきますか? 確認してみてください。
>> "#{:success}" => "success"2.先ほどの演習で試した結果を参考に、リスト 7.30のflashはどのような結果になるか考えてみてください。
valueの値の文字列が返ってくる。7.4.3 演習
1.Railsコンソールを使って、新しいユーザーが本当に作成されたのかもう一度チェックしてみましょう。結果は、リスト 7.32のようになるはずです。
省略2.自分のメールアドレスでユーザー登録を試してみましょう。既にGravatarに登録している場合、適切な画像が表示されているか確認してみてください。
省略7.4.4 演習
1.7.4.2で実装したflashに対するテストを書いてみてください。どのくらい細かくテストするかはお任せします。リスト 7.34に最小限のテンプレートを用意しておいたので、参考にしてください (FILL_INの部分を適切なコードに置き換えると完成します)。ちなみに、テキストに対するテストは壊れやすいです。文量の少ないflashのキーであっても、それは同じです。筆者の場合、flashが空でないかをテストするだけの場合が多いです。
/test/integration/users_signup_test.rbassert_not flash.empty?2.本文中でも指摘しましたが、flash用のHTML (リスト 7.31) は読みにくいです。より読みやすくしたリスト 7.35のコードに変更してみましょう。変更が終わったらテストスイートを実行し、正常に動作することを確認してください。なお、このコードでは、Railsのcontent_tagというヘルパーを使っています。
省略3.リスト 7.28のリダイレクトの行をコメントアウトすると、テストが失敗することを確認してみましょう。
REDになる。4.リスト 7.28で、@user.saveの部分をfalseに置き換えたとしましょう (バグを埋め込んでしまったと仮定してください)。このとき、assert_differenceのテストではどのようにしてこのバグを検知するでしょうか? テストコードを追って考えてみてください。
'User.count', 1
にならないのを検知する。またしてもエラー
heroku run rails db:migrate
がまたうまくいかない。前章でもエラーが。何故だろう。
前章と同じく、heroku command not found の対処を参考に。7.5.3 演習
1.ブラウザから本番環境 (Heroku) にアクセスし、SSLの鍵マークがかかっているか、URLがhttpsになっているかどうかを確認してみましょう。
無事デプロイ出来て、確認出来た。2.本番環境でユーザーを作成してみましょう。Gravatarの画像は正しく表示されているでしょうか?
省略メモ
- Railsには標準で3つ環境が備わっており、それぞれ開発環境 (development)、テスト環境 (test)、本番環境 (production)と呼ぶ
any?
メソッドはちょうどempty?
と逆の動作で、要素が1つでもある場合はtrue、ない場合はfalseを返す。
- 投稿日:2020-07-11T00:32:45+09:00
Puma caught this error: Missing `secret_key_base` for 'development' environment, set this value in `config/secrets.yml` (RuntimeError)
前提
rails s
をしてlocalhost:3000/
にアクセスするとエラーが頻発する
タイトルと全く同じエラーをさっさと解決したい場合は8)
から閲覧してください環境
ruby 2.5.1 Rails 5.0.7.2最終エラー
localhost:3000/
で正しいviewではなく以下の表示がされるPuma caught this error: Missing `secret_key_base` for 'development' environment, set this value in `config/secrets.yml` (RuntimeError) /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/application.rb:513:in `validate_secret_key_config!' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/application.rb:246:in `env_config' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/engine.rb:693:in `build_request' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/application.rb:521:in `build_request' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/engine.rb:521:in `call' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/puma-3.12.6/lib/puma/configuration.rb:227:in `call' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/puma-3.12.6/lib/puma/server.rb:706:in `handle_request' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/puma-3.12.6/lib/puma/server.rb:476:in `process_client' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/puma-3.12.6/lib/puma/server.rb:334:in `block in run' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/puma-3.12.6/lib/puma/thread_pool.rb:135:in `block in spawn_thread'現在のエラーに至る過程
1)
rails s
をしたときに以下のメッセージがコンソールにでるCould not find fog-aws-3.6.4 in any of the sources Run `bundle install` to install missing gems.2)
bundle instal
をする3)再度
rails s
すると以下のメッセージがでる/Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/devise-4.7.1/lib/devise/rails/routes.rb:500:in `raise_no_secret_key': Devise.secret_key was not set. Please add the following to your Devise initializer: (RuntimeError) config.secret_key = '65a95ec21686dc552d1312XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX’補足:エラー全体
rails s => Booting Puma => Rails 5.0.7.2 application starting in development on http://localhost:3000 => Run `rails server -h` for more startup options Exiting Traceback (most recent call last): 65: from bin/rails:3:in `<main>' 64: from bin/rails:3:in `load' 63: from /Users/ユーザー名/Desktop/fleamarket_sample_72a_ver02/bin/spring:15:in `<top (required)>' 62: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require' 61: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require' 60: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/spring-2.1.0/lib/spring/binstub.rb:11:in `<top (required)>' 59: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/spring-2.1.0/lib/spring/binstub.rb:11:in `load' 58: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/spring-2.1.0/bin/spring:49:in `<top (required)>' 57: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/spring-2.1.0/lib/spring/client.rb:30:in `run' 56: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/spring-2.1.0/lib/spring/client/command.rb:7:in `call' 55: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/spring-2.1.0/lib/spring/client/rails.rb:28:in `call' 54: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/spring-2.1.0/lib/spring/client/rails.rb:28:in `load' 53: from /Users/ユーザー名/Desktop/fleamarket_sample_72a_ver02/bin/rails:9:in `<top (required)>' 52: from /Users/ユーザー名/Desktop/fleamarket_sample_72a_ver02/bin/rails:9:in `require' 51: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/commands.rb:18:in `<top (required)>' 50: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/commands/commands_tasks.rb:49:in `run_command!' 49: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/commands/commands_tasks.rb:85:in `server' 48: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/commands/commands_tasks.rb:85:in `tap' 47: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/commands/commands_tasks.rb:90:in `block in server' 46: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/commands/server.rb:102:in `start' 45: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/commands/server.rb:148:in `log_to_stdout' 44: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.2.2/lib/rack/server.rb:422:in `wrapped_app' 43: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/commands/server.rb:84:in `app' 42: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.2.2/lib/rack/server.rb:249:in `app' 41: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.2.2/lib/rack/server.rb:349:in `build_app_and_options_from_config' 40: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.2.2/lib/rack/builder.rb:66:in `parse_file' 39: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.2.2/lib/rack/builder.rb:105:in `load_file' 38: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.2.2/lib/rack/builder.rb:116:in `new_from_string' 37: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rack-2.2.2/lib/rack/builder.rb:116:in `eval' 36: from /Users/ユーザー名/Desktop/fleamarket_sample_72a_ver02/config.ru:3:in `block in <main>' 35: from /Users/ユーザー名/Desktop/fleamarket_sample_72a_ver02/config.ru:3:in `require_relative' 34: from /Users/ユーザー名/Desktop/fleamarket_sample_72a_ver02/config/environment.rb:5:in `<top (required)>' 33: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/application.rb:352:in `initialize!' 32: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/initializable.rb:54:in `run_initializers' 31: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/2.5.0/tsort.rb:205:in `tsort_each' 30: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/2.5.0/tsort.rb:226:in `tsort_each' 29: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/2.5.0/tsort.rb:347:in `each_strongly_connected_component' 28: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/2.5.0/tsort.rb:347:in `call' 27: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/2.5.0/tsort.rb:347:in `each' 26: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/2.5.0/tsort.rb:349:in `block in each_strongly_connected_component' 25: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/2.5.0/tsort.rb:431:in `each_strongly_connected_component_from' 24: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/2.5.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component' 23: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/2.5.0/tsort.rb:228:in `block in tsort_each' 22: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/initializable.rb:55:in `block in run_initializers' 21: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/initializable.rb:30:in `run' 20: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/initializable.rb:30:in `instance_exec' 19: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/application/finisher.rb:119:in `block in <module:Finisher>' 18: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/application/routes_reloader.rb:7:in `execute_if_updated' 17: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/application/routes_reloader.rb:27:in `updater' 16: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.0.7.2/lib/active_support/file_update_checker.rb:77:in `execute' 15: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/application/routes_reloader.rb:26:in `block in updater' 14: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/application/routes_reloader.rb:16:in `reload!' 13: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/application/routes_reloader.rb:40:in `load_paths' 12: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/application/routes_reloader.rb:40:in `each' 11: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/application/routes_reloader.rb:40:in `block in load_paths' 10: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.0.7.2/lib/active_support/dependencies.rb:287:in `load' 9: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.0.7.2/lib/active_support/dependencies.rb:259:in `load_dependency' 8: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.0.7.2/lib/active_support/dependencies.rb:287:in `block in load' 7: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activesupport-5.0.7.2/lib/active_support/dependencies.rb:287:in `load' 6: from /Users/ユーザー名/Desktop/fleamarket_sample_72a_ver02/config/routes.rb:1:in `<top (required)>' 5: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/actionpack-5.0.7.2/lib/action_dispatch/routing/route_set.rb:373:in `draw' 4: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/actionpack-5.0.7.2/lib/action_dispatch/routing/route_set.rb:391:in `eval_block' 3: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/actionpack-5.0.7.2/lib/action_dispatch/routing/route_set.rb:391:in `instance_exec' 2: from /Users/ユーザー名/Desktop/fleamarket_sample_72a_ver02/config/routes.rb:15:in `block in <top (required)>' 1: from /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/devise-4.7.1/lib/devise/rails/routes.rb:228:in `devise_for' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/devise-4.7.1/lib/devise/rails/routes.rb:500:in `raise_no_secret_key': Devise.secret_key was not set. Please add the following to your Devise initializer: (RuntimeError) config.secret_key = '65a95ec21686dc552d1312XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'4)
Devise.secret_key was not set.
に注目して
config/initializers/devise.rb
のコメントアウトを外すBefor
# config.secret_key = '7f2977830281c6192ccdb7XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX’
After
config.secret_key = '7f2977830281c6192ccdb7XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX’5)まだエラー
=> Booting Puma => Rails 5.0.7.2 application starting in development on http://localhost:3000 => Run `rails server -h` for more startup options => Booting Puma => Rails 5.0.7.2 application starting in development on http://localhost:3000 => Run `rails server -h` for more startup options Puma starting in single mode... * Version 3.12.6 (ruby 2.5.1-p57), codename: Llamas in Pajamas * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://localhost:3000 Use Ctrl-C to stop DEPRECATION WARNING: You didn't set `secret_key_base`. Read the upgrade documentation to learn more about this new config option. (called from env_config at /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/application.rb:246) 2020-07-10 22:34:13 +0900: Rack app error handling request { GET / } #<RuntimeError: Missing `secret_key_base` for 'development' environment, set this value in `config/secrets.yml`>6)
1)
のfog-aws-3.6.4
に注目して以下のサイトを確認
https://github.com/fog/fog-aws手順に沿って設定
Add this line to your application's Gemfile:
gem 'fog-aws'
And then execute:
$ bundle
Or install it yourself as:
$ gem install fog-aws7)念のため再度
bundle install
してからrails s
localhost:3000/
にアクセスすると正しいview
ではなく以下の表示がされるPuma caught this error: Missing `secret_key_base` for 'development' environment, set this value in `config/secrets.yml` (RuntimeError) /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/application.rb:513:in `validate_secret_key_config!' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/application.rb:246:in `env_config' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/engine.rb:693:in `build_request' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/application.rb:521:in `build_request' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/railties-5.0.7.2/lib/rails/engine.rb:521:in `call' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/puma-3.12.6/lib/puma/configuration.rb:227:in `call' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/puma-3.12.6/lib/puma/server.rb:706:in `handle_request' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/puma-3.12.6/lib/puma/server.rb:476:in `process_client' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/puma-3.12.6/lib/puma/server.rb:334:in `block in run' /Users/ユーザー名/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/puma-3.12.6/lib/puma/thread_pool.rb:135:in `block in spawn_thread'8)先頭の
secrets.yml
に注目config/secrets.ymlが存在していない
9)
config/secrets.yml
を作成10)
secret_key_base
を生成11)
rails s
が成功。localhost:3000/
も表示される参考記事
rails s が失敗して`raise_no_secret_key': Devise.secret_key was not setと言われました。
Rails で Missing 'secret_key_base' 真っ白な画面
rails s が失敗してERROR RuntimeError: Missing secret_key_base と言われました。
- 投稿日:2020-07-11T00:25:18+09:00
[Rails] Devise でgem' html2slim'を使用した際のエラーについて
Deviseを使用した際,「$rails g devise:views」を実行後、
$ bundle exec erb2slim app/views/devise -d
を実行した。その後、「localhost:3000/users/sign_up」に飛んだ際にエラー発生。
app/views/devise/shared/_error_messages.html.slim- if resource.errors.any? #error_explanation h2 = I18n.t("errors.messages.not_saved", - count: resource.errors.count, - resource: resource.class.model_name.human.downcaseよく見ると slim の構文が間違っている。
「-
」は埋め込みrubyを記述する際に使用するので、構文がおかしい。
よって、「-
」を消去することでエラーが回避された。感想
エラー内容は単純なものでしたが、自動でファイルの中身を
修正してくれるgemは完璧ではないという事を学べました。
- 投稿日:2020-07-11T00:00:05+09:00
【Rails/Docker/mysql】ホストPC直下で開発していたWEBアプリをコンテナで動かしてみたぉ
はじめに
Udemyの動画でDockerを学んだ後、ローカルホストで開発していたアプリケーションをコンテナで動かしてみました。
以下を参考にしながら、まずはdocker-composeを使わずにやってみました。
参考
udemy 米国AI開発者がゼロから教えるDocker講座
https://hub.docker.com/_/rails
https://qiita.com/tatsuya-miyamoto/items/08bd6ea142d02708614f
https://qiita.com/y-suna/items/e52b3af1d80c52b66b31
https://qiita.com/Masato338/items/f162394fbc37fc490dfb実行環境
アプリケーションサーバ(コンテナ直下): puma4.3.3 (rails5.2.4.1 / ruby 2.5.1)
Database(ホスト直下): MySQL 5.6.47
コンテナ(ホスト直下): docker 19.03.8
ホスト: macOS Catalina 10.15.5実施手順
既存アプリケーションを壊さないよう、対象となるアプリケーションのフォルダをコピーして実行しました。
$ cp -r ~/project/memo-space ~/project/memo-space_v2~/project/memo-space -> ~/project/memo-space_v2
Dockerfileを作成する。
DockerfileFROM ruby:2.5.1 RUN apt-get update RUN apt-get install -y mysql-client nodejs vim --no-install-recommends RUN rm -rf /var/lib/apt/lists/* RUN mkdir /myproject WORKDIR /myproject ADD Gemfile /myproject/Gemfile ADD Gemfile.lock /myproject/Gemfile.lock RUN gem install bundler ADD . /myprojectDockerfileに基づきビルド
terminal$ cd ~/projects/memo-space_v2 $ docker build .docker image を確認します。
terminaldocker images REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> df22a2c4c7f7 56 minutes ago 1.07GB ...dockerを実行します。
この時、ホストのrails pumaのポート3000番とmysqlのポート3306番にコンテナのポートを紐づけます。
また、ホストのアプリケーションフォルダ「~/projects/memo-space_v2」にコンテナのフォルダ「/myproject」をマウントします。terminal$ docker run -it -p 3000:3000 -p 3306:3306 -v ~/projects/memo-space_v2:/myproject df22a2c4c7f7 bashファイル「Gemfile.lock」を削除します。
terminal$ rm Gemfile.lockbundle installを実行し、必要なGemをインストールします。
terminal$ bundle installdatabase.ymlに記載された既存のアプリの定義を次の通り修正します。
修正箇所
・mysqlのhost(追記)
・アプリケーション名(修正)config/database.yml# MySQL. Versions 5.0 and up are supported. # # Install the MySQL driver # gem install mysql2 # # Ensure the MySQL gem is defined in your Gemfile # gem 'mysql2' # # And be sure to use new-style password hashing: # http://dev.mysql.com/doc/refman/5.7/en/old-client.html # default: &default adapter: mysql2 encoding: utf8 pool: 5 username: root password: socket: /tmp/mysql.sock development: <<: *default database: memo-space_v2_development #修正 host: docker.for.mac.localhost #追記 # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: <<: *default database: memo-space_v2_test #修正 # As with config/secrets.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is # ever seen by anyone, they now have access to your database. # # Instead, provide the password as a unix environment variable when you boot # the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database # for a full rundown on how to provide these environment variables in a # production deployment. # # On Heroku and other platform providers, you may have a full connection URL # available as an environment variable. For example: # # DATABASE_URL="mysql2://myuser:mypass@localhost/somedatabase" # # You can use this database configuration with: # # production: # url: <%= ENV['DATABASE_URL'] %> # production: <<: *default database: memo-space_v2_production #修正 adapter: postgresql # database: postgresql encording: unicorde pool: 5 username: memo-space url: <%= ENV['DATABASE_URL'] %> password: <%= ENV['MEMO-SPACE_DATABASE_PASSWORD'] %>※既存アプリでは、元々production環境として、heroku上のpostgresqlを利用しており上記の記載となっていますが、未修正です。
※コンテナからホストPCへのアクセスは、次の通り指定することで実行できました。
terminalmysql --host=docker.for.mac.localhost -u root
dbをcreateします。
terminalrails db:create
dbをmigrateします。
terminalrails db:migrate
コンテナの全てのインタフェースにバインディングすることで、ホストPCからアクセスできるようにします。
terminalrails s -p 3000 -b '0.0.0.0'
以上により、ホストPCからブラウザでURL「localhost:3000」を指定し、アプリにアクセスできました。