20211128のRubyに関する記事は13件です。

FactoryBot のまとめ

FactoryBot とは factory_bot_rails といった gem を導入することで使える。 → model のデータに紐づいたテストデータを簡単に作るためのもの。 spec 配下の factories の中に定義する。 各モデルのファイルを作成して、カラムに基づくデータを Faker を使って定義する。 Faker とは… ダミーデータを作るのに便利な gem のこと。 定義したデータをテストの際などで呼び出すことが可能になる! FactoryBot の定義の仕方 FactoryBot.defineをdo 〜 end の中で定義するような書き方をする。 作成例) FactoryBot.define do factory :article do title { Faker::Lorem.word } body { Faker::Lorem.sentence } end end 上記のような書き方だと、 title カラムでは、Faker::Lorem.wordによってランダムな単語が作成される。 body カラムでは、Faker::Lorem.sentenceによってランダムな文が作成される。 FactoryBot の呼び出し方 定義したFactoryBot を呼び出すためのメソッドが存在する。 【代表的なメソッド】 create メソッド DBに保存する形でレコードを更新するメソッドのこと。 FactoryBot を使ってレコードを作成する。 特徴としては、association も保存する! 例)FactoryBot.create(:user) build メソッド DB保存しない状態でインスタンスを作成するメソッドのこと。 FactoryBot を使って、インスタンスを new する。 特徴としては、association は保存する! 例)FactoryBot.build(:user) build_stubbed メソッド DB保存しない状態でインスタンスを作成するメソッドのこと。 特徴としては、「IDカラムには適当な値が入る」、「association も保存しない」 attributes_for メソッド パラメーターを生成するメソッドのこと。 FactoryBot の定義から、値をハッシュ形式で受け取る。 例)FactoryBot.attributes_for(:user) _list メソッド 生成系のメソッド + _list の記述で、それぞれに対応する同じデータを複数件生成できる。 例)build_list()、build_stubbed_list()、create_list()、attributes_for_list() ( 引用記事:https://qiita.com/morrr/items/f1d3ac46b029ccddd017 ) 重複しないデータを作る テストを実装していく中でvalidationによって重複したデータができては困る場合が出てくる。 そこで出てくるのが sequence である。 FactoryBot には sequence という機能がありsequence を使うことで重複を防ぐことができる!この機能を使うと、FactoryBot の機能を呼び出すたびに、n の数字が1 ずつ増えていく。 つまり、Faker で作ったデータの前に数字がつくので重複しないデータを作ることができる!! (例)sequence(:account) { |n| "#{n}_#{Faker::Internet.username}" } Factoryで関連を扱う association という機能を使うことで関連するダータを作ることができる。 belongs_to の関係を持っているモデルの Factory では、 association という機能を使うことで関連するデータを自動的に作成できるようになる! 書き方の例)association :user, factory: :user ※ association には省略形もあり、上記の例の場合だとuserだけで足りる! trait という機能を使うことで、Factory の場合わけをすることができる! 関連するモデルを持っている方を単体で呼び出せるようにすることができるということ。 with_ + belongs_toの関係を持つモデルに trait を指定して、そこで association の機能を使う。 書き方の例)user テーブルの Factory に下記の記述を追加。 trait :with_user_detail do # association :user_detail, factory: :user_detail の省略形 user_detail end 上記のコードを記述することで、場合分けができるようになる! 詳細データが必要ないときは、user だけ作成する  → FactoryBot.create(:user) 詳細データも必要なときは、user_detail も一緒に作成する  → FactoryBot.create(:user, :with_user_detail) 引用元 ワンダフルコード・講義資料 https://qiita.com/morrr/items/f1d3ac46b029ccddd017 まとめ FactoryBot はテストの実装でめちゃめちゃ使う gem である。 メソッドの理解が不十分なまま実装していたので、言語化してまとめていくことで理解を深めていくことができたと思う。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【jbuilder】部分テンプレートのオプション

環境 Ruby 3.0.2 Rails 6.1.4.1 部分テンプレート 部分テンプレート内で呼び出し方をasで指定 2つとも同じように取れる app/views/users/index.json.jbuilder json.partial! 'users/user', collection: @users, as: :user #or json.array! @users, partial: 'users/user', as: :user app/views/users/_user.json.jbuilder json.extract! user, :id, :name, :age 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】IN句の書き方

IN句の書き方いろいろ User.where(id: [1, 3, 6]) #=> SELECT `users`.* FROM `users` WHERE `users`.`id` IN ('1', '3', '6') ids = [1, 3, 6] User.where('id IN (?)', ids) #=> SELECT `users`.* FROM `users` WHERE (id IN (1, 3, 6)) User.where('id IN (?)', [1, 3, 6]) #=> SELECT `users`.* FROM `users` WHERE (id IN (1, 3, 6)) User.where('id IN (1, 3, 6)') #=> SELECT `users`.* FROM `users` WHERE (id IN (1, 3, 6))
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】Routingのネスト,member, collectionの違い

はじめに Railsでアプリケーション作成しております。 作成中にルーティングについて少々学習したので、自分用のメモとして残しておきます。 ルーティングについて ルーティングは、受け取ったHTTPリクエストに応じて、特定のコントローラー内のアクションを動作するように割り当てを行なっている。 Railsのルーティングはconfig/routes.rbで設定する。 config/routes.rb Rails.application.routes.draw do # ここにルーティングを設定する root 'home#index' end 設定したルーティングは、以下のコマンドを実行することで確認できます。 ターミナル $ bin/rails routes Prefix Verb URI Pattern Controller#Action root GET / home#index 実装したかったこと(前提) ユーザー(user)が、ある施設(house)に口コミ(review)を投稿する機能を実装します。 施設は複数あり、1つの施設に複数の口コミが投稿されると想定する。 各々の投稿のURLを規則的に振り当てるとすると、https://○○○/house/id/review/idというふうにしたい。 今回の各モデルのアソシエーションは以下のようにしている。 Userの認証モデルについてはdeviseにて実装済みである。 結論 ルーティングをネストするといい! config/routes.rb Rails.application.routes.draw do root 'home#index' devise_for :users # ネストしたルーティング resources :houses do resources :reviews end end ルーティングを確認する際は、-gや-cオプションを用いると見やすくなります。 ターミナル # -g :名前付きルーティングやHTTP動詞、URLパスのいずれかに部分マッチするルーティングのみ表示する $ bin/rails routes -g reviews Prefix Verb URI Pattern Controller#Action house_reviews GET /houses/:house_id/reviews(.:format) reviews#index POST /houses/:house_id/reviews(.:format) reviews#create new_house_review GET /houses/:house_id/reviews/new(.:format) reviews#new edit_house_review GET /houses/:house_id/reviews/:id/edit(.:format) reviews#edit house_review GET /houses/:house_id/reviews/:id(.:format) reviews#show PATCH /houses/:house_id/reviews/:id(.:format) reviews#update PUT /houses/:house_id/reviews/:id(.:format) reviews#update DELETE /houses/:house_id/reviews/:id(.:format) reviews#destroy # -c :特定のコントローラーのルーティングのみ表示する $ bin/rails routes -c reviews Prefix Verb URI Pattern Controller#Action house_reviews GET /houses/:house_id/reviews(.:format) reviews#index POST /houses/:house_id/reviews(.:format) reviews#create new_house_review GET /houses/:house_id/reviews/new(.:format) reviews#new edit_house_review GET /houses/:house_id/reviews/:id/edit(.:format) reviews#edit house_review GET /houses/:house_id/reviews/:id(.:format) reviews#show PATCH /houses/:house_id/reviews/:id(.:format) reviews#update PUT /houses/:house_id/reviews/:id(.:format) reviews#update DELETE /houses/:house_id/reviews/:id(.:format) reviews#destroy memberやcollectionとの違いは? ルーティングにREST以外のアクションを追加したい場合に、memberやcollectionを使用します。 memberやcollectionを使う場合とどのような違いが出るのか、確認してみます。 ①memberを使う場合 config/routes.rb Rails.application.routes.draw do root 'home#index' devise_for :users resources :houses do member do resources :reviews end end end ターミナル $ bin/rails routes -g reviews Prefix Verb URI Pattern Controller#Action reviews GET /houses/:id/reviews(.:format) reviews#index POST /houses/:id/reviews(.:format) reviews#create new_review GET /houses/:id/reviews/new(.:format) reviews#new edit_review GET /houses/:id/reviews/:id/edit(.:format) reviews#edit review GET /houses/:id/reviews/:id(.:format) reviews#show PATCH /houses/:id/reviews/:id(.:format) reviews#update PUT /houses/:id/reviews/:id(.:format) reviews#update DELETE /houses/:id/reviews/:id(.:format) reviews#destroy 一見これでも良さそうだが、houses後の:idとreview後の:idが同じになってしまう。 ②collectionを使う場合 config/routes.rb Rails.application.routes.draw do root 'home#index' devise_for :users resources :houses do collection do resources :reviews end end end ターミナル $ bin/rails routes -g reviews Prefix Verb URI Pattern Controller#Action reviews GET /houses/reviews(.:format) reviews#index POST /houses/reviews(.:format) reviews#create new_review GET /houses/reviews/new(.:format) reviews#new edit_review GET /houses/reviews/:id/edit(.:format) reviews#edit review GET /houses/reviews/:id(.:format) reviews#show PATCH /houses/reviews/:id(.:format) reviews#update PUT /houses/reviews/:id(.:format) reviews#update DELETE /houses/reviews/:id(.:format) reviews#destroy この場合、houses後に:idが付かないURLになってしまう。 以上のことから、今回のケースではネストした方が良いということがわかりました。 コントローラーやビューでの振る舞い ルーティングをネストすれば、houseとreviewのIDを別々に定義できることがわかりました。 それでは、それぞれのidを用いて、DBにデータを保存するにはどうすれば良いのか? 今回はform_withを用いた口コミ作成、編集フォームを例に考えます。 コントローラーでのインスタンスの定義や、ビューでの記述については以下のようにしました。 コントローラーの記述 app/controllers/reviews_controller.rb class ReviewsController < ApplicationController def new @house = House.find(params[:house_id]) @review = current_user.reviews.build end def create @review = current_user.reviews.build(review_create_params) @review.house_id = params[:house_id] if @review.save flash[:success] = "口コミを投稿しました!" redirect_to house_path(@review.house_id) else render 'new' end end def edit @house = House.find(params[:house_id]) @review = Review.find(params[:id]) end def update @review = Review.find(params[:id]) if @review.update(review_update_params) flash[:success] = "口コミを修正しました!" redirect_to root_url else render 'edit' end end private def review_create_params params.require(:review).permit(:content, :user_id) end def review_update_params params.require(:review).permit(:content) end end 口コミは、どの施設に対する口コミなのかということを定義する必要があります。 そのため、@houseを上記のような方法で取得しています。 ビューファイルの記述 app/views/reviews/new.html.slim = form_with model: [@house, @review], local: true do |f| = f.text_field :content, placeholder: "口コミ本文を書いてください(10,000字以内)" = f.submit "口コミを投稿する" app/views/reviews/edit.html.slim = form_with model: [@house, @review], local: true do |f| = f.text_field :content = f.submit '口コミを修正する' ビュー側では、form_withの引数に[@house, @review]のように配列を渡すように記述する必要があります。 以上になります。誤りなどありましたら、ご指摘お願いします。 参考 https://railsguides.jp/routing.html https://pikawaka.com/rails/form_with
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】SQLでor検索

A OR Bの結果が出力される。 User.where(name: 'コナン') .or(User.where(email: 'ran@gmail.com')) #=> SELECT `users`.* FROM `users` WHERE (`users`.`name` = 'コナン' OR `users`.`email` = 'ran@gmail.com') orメソッドがまだなかったときはこんな書き方をよく見かけたらしい。 User.where("name = ? OR email = ?", 'コナン', 'ran@gmail.com') #=> SELECT `users`.* FROM `users` WHERE (name = 'コナン' OR email = 'ran@gmail.com')
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】複数レコード一括保存のRspecの書き方

https://ryucoding.com/programming/rails-form-bulk-create で紹介されている複数レコードを一括保存するcreateアクションをテストするリクエストspecの書き方で詰まったのでその備忘録です。 テスト対象のコントローラーとアクション //questions_controller def create @form = Form::QuestionCollection.new(question_collection_params) if @form.save redirect_to root_url else render 'new' end end . . . . . def question_collection_params params.require(:form_question_collection).permit(questions_attributes: [:content, :mode_num]) end クイズ出題アプリで[question]という出題文を表すモデルを同時に10個作成するためのアクションです。 rspec //questions_request_spec.rb describe "POST /create" do context "空欄なく入力した場合" do it "redirects to root path" do expect{ post questions_path, params: {form_question_collection: {questions_attributes:  {0=> {content: "test question1", mode_num:1}, 1 =>{content: "test question2", mode_num:1}, 2 =>{content: "test question3", mode_num:1}, 3 =>{content: "test question4", mode_num:1}, 4 =>{content: "test question5", mode_num:1}, 5 =>{content: "test question6", mode_num:1}, 6 =>{content: "test question7", mode_num:1}, 7 =>{content: "test question8", mode_num:1}, 8 =>{content: "test question9", mode_num:1}, 9 =>{content: "test question10", mode_num:1}}}} }.to change(Question, :count).by (10) expect(response).to redirect_to root_path end end [content]と[mode_num]はカラム名です。保存に成功し際はroot_pathにリダイレクトすることをテストするためのコードです。 上記の書き方で同時に10個のレコードをcreateするアクションのリクエストspecを実現できました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】左外部結合と内部結合

環境 Ruby 3.0.2 Rails 6.1.4.1 前提条件 class Owner < ActiveRecord::Base has_many :dogs end class Dog < ActiveRecord::Base belongs_to :owner end 左外部結合 左側のテーブルにしかないレコードも取得して結合する。 下の例でいうと、飼犬がいないオーナーのデータも取得できる。 Owner.left_joins(:dogs) => SELECT `owners`.* FROM `owners` LEFT OUTER JOIN `dogs` ON `dogs`.`owner_id` = `owners`.`id` 内部結合 結合条件に一致するレコードのみを結合する。 下の例でいうと、飼犬がいるオーナーのデータのみ取得できる。 Owner.joins(:dogs) => SELECT `owners`.* FROM `owners` INNER JOIN `dogs` ON `dogs`.`owner_id` = `owners`.`id` 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

勝手に「点字メーカープログラム」を作ってみる

はじめに これは、2021年の Ruby アドベントカレンダー2の3日目の記事です。 先日「挑戦者求む!Rubyで点字メーカープログラムを作ってみよう 〜Qiita Advent Calendar 2021〜」という記事を見つけました。 これは面白そうな題材です。10人いれば100通りの実装が出てくるのが ruby の醍醐味。是非とも、いろいろな方が書いたコードを見比べてみたい、自分の作ったコードとも比較してみたい。 なので、さっそく参加しようと思ったものの、その時点で既にすべての枠が埋まっていたのでした。仕方がないので、こうして勝手にRuby アドベントカレンダーに投稿しています。 (Ruby アドベントカレンダー1の2日目にも、同じような方がいる模様です) なお、出来上がったコードとテストの実行結果は、この記事の末尾に掲載しています。 前提条件 レギュレーションは基本的に、元記事の指定内容に沿ったものにしています。 元記事には評価のポイントについても記載されていますが、あまり気にせず、自分が普段 ruby で書いているやり方で実装してみました。 ロジックの説明 点字の仕様を読んで、点字が6個のドットのパターンで構成されていること、母音と子音の組み合わせで合成できそうな規則性があること、といった辺りを大まかに把握してから、作り始めました。 クラスは、点字文字列を扱うTenjiStringと、点字のドットパターンを組み立てるファクトリTenjiString::DotPatternの2つです。 最近の傾向に沿って、点字1文字を扱うクラスは用意していません。 ドットパターンの組み立て クラスTenjiString::DotPatternの責務は、点字のドットパターンの組み立てで、ローマ字の1語を与えると、対応する点字のドットパターンが得られます。 ドットパターンは、内部では6ビットの2進数として扱っています。 2進数とドットパターンの配置との対応関係は、次の通りとしました。 MSB LSB b5 b4 b3 b2 b1 b0 b5 b4 b3 b2 b1 b0 この対応関係は、表示の際の利便性により、点字の仕様を記載している「全視情協:点字とは - 点字のしくみ」でのドット番号とは異なっています。 ローマ字の1語は、まず文字数が1個か2個か、で場合分けをします。 1個の場合、母音または撥音("ん")ですので、対応するドットパターンを返します。 2個の場合、「子音+母音」の組合せなので、1文字目を子音、2文字目を母音として、それぞれ対応するドットパターンを合成しています。 や行とわ行の場合、可能な母音の種類とドットパターンが通常とは異なるので、これも場合分けしています。 点字文字列の表示 クラスTenjiStringは、文字列クラスとして点字を扱うものですが、現在は表示用にドットパターンを出力することが、主な責務です。 入力としてローマ字の文字列を与えると、空白で分割して、ローマ字1語単位で配列に変換し、TenjiString::DotPatternを使ってドットパターンを取得したのち、画面出力用に変換します。 点字は、表示が3行に渡るので、各行の出力内容を作成してから、結合しています。 各行の出力内容は、ドットパターンを6桁2進数の文字列へ変換して、2文字づつ3個に分割したものを、それぞれ使っています。 前述の、ドットパターンと2進数との配置の対応関係は、ここの処理が書きやすいように決めました。 実装の解説 完全コンストラクタと不変オブジェクト インスタンス変数は、#initializeだけで設定し、attr_readerによる参照のみ、行っています。 これにより、#initialize以外の個所でインスタンス変数が出てこない(つまりアットマークが出てこない)表面的なチェックだけで、インスタンスオブジェクトの不変性が担保できます。 なお、不変なオブジェクトを構築しやすくするため、インスタンス作成にはクラスメソッド#createを使用しています。 関数型プログラミング 厳密な意味での関数型プログラミングではなく、ある程度、寄せている感じです。 まず、繰返しや条件分岐のような、いわゆる制御構造が一切でてきません。今回は加えて三項演算子すら使っていませんが、別に縛りをかけている訳ではなく、普段は三項演算子も後置if式も使っています。 ローカル変数もほとんど出てきません。唯一の使用箇所はTenjiString#row_dotsで、ラムダの説明変数としてformatterがあるだけです。 これも縛りをかけているというよりも、結果的にローカル変数を使う必要が無くなった為です。その代わり、短いメソッドが多数できています。 また、外部との界面になっているメソッドを除くと、メソッドに引数が付いている箇所もほとんどありません。今回は、ブロック内から呼ばれているTenjiString#row_dotsのみです。 わかりにくい箇所 以下は、case に相当する処理を、ハッシュとメソッドの動的呼び出しの組合せで実現しています。やりすぎだと思う方も多いでしょう。自分でも、そう思います。普段は三項演算子で事足りるケースが殆どなので、多用はしていません。 def two_letter_word method(two_letter_word_table).call end def two_letter_word_table { y: :composition_with_shift, w: :composition_wa, }.fetch(first_char, :standard_composition) end 以下は、文字数(1または2)と配列の添え字(0から始まる)を揃えるため、配列の先頭に1個、要素を挿入しています。 文字数から 1 を引いて配列の添え字にする方法では、文字数が0の場合に添え字が -1 となって期待通りに動きません。 def construct_pattern method(construct_method).call end def construct_method construct_method_table.prepend(nil).fetch(word.length) end def construct_method_table [ :one_letter_word, :two_letter_word, ] end 異常系の対応 異常な入力の場合は何らかの例外が上るように実装しています。 レギュレーションでは「入力の異常系については考慮不要」となっていますので、どのエラーで何の例外が上るか、上がった例外をどう処理するか、には対応していません。 エラーチェック用のコードは特に追加していませんが、例えば、異常な文字が入った場合はHash#fetchで例外が上り、1語の文字数がおかしい場合はmethod(nil).callで例外が上る、といった様に、既存のメソッドが持つ例外対応を利用しています。 拡張性 レギュレーションに沿って、要求されている範囲は実装していますが、同時に、要求されていない範囲は実装していません。 今後、例えば対応するローマ字の種類を増やす場合、「を」や促音、長音については、TenjiString::DotPatternにて文字数1個への追加で容易に対応可能です。 濁音や拗音への追加対応の場合、点字が2マス使用するので、まずTenjiString側でローマ字での文字列変換処理を新規追加した後、ドットパターンを追加したTenjiString::DotPatternへ渡す流れを考えています(詳細は検証していません) どちらのケースでも、既存のコードの変更箇所は最小限で済むはずです。 心残りなところ わ行の対応 点字には、かなりの規則性があるのですが、それでも扱いを分ける必要が出てきます。 わ行の扱いを「独立した特別扱い」にするか「や行と同じ扱い」にするか、2通りのアプローチが考えられますが、今回は後者で実装しています。 ただ、実際に書いてみて、や行と同じ扱いにするメリットが少なかったので、どちらで作っても大差なかったと感じています。 ドットパターンの表示 ドットパターンの表示処理を、どこのクラスに持たせるか、で悩みました。 同じドットパターンに関連する処理ではあるものの、クラスTenjiString::DotPatternに入れるのは、違うと思います。 点字の表示や出力に責務を負う、新たなクラスを作って、そこで行うのが適切だった気がしています。 今後、クラスTenjiStringがクラスString並みに機能を充実していくことがあるなら、その際に見直しを行うことになるでしょう。 なお、TenjiString#print_in_dotsというメソッド名は、もう少しいい感じの名前にしたかったです。 結果 出来上がったコード lib/tenji_maker.rb class TenjiMaker def to_tenji(text) TenjiString.create(text).print_in_dots end end class TenjiString def self.create(words) new(words).create end def initialize(words, tenji_string = nil) @words = words @tenji_string = tenji_string end def create self.class.new(words, build) end def print_in_dots (0..2).map {|line| row_dots(line) } .join("\n").tr('10', 'o-') end private attr_reader :words, :tenji_string def parse words.downcase.split(' ') end def build parse.map {|word| DotPattern.create(word) } end def row_dots(line) formatter = ->(dots) { ('%06b' % dots).scan(/../)[line] } dot_pattern.map(&formatter).join(' ') end def dot_pattern tenji_string.map(&:dot_pattern) end end class TenjiString::DotPattern def self.create(word) new(word).create end def initialize(word, dot_pattern = nil) @word = word @dot_pattern = dot_pattern end def create self.class.new(word, construct_pattern) end attr_reader :dot_pattern private attr_reader :word def construct_pattern method(construct_method).call end def construct_method construct_method_table.prepend(nil).fetch(word.length) end def construct_method_table [ :one_letter_word, :two_letter_word, ] end def one_letter_word vowel.merge(repellency).fetch(first_char) end def two_letter_word method(two_letter_word_table).call end def two_letter_word_table { y: :composition_with_shift, w: :composition_wa, }.fetch(first_char, :standard_composition) end def standard_composition consonant.fetch(first_char) | vowel.fetch(second_char) end def composition_with_shift consonant_with_shift.fetch(first_char) | shifted_vowel.fetch(second_char) end def composition_wa consonant_with_shift.fetch(first_char) | shifted_vowel_wa.fetch(second_char) end def first_char word[0].to_sym end def second_char word[1].to_sym end # 母音 def vowel { a: 0b0_10_00_00, i: 0b0_10_10_00, u: 0b0_11_00_00, e: 0b0_11_10_00, o: 0b0_01_10_00, } end # 子音 def consonant { k: 0b0_00_00_01, s: 0b0_00_01_01, t: 0b0_00_01_10, n: 0b0_00_00_10, h: 0b0_00_00_11, m: 0b0_00_01_11, r: 0b0_00_01_00, } end # 子音(母音が一番下へ移動する) def consonant_with_shift { y: 0b0_01_00_00, w: 0b0_00_00_00, } end # 母音(一番下へ移動した) def shifted_vowel { a: 0b0_00_00_10, u: 0b0_00_00_11, o: 0b0_00_01_10, } end # 母音(わ行専用) def shifted_vowel_wa { a: 0b0_00_00_10, o: 0b0_00_01_10, } end # 撥音("ん") def repellency { n: 0b0_00_01_11, } end end テストの実行結果
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

「Ruby」where文で同じカラムで複数指定する方法

where文で配列を同じカラムで複数指定する方法 変更前 @q = Tweet.where(completed: "0") 変更後 @q = where(completed: ['0', '1']) このように配列にすれば指定できる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【しくじり先生】失敗続きのエンジニア転職1年間を振り返って最短で満足のいく転職をするにはどうすれば良いかを考えてみた

はじめに こんにちは、28歳未経験から12月より150名規模の自社開発企業で働くことになったもきおです。エンジニア転職を目指し2020年10月に前職を辞め、早1年も経ってしまいました。 仕事をしていながらなら分かるが学習にコミットして流石に一年は長かった。 1年間色々と細かい失敗を繰り返し続けました。でも失敗ばかりだったから伝えられることも多くあると思うんです。そこで今回は今までの流れを振り返りつつ、失敗から何を学びどのようにすればもっと早く満足のいくエンジニア転職ができるかを考えてみました。 書きたいことが多く結構なボリュームになってしまいましたが最後までご覧いただけますと幸いです。 こんな人に読んで欲しい ・プログラミングスクールからエンジニア転職を目指している方 ・独学からエンジニア転職を目指している方 ・エンジニア転職活動をしている方 ・これからプログラミングを学んでエンジニア転職を考えている方 今までの流れ まず初めに「おいもきお、一年も何やってたんだよ」と声が聞こえてきそうなので今までの流れをざっと表で振り返っていきます。 期間 やったこと 2020年10~12月 Progateで基礎固め、DMMWEBCAMP事前学習 2020年12月~3月 DMMWEBCAMP受講 2020年4月~6月 1回目のエンジニア転職活動 2020年7月 フリーランス案件準備、案件結局もらえず 2020年8~10月 実務が積めるエンジニアスクール 2020年10~11月 エンジニア転職活動2回目 実はエンジニア転職活動は2回しています。1回目と2回目は何が違ったのかなどもお伝えできればなと思います。 エンジニアになりたいと思ったら最初にやるべき行動 振り返っていく前に余談を挟みます。 皆さんがエンジニアになりたいと思ったらまず何をするでしょうか? まぁ間違いなくプログラミング学習ですよね。そしてプログラミングスクールに通うか、独学で勉強して転職活動していくかって感じになると思います。 しかしエンジニア系YouTuberのしまぶーさんも仰ってましたが最初にやるべき行動はいきたい企業を探すことです。 いきたい企業を探す→行きたい企業の必要な言語、技術がわかる→必要な言語、技術に対して学習開始→ポートフォリオ作成 この流れが最も明確に学習を進められると思います。 ここでいきたい企業が明確に決まれば問題ないですが最初からそこまで明確には決められないのでスタートアップ系とか大枠の事業内容とかとにかく一旦色んな企業を学習する前、初期段階から見てみるのが良いかなと思います。 また、現役エンジニアの方に積極的にコミュニケーションをとってエンジニア業界の話をまずは聞いてみるのが良いかと思います。現在はTwitter、色んなエンジニアコミュニティなど様々な現役エンジニアの方へのアプローチがあると思います。 2020年10~12月 Progate、DMMWEBCAMP事前学習 そんなこんな言ってますが当時の自分は「プログラミングスクール通ってポートフォリオ作ってエンジニア転職活動すれば転職できるっしょ」くらいに思ってました。 そこで特に仕事を継続して学習しようとはせずプログラミング学習に打ち込むため仕事を辞めることを決意しました。まあ今思えばですけどこの選択は間違ってはなかったとは思います。 さて話を戻して会社を辞めてプログラミング学習を始めたわけですがDMMWEBCAMPはかなり人気で10月から入校したかったのに12月になってしまいました。 なぜDMMWEBCAMPというスクールを選んだのか、実際受講してみてどうだったかはまた別の記事でお伝えしていきたいと思います。 なので最初の2ヶ月はProgateと入校1ヶ月前からDMMWEBCAMPのカリキュラムが配布されるので事前学習をしていました。 事前学習のメリットは振り返ると以下2点 ・本受講で余裕が生まれモチベーション高く学習を進められる ・期限に縛られないで受講できるので理解をしっかりと深め学習できる 当時は今と比べると全然学習時間が取れていませんでしたね。平均3、4時間。多くても6時間くらい。それでも事前学習をできていたのは振り返ってもかなり良かったと思います。 下記Twitterで投票もしてもらいましたが大半が事前学習をするべきを回答していただいていました。どの程度まで事前学習した方がいいのかはこのリンクのスレッドとかで議論されているので良かったらみてください YouTubeのコメントにて「DMMWEBCAMPの事前学習をする必要があると思ってるのはあなただけなんじゃないの」とコメントいただいたので初めて投票機能使ってみたいとおもいます。結果をコメントしていただいた方にご返信するので受講された方はご協力いただけますと幸いです。— もきお (@mokio_50) November 21, 2021 この期間で感じたこと ・事前学習は大事 ・事前学習から危機感を持って学習する 2020年12月~3月DMMWEBCAMP受講 実際の内容とかは後日また記事にしようと思うので省きますが当時の自分を客観的に他受講生と見比べると技術レベルは中の中、あるいは中の下って感じだった気がします。特に後半は結構失速しました笑 受講当時、自分は「学習は量より質でしょ」って思ってたし、「12時間学習しました!」みたいなツイートを見ても「あーそうなんだ」くらいな感じで思ってたしなんなら少ない時間でこれだけ進んでる自分をかっこいいとさえ思ってました(ちょっと誇張してはいるが今考えると普通にキモい)。 そんなこんなで学習時間確保の大切さをわかっていませんでした。よって大体一日6~7時間くらいしか学習していませんでした。今振り返ると圧倒的に絶対的な学習の確保は必要だったなとつくづく思っております。 なぜ絶対的な学習時間の確保が必要であると感じるようになったのか。 それは学習のモチベーション維持にあると思っております。 プログラミング学習はちゃんと継続できる人が、学習する人の1割程度と言われているように様々なところで挫折しそうになるのでモチベーション維持が非常に大切だと感じています。 モチベーション維持のためには小さな成功体験を積み重ねることが大切だと思います。なので質を重視してしまうと、実際思うように学習が進まないときに、モチベーション低下につながります。 一方で量にこだわり学習時間をちゃんと確保していけば学習時間を確保できたことが小さな成功体験になっていくのでモチベーションを維持しやすいのかなと今は感じています。その小さな成功体験によって段々と質の方も自然と良くなっていったなと振り返って見て感じました。 振り返ってみてプログラミングスクールで重要なのは常に危機感を持つことだと思います。 これは井の中の蛙でもないのですが、同期の受講生の中で一番学習した!同期の中で一番技術力がついた!くらい思えるくらい学習しないと満足のいく転職先にいけない可能性は高いです。 これから受講される方はそれくらい高いモチベーションで受講されるのをオススメします。 実際はそんなこともないのですが、要はそれくらいの気持ちで向上心高く貪欲に学習をすると良い方向に進んでいけると思いました。 この期間の失敗から学んだこと ・「質より量」を重視して学習する ・余裕を持つことは大事だが、余裕をぶっこいてると痛い目見るのでどんどん余裕を持って学習できるよう学習を進めていく。 2020年4月~6月 1回目のエンジニア転職活動 さて、プログラミングスクールもなんとか卒業しポートフォリオも一応作成できたので就職活動に移りました。 まず当時の自分のスペックを表にしてみました。客観的にみて10段階評価もつけてみました。 項目 どのくらいやったか 客観的な評価 職務経歴書 ある程度添削してもらい3回くらい修正 7 企業研究 受ける企業を直前に2時間程度 3 面接対策 受ける企業頻出質問5個ぐらい回答を用意 3 ポートフォリオ 一応完成、オリジナリティはある。エラーとかは多発 4 GitHub草 一応毎日生やしてはいた1コミットくらいしかしてない 4 Qiita記事 1記事もかけていなかった 0 この期間の活動を転職活動と学習に分けて振り返っていきたいと思います。 転職活動について 当時はDMMWEBCAMPさんの紹介に任せっきりで自発的に転職活動できていなかったのが一番の失敗した要因だったかなとは振り返ってみて思いました。 エントリー、選考状況は以下でした。 項目 件数 エントリー数 39社 書類選考通過数 11社 一次面接社数 10社 最終面接社数 2社 内定数 1社 内定は一社いただき後に開発経験もしっかり積めそうでしたが、これが本当に自分のやりたかったことなのかと思うと違うと思い辞退しました。 まず転職活動で大事にしたいのは受け身で転職活動をしないこと。 受け身で就活すると特にいきたくない企業ばかり受けることになり、モチベーションも下がるし面接時に志望動機がどうしても弱くなってしまうので企業へ熱意が伝わりづらくなってしまいます。 スクールの紹介は転職活動でのツール(手段)の一つにすぎないという気持ちで転職活動をした方がよっぽど成功する気がしています。これはスクールの紹介企業がダメだとかは全く言っておらず、スクール頼りにならないことが結果的にスクールの紹介で良い企業に内定をもらえたりするからです。 実際現在DMMWEBCAMP生限定のコミュニティであるShuffleというコミュニティに参加させていただいていますが、大半の人が満足のいく企業にスクールの紹介で入社されている印象です。 でもこの方々の多くはWantedlyとかで自ら動いて企業を探してエントリーしつつ、結果的にスクールの紹介企業で内定承諾した人達が多かったです。 よくスクールの紹介以外で転職活動をすると転職保証がなくなりますみたいな感じの制度を持っているスクールが多いですが、これはマジで無視しましょう笑 転職保証に関してはあってないようなものだと思っているくらいがちょうどいいと思います。 大きな決断をしなければいけない転職活動でそういった制度に縛られて視野を狭めるのはやめましょう。正直ここに関してスクール運営をしている企業の方々には申し訳ない発言をしているとは思いますが、本気で満足する企業に就職するにはお伝えしなければいけないと思い、伝えさせていただいております。 学習について プログラミングスクールを卒業してからはJavaと基本情報技術者試験の勉強を進めていました。 振り返ってみるとこれは間違いなく失敗だったと思います笑 内定をいただいた企業で役員との最終面接の際に「やはり目に見えるアウトプットがないと学習の興味度が感じられない。Javaを勉強するのは良いが簡単なポートフォリオを作ってくるくらいじゃないと評価できない。むしろ今まで学習してきたRailsでもう一個自分の興味のある分野でポートフォリオを作るとかの方が俺は好きだなー」っておっしゃってました。この企業はJavaをメインで扱っていて、それでもそうおっしゃるということはやはり成果物がなくただ学習するだけだと評価対象には全くならないんだなと感じました。 なのでJavaやPHPなどRubyは求人数が少ないからみたいな感じで他の言語に手を出して安易に学習するのは間違いなく辞めた方が良いです。 実際その言語でないとできないものを作りたい(Rubyじゃ作れないスマートフォンアプリを作りたい)等具体的なアウトプットや明確にいきたい企業が学習した言語と違うみたいな感じであれば別ですが。 あと2回目の転職活動の方でも書きますが企業が使っている言語を学習していなくても採用される可能性は全然あります。要は何か一つの言語を極めていくこと。これが企業評価として大事なんだなと振り返って思いました。 あと資格は重要なのかについてはそんなにガチで取りに行く必要はないかなと思います。 資格を持っていてもそこまで評価は変わらない。優先順位としては低い感じですかね。 ただコンピューターサイエンスを学ぶ面では良かったと思うので参考書を買ってちょくちょく読んでいると面接の技術質問対策にはなるかなと思いました。 ここまで学習の失敗をダラダラ書いてきましたが転職活動と並行して追加で何を勉強したら企業に評価されるかというとLinux、SQL、 Git、AWSなどのインフラへの理解等、どんなサーバーサイド言語でを使用したとしても汎用性の高いのものを学習するのが良いのかなと思いました。 実際企業に入っても(まだ入社してないけど笑)学習が無駄にならないし、技術質問でも「Linuxコマンドはどんなの使ってましたか?」とかSQL知識を問われたりとか、Gitの使用経験とかも聞かれたので学んでおいて損はないと思います。 あとは作成したポートフォリオのブラッシュアップですかね。テストコード書いたり、エラー修正したり、非同期通信増やしたり。ここら辺はどんな機能を追加したから良いとかではなく、改善する姿勢を見せていくことが重要だと思います。 最後にこのフェーズで言いたいと思ったのは学習習慣を途切れさせないこと。 これはマジで重要だと思います。就活はメインでやっていくのですが1日30分でも良いので必ず1日の何処かで学習するようにした方が良いです。学習週間が途切れていると就活入ってから学習していないなと面接官にすぐバレます。 学習習慣はマジで脆いです。二、三日学習しないだけでも、もろに崩れていきます。 そして学習が30分しかできなかったと思うのではなく、30分学習できたと自分を褒めてあげてください。これが転職活動が始まった後も学習習慣を途切れさせない秘訣だと自分は思います。 この期間の失敗から学んだこと 転職活動 ・自発的に企業を探していく意識を持つ ・転職保証制度に縛られない ・色んな求人媒体を使用して広い視野を持って企業を探す 学習 ・安易に他の学習をしない ・追加で学ぶなら汎用性の高いものを学習 ・一日30分でも良いから学習の継続週間を途切れさせないようにする ・ちょっとでも学習できた自分を褒めてあげる ・ポートフォリオのブラッシュアップをコンスタントにやる 2020年7月 フリーランス案件準備、案件結局もらえず さて、最終的に内定を辞退して何を思ったのかというと「やはり実務経験を積まないと満足いく企業に就職できないんじゃね?」って思いました。実際そんなことないのにね笑 ただ後に記載しますが短い期間でも実務経験を積めるに越したことはないのも事実です。 そこでフリーランスエンジニアの方に相談し、他のエンジニアの方と一緒に同じ案件に参画できる可能性があるとお伝えされました。1人でやるならまず厳しいけど、他のエンジニアの方と一緒に参画できるならアリかもしれないと思い参画を希望しました。 ただ現実はそんなに甘くはなかった。結果的に未経験だったからか企業に推薦して参画できるかもってなってもその後企業から返信が来なかったりして結局案件に参加することができませんでした。 その期間にLaravelを使用した案件に参画する可能性が高いからLaravelをかじったり、基本その方の案件で多いのはPythonのDjangoだったのでそれをかじったりと学習は瞑想していました。 改めて一つの言語に絞って極めていく重要性を感じた時でもありました。 ここら辺の学習はマジで無駄だったなと思います笑 でもそういった視野を広げてフリーランス業界を知れたのは良かったと思います。 今ではフリーランスの実際の現場とかの話を聞いたからか全くと言っていいほどフリーランスになりたいとは思わないけど笑 この期間で学んだこと ・広く浅く学んでも市場価値は全く変わらない ・フリーランス事情、大変さ ・未経験からフリーランスはほぼ間違いなくやめた方が良い 2020年8~10月 実務が積めるエンジニアスクール入校 学習は瞑想する一方だし、フリーランスエンジニアの方に頼る一方じゃなくて自分でも動かないといけないなと思っていた矢先のこと、YouTubeでちょくちょく拝見させていただいた山浦清人さん @kiyotoyamauraが8月より始まる「実務が詰めるエンジニアスクール」を募集しているではありませんか!! これは応募しない手はない!と思い応募し、無事応募選考を通り入校させていただきました。 このスクールは自分の時は1ヶ月半実務期間、残りは就職活動サポート期間って感じでした。 実際実務をやって思ったのは想像の何倍も大変だったということ。しかも山浦さんにアドバイスをもらいつつもそれくらい大変だったので、1人で実務案件をこなすのはどれだけ大変なんだろうと考えるだけでも嫌になったのを覚えています。笑 でも曲がりなりにも実務案件をやり切れたのは自分の中の経験として非常に大きかったし、面接でもこれだけやったから自信を持って実務案件について説明することができました。 そして実務案件と同じくらいすごく良い経験になったのはその後の就職活動サポートです。 現役エンジニアでもあり、採用担当もされていた山浦さんの提出書類、Wantedlyプロフィール添削、面接対策は本当に参考になったし模擬面接を録画して何度も見返すことでかなり面接力みたいなのがかなりついたと思います。 2020年10~11月 エンジニア転職活動2回目 さて、いよいよ2回目の転職活動が始まりました。また別記事に詳しい就活戦略とかは書いていこうと思うので今回はある程度の概要だけ書こうと思います。 また一回目と同じようにスペックを以下に記載していきます。 項目 どのくらいやったか 客観的な評価 職務経歴書 土台をさらに添削してもらい3回くらい修正 9 企業研究 企業ブログ、コーポレートサイトを網羅的に 10 面接対策 頻出質問網羅的に、録画してひたすら見返す 8 ポートフォリオ ちょくちょく修正はしていた 5 GitHub草 ちゃんと生やしていた。平均5、6コミットくらい 7 Qiita記事 15記事書いた 8 エントリー、選考状況は以下でした。 項目 件数 エントリー数 79社 書類選考通過数 30社 一次面接社数 11社 最終面接社数 5社 内定数 4社 最初は最悪開発経験がある程度早い段階でしっかり積める企業であればいいかな程度に思っていましたが、終わってみれば想像の数倍上手くいったなと感じております。もちろん実務が詰めるスクールでの就活対策も非常に役に立ちましたが、DMMWEBCAMPでの職務経歴書の土台作りがあったからこそスムーズに言ったとつくづく感じました。 学習していない言語を使う企業も内定をいただけました。聞いてみたらやはり未経験の学習なんてたかが知れているので特に学習してきた言語はそこまで見ていないとのこと。それよりも何を考え学習してきたかという学習のプロセスが大事だと企業の人に言われました。 評価されたポイント 内定をいただけた企業、落ちた企業にフィードバックをひたすら求め評価していただいた点を羅列しておきます。 ・積極的に自ら技術にキャッチアップし自走できるタイプと判断 ・忍耐力と柔軟性を兼ね備えている ・未経験だが努力できる性格 ・人柄も、勉強熱心な姿勢もベンチャー向きな印象 ・受け答えも端的で落ち着いている ・未経験ながら要件定義〜開発と弊社で生かせる実務を経験 ・エンジニアとして大切な技術に対する向上心がある ・一緒に会社を創っていきたいメンバーだと思えた ・Qiita記事を継続的にアウトプットしている ・ポートフォリオのコンセプトは良い 面接に落ちた理由 また面接に落ちた理由もフィードバックを求めたら何社かもらえたので羅列しておきます。 ・技術力を付けたい気持ち、技術的ポテンシャルは感じるが会社への貢献欲求が感じられない ・継続的にうちの会社で働く気があまり感じられない ・実際に面接してみて必要なスキル面がうちの基準に満たない ・サービスに対する見方や志向性の部分がポートフォリオに落とし込み切れていない これらから企業が未経験の中でどういう人材を求めていてどこら辺を軸に活動すれば良いかを最後に記載して終わろうと思います。 これからエンジニア転職活動される方へ まず大前提として意識しておくべきなのは面接を通じて面接官に一緒に働きたいと思ってもらうことです。常にここは頭の片隅に置いておくのが良いかなと思います。面接対策をしているときもこの発言は相手が一緒に働きたいと思える発言なのかという感じで。 2回にわたるエンジニア転職活動で重要だと感じたのはコミュニケーション能力とかそう言った前提のものはもちろん必要だとして企業への熱意をしっかりと伝えられる状態にすること、技術への興味関心をしっかりと伝えていくことの2点が重要だと感じました。ここら辺を深ぼっていきます。 企業への熱意をしっかりと伝えられる状態にするには ここに関しては基本的なことになりますが、企業をよく知ること、自社開発企業であれば自社サービスをよく知ることの2つ重要になってくると思いました。 ・企業をよく知ること とにかく企業のコーポレートサイトを始め、wantedlyの企業サイトでのストーリーや募集要項の読み込み、ブログをやっているならそこら辺もしっかり読み込むことが大事だと思います。 これだけだと普通だし、どこを意識して読めばいいんだよと言われそうなのでもう少し深く記載していきます。 どう言ったところを意識して読めばいいのかというと社員インタビュー、技術ブログ記事は結構読み込んだ方が良いです。 また役員面接とかになってくるとしたらその人の名前で検索して出てきた記事を片っ端から読んでいました。 そこでいろんな価値観や考え方が書かれており、色々見ていくと自分が共感できる部分も何個か出てくると思います。自分は面接時に「この方がこういったことをブログに書かれていて自分もこう言った体験があったので非常に共感できました」とカルチャーへの共感を伝えていました。ただカルチャーや企業理念に共感したとかそう言ったものを伝えてしまうと上部な感じや薄いなと思われるのがオチです。 ・自社サービスをよく知ること これは実際に使ってみる、Twitterとかでそのサービスを調べ他の人がレビューしていたりしていないかなどを探してみる、また強豪他社になるサービスを調べて比較してみたりするのが良いかと思います。 サービスの良かったところ、今後こう言った風に機能改善して行きたいとお伝えできるとちゃんと見てくれてるなと思ってもらえると思います。ここで難しいのが機能改善提案は良いのですが一歩間違えると上から目線に捉えられてしまう可能性もあるので伝えるときには注意が必要です。「未経験なのに何言ってんだみたいな感じで聞いていただければ幸いなんですけど」みたいな感じで枕詞を最初に添えてお伝えして行った方が良いかなと思います。 技術への興味関心を伝えるには まず代表的なのはもちろんポートフォリオだと思います。継続的にブラッシュアップしていき完成度の高いポートフォリオにしていくのは企業評価としても高いのではないかなと思います。 しかしそれ以外にも技術的な興味を伝えるアプローチは沢山あります。自分が力を入れたのはQiitaでのアウトプットです。ただメモ用みたいな感じの記事ではなく、しっかりと学んだ技術を理解しているなと感じさせられるような記事を書けると良いのかなと思いました。そう言った記事が書ければ自然と他の方から見られる回数も多くなりLGTMやストックなど数字としても良いアピールができるかと思います。 あとはIoT機器に触れたりLINEbotとAWS Lambdaを使用して何か自宅のポストに投函されたらラインに通知がいくような装置を作るみたいに面白そうだからやってみたみたいな体験が一つでもできると技術的興味を伝えられると思います。 自分はお風呂の換気扇を自動停止する環境をIoT機器で作ってみました笑 あと学習面で評価されたのは日報作成でした。実務が詰めるエンジニアスクール開始当初から3ヶ月以上日報を書いていて就活が始まった後もずっと書いていたのをWantedlyプロフィールに載せていたのですが、これは思ってたより面接にて触れていただく機会が多く評価されたと思います。 あとがき コロナ影響からか現状かなり未経験からエンジニアを目指す方が増えており、未経験からのエンジニア転職は完全に買い手市場になっているとは思います。 しかしながら継続的に学習し、しっかりとした就活対策をすれば満足のいける企業に入社できる可能性があるのも事実だなと今回改めて転職活動をしてみて思いました。 努力は必ず報われるなんていう無責任なことは言えないけれど、継続的に努力していければ必ず良い方向に向かっていくことができる。自分自身もそういう気持ちで入社後も貪欲に技術力を磨いて行きたいと思います。 最後までご覧いただき本当にありがとうございました!! 少しでも良かったと思っていただけたらLGTMポチッといただけますと幸いです。 Twitterでも今後も転職活動で思ったことを呟いていくのでご覧いただけると幸いです。 @mokio_50
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【しくじり先生】失敗続きの未経験からのエンジニア転職1年間を振り返って最短で満足のいく転職をするにはどうすれば良いかを考えてみた

はじめに こんにちは、28歳未経験から12月より150名規模の自社開発企業で働くことになったもきおです。エンジニア転職を目指し2020年10月に前職を辞め、早1年も経ってしまいました。 仕事をしていながらなら分かるが学習にコミットして流石に一年は長かった。 1年間色々と細かい失敗を繰り返し続けました。でも失敗ばかりだったから伝えられることも多くあると思うんです。そこで今回は今までの流れを振り返りつつ、失敗から何を学びどのようにすればもっと早く満足のいくエンジニア転職ができるかを考えてみました。 書きたいことが多く結構なボリュームになってしまいましたが最後までご覧いただけますと幸いです。 こんな人に読んで欲しい ・プログラミングスクールからエンジニア転職を目指している方 ・独学からエンジニア転職を目指している方 ・エンジニア転職活動をしている方 ・これからプログラミングを学んでエンジニア転職を考えている方 今までの流れ まず初めに「おいもきお、一年も何やってたんだよ」と声が聞こえてきそうなので今までの流れをざっと表で振り返っていきます。 期間 やったこと 2020年10~12月 Progateで基礎固め、DMMWEBCAMP事前学習 2020年12月~3月 DMMWEBCAMP受講 2020年4月~6月 1回目のエンジニア転職活動 2020年7月 フリーランス案件準備、案件結局もらえず 2020年8~10月 実務が積めるエンジニアスクール 2020年10~11月 エンジニア転職活動2回目 実はエンジニア転職活動は2回しています。1回目と2回目は何が違ったのかなどもお伝えできればなと思います。 エンジニアになりたいと思ったら最初にやるべき行動 振り返っていく前に余談を挟みます。 皆さんがエンジニアになりたいと思ったらまず何をするでしょうか? まぁ間違いなくプログラミング学習ですよね。そしてプログラミングスクールに通うか、独学で勉強して転職活動していくかって感じになると思います。 しかしエンジニア系YouTuberのしまぶーさんも仰ってましたが最初にやるべき行動はいきたい企業を探すことです。 いきたい企業を探す→行きたい企業の必要な言語、技術がわかる→必要な言語、技術に対して学習開始→ポートフォリオ作成 この流れが最も明確に学習を進められると思います。 ここでいきたい企業が明確に決まれば問題ないですが最初からそこまで明確には決められないのでスタートアップ系とか大枠の事業内容とかとにかく一旦色んな企業を学習する前、初期段階から見てみるのが良いかなと思います。 また、現役エンジニアの方に積極的にコミュニケーションをとってエンジニア業界の話をまずは聞いてみるのが良いかと思います。現在はTwitter、色んなエンジニアコミュニティなど様々な現役エンジニアの方へのアプローチがあると思います。 2020年10~12月 Progate、DMMWEBCAMP事前学習 そんなこんな言ってますが当時の自分は「プログラミングスクール通ってポートフォリオ作ってエンジニア転職活動すれば転職できるっしょ」くらいに思ってました。 そこで特に仕事を継続して学習しようとはせずプログラミング学習に打ち込むため仕事を辞めることを決意しました。まあ今思えばですけどこの選択は間違ってはなかったとは思います。 さて話を戻して会社を辞めてプログラミング学習を始めたわけですがDMMWEBCAMPはかなり人気で10月から入校したかったのに12月になってしまいました。 なぜDMMWEBCAMPというスクールを選んだのか、実際受講してみてどうだったかはまた別の記事でお伝えしていきたいと思います。 なので最初の2ヶ月はProgateと入校1ヶ月前からDMMWEBCAMPのカリキュラムが配布されるので事前学習をしていました。 事前学習のメリットは振り返ると以下2点 ・本受講で余裕が生まれモチベーション高く学習を進められる ・期限に縛られないで受講できるので理解をしっかりと深め学習できる 当時は今と比べると全然学習時間が取れていませんでしたね。平均3、4時間。多くても6時間くらい。それでも事前学習をできていたのは振り返ってもかなり良かったと思います。 下記Twitterで投票もしてもらいましたが大半が事前学習をするべきを回答していただいていました。どの程度まで事前学習した方がいいのかはこのリンクのスレッドとかで議論されているので良かったらみてください YouTubeのコメントにて「DMMWEBCAMPの事前学習をする必要があると思ってるのはあなただけなんじゃないの」とコメントいただいたので初めて投票機能使ってみたいとおもいます。結果をコメントしていただいた方にご返信するので受講された方はご協力いただけますと幸いです。— もきお (@mokio_50) November 21, 2021 この期間で感じたこと ・事前学習は大事 ・事前学習から危機感を持って学習する 2020年12月~3月DMMWEBCAMP受講 実際の内容とかは後日また記事にしようと思うので省きますが当時の自分を客観的に他受講生と見比べると技術レベルは中の中、あるいは中の下って感じだった気がします。特に後半は結構失速しました笑 受講当時、自分は「学習は量より質でしょ」って思ってたし、「12時間学習しました!」みたいなツイートを見ても「あーそうなんだ」くらいな感じで思ってたしなんなら少ない時間でこれだけ進んでる自分をかっこいいとさえ思ってました(ちょっと誇張してはいるが今考えると普通にキモい)。 そんなこんなで学習時間確保の大切さをわかっていませんでした。よって大体一日6~7時間くらいしか学習していませんでした。今振り返ると圧倒的に絶対的な学習の確保は必要だったなとつくづく思っております。 なぜ絶対的な学習時間の確保が必要であると感じるようになったのか。 それは学習のモチベーション維持にあると思っております。 プログラミング学習はちゃんと継続できる人が、学習する人の1割程度と言われているように様々なところで挫折しそうになるのでモチベーション維持が非常に大切だと感じています。 モチベーション維持のためには小さな成功体験を積み重ねることが大切だと思います。なので質を重視してしまうと、実際思うように学習が進まないときに、モチベーション低下につながります。 一方で量にこだわり学習時間をちゃんと確保していけば学習時間を確保できたことが小さな成功体験になっていくのでモチベーションを維持しやすいのかなと今は感じています。その小さな成功体験によって段々と質の方も自然と良くなっていったなと振り返って見て感じました。 振り返ってみてプログラミングスクールで重要なのは常に危機感を持つことだと思います。 これは井の中の蛙でもないのですが、同期の受講生の中で一番学習した!同期の中で一番技術力がついた!くらい思えるくらい学習しないと満足のいく転職先にいけない可能性は高いです。 これから受講される方はそれくらい高いモチベーションで受講されるのをオススメします。 実際はそんなこともないのですが、要はそれくらいの気持ちで向上心高く貪欲に学習をすると良い方向に進んでいけると思いました。 この期間の失敗から学んだこと ・「質より量」を重視して学習する ・余裕を持つことは大事だが、余裕をぶっこいてると痛い目見るのでどんどん余裕を持って学習できるよう学習を進めていく。 2020年4月~6月 1回目のエンジニア転職活動 さて、プログラミングスクールもなんとか卒業しポートフォリオも一応作成できたので就職活動に移りました。 まず当時の自分のスペックを表にしてみました。客観的にみて10段階評価もつけてみました。 項目 どのくらいやったか 客観的な評価 職務経歴書 ある程度添削してもらい3回くらい修正 7 企業研究 受ける企業を直前に2時間程度 3 面接対策 受ける企業頻出質問5個ぐらい回答を用意 3 ポートフォリオ 一応完成、オリジナリティはある。エラーとかは多発 4 GitHub草 一応毎日生やしてはいた1コミットくらいしかしてない 4 Qiita記事 1記事もかけていなかった 0 この期間の活動を転職活動と学習に分けて振り返っていきたいと思います。 転職活動について 当時はDMMWEBCAMPさんの紹介に任せっきりで自発的に転職活動できていなかったのが一番の失敗した要因だったかなとは振り返ってみて思いました。 エントリー、選考状況は以下でした。 項目 件数 エントリー数 39社 書類選考通過数 11社 一次面接社数 10社 最終面接社数 2社 内定数 1社 内定は一社いただき後に開発経験もしっかり積めそうでしたが、これが本当に自分のやりたかったことなのかと思うと違うと思い辞退しました。 まず転職活動で大事にしたいのは受け身で転職活動をしないこと。 受け身で就活すると特にいきたくない企業ばかり受けることになり、モチベーションも下がるし面接時に志望動機がどうしても弱くなってしまうので企業へ熱意が伝わりづらくなってしまいます。 スクールの紹介は転職活動でのツール(手段)の一つにすぎないという気持ちで転職活動をした方がよっぽど成功する気がしています。これはスクールの紹介企業がダメだとかは全く言っておらず、スクール頼りにならないことが結果的にスクールの紹介で良い企業に内定をもらえたりするからです。 実際現在DMMWEBCAMP生限定のコミュニティであるShuffleというコミュニティに参加させていただいていますが、大半の人が満足のいく企業にスクールの紹介で入社されている印象です。 でもこの方々の多くはWantedlyとかで自ら動いて企業を探してエントリーしつつ、結果的にスクールの紹介企業で内定承諾した人達が多かったです。 よくスクールの紹介以外で転職活動をすると転職保証がなくなりますみたいな感じの制度を持っているスクールが多いですが、これはマジで無視しましょう笑 転職保証に関してはあってないようなものだと思っているくらいがちょうどいいと思います。 大きな決断をしなければいけない転職活動でそういった制度に縛られて視野を狭めるのはやめましょう。正直ここに関してスクール運営をしている企業の方々には申し訳ない発言をしているとは思いますが、本気で満足する企業に就職するにはお伝えしなければいけないと思い、伝えさせていただいております。 学習について プログラミングスクールを卒業してからはJavaと基本情報技術者試験の勉強を進めていました。 振り返ってみるとこれは間違いなく失敗だったと思います笑 内定をいただいた企業で役員との最終面接の際に「やはり目に見えるアウトプットがないと学習の興味度が感じられない。Javaを勉強するのは良いが簡単なポートフォリオを作ってくるくらいじゃないと評価できない。むしろ今まで学習してきたRailsでもう一個自分の興味のある分野でポートフォリオを作るとかの方が俺は好きだなー」っておっしゃってました。この企業はJavaをメインで扱っていて、それでもそうおっしゃるということはやはり成果物がなくただ学習するだけだと評価対象には全くならないんだなと感じました。 なのでJavaやPHPなどRubyは求人数が少ないからみたいな感じで他の言語に手を出して安易に学習するのは間違いなく辞めた方が良いです。 実際その言語でないとできないものを作りたい(Rubyじゃ作れないスマートフォンアプリを作りたい)等具体的なアウトプットや明確にいきたい企業が学習した言語と違うみたいな感じであれば別ですが。 あと2回目の転職活動の方でも書きますが企業が使っている言語を学習していなくても採用される可能性は全然あります。要は何か一つの言語を極めていくこと。これが企業評価として大事なんだなと振り返って思いました。 あと資格は重要なのかについてはそんなにガチで取りに行く必要はないかなと思います。 資格を持っていてもそこまで評価は変わらない。優先順位としては低い感じですかね。 ただコンピューターサイエンスを学ぶ面では良かったと思うので参考書を買ってちょくちょく読んでいると面接の技術質問対策にはなるかなと思いました。 ここまで学習の失敗をダラダラ書いてきましたが転職活動と並行して追加で何を勉強したら企業に評価されるかというとLinux、SQL、 Git、AWSなどのインフラへの理解等、どんなサーバーサイド言語を使用したとしても汎用性の高いのものを学習するのが良いのかなと思いました。 実際企業に入っても(まだ入社してないけど笑)学習が無駄にならないし、技術質問でも「Linuxコマンドはどんなの使ってましたか?」とかSQL知識を問われたりとか、Gitの使用経験とかも聞かれたので学んでおいて損はないと思います。 あとは作成したポートフォリオのブラッシュアップですかね。テストコード書いたり、エラー修正したり、非同期通信増やしたり。ここら辺はどんな機能を追加したから良いとかではなく、改善する姿勢を見せていくことが重要だと思います。 最後にこのフェーズで言いたいと思ったのは学習習慣を途切れさせないこと。 これはマジで重要だと思います。就活はメインでやっていくのですが1日30分でも良いので必ず1日の何処かで学習するようにした方が良いです。学習習慣が途切れていると就活入ってから学習していないなと面接官にすぐバレます。 学習習慣はマジで脆いです。二、三日学習しないだけでも、もろに崩れていきます。 そして学習が30分しかできなかったと思うのではなく、30分学習できたと自分を褒めてあげてください。これが転職活動が始まった後も学習習慣を途切れさせない秘訣だと自分は思います。 この期間の失敗から学んだこと 転職活動 ・自発的に企業を探していく意識を持つ ・転職保証制度に縛られない ・色んな求人媒体を使用して広い視野を持って企業を探す 学習 ・安易に他の学習をしない ・追加で学ぶなら汎用性の高いものを学習 ・一日30分でも良いから学習の継続週間を途切れさせないようにする ・ちょっとでも学習できた自分を褒めてあげる ・ポートフォリオのブラッシュアップをコンスタントにやる 2020年7月 フリーランス案件準備、案件結局もらえず さて、最終的に内定を辞退して何を思ったのかというと「やはり実務経験を積まないと満足いく企業に就職できないんじゃね?」って思いました。実際そんなことないのにね笑 ただ後に記載しますが短い期間でも実務経験を積めるに越したことはないのも事実です。 そこでフリーランスエンジニアの方に相談し、他のエンジニアの方と一緒に同じ案件に参画できる可能性があるとお伝えされました。1人でやるならまず厳しいけど、他のエンジニアの方と一緒に参画できるならアリかもしれないと思い参画を希望しました。 ただ現実はそんなに甘くはなかった。結果的に未経験だったからか企業に推薦して参画できるかもってなってもその後企業から返信が来なかったりして結局案件に参加することができませんでした。 その期間にLaravelを使用した案件に参画する可能性が高いからLaravelをかじったり、基本その方の案件で多いのはPythonのDjangoだったのでそれをかじったりと学習は瞑想していました。 改めて一つの言語に絞って極めていく重要性を感じた時でもありました。 ここら辺の学習はマジで無駄だったなと思います笑 でもそういった視野を広げてフリーランス業界を知れたのは良かったと思います。 今ではフリーランスの実際の現場とかの話を聞いたからか全くと言っていいほどフリーランスになりたいとは思わないけど笑 この期間で学んだこと ・広く浅く学んでも市場価値は全く変わらない ・フリーランス事情、大変さ ・未経験からフリーランスはほぼ間違いなくやめた方が良い 2020年8~10月 実務が積めるエンジニアスクール入校 学習は瞑想する一方だし、フリーランスエンジニアの方に頼る一方じゃなくて自分でも動かないといけないなと思っていた矢先のこと、YouTubeでちょくちょく拝見させていただいた山浦清人さん @kiyotoyamauraが8月より始まる「実務が詰めるエンジニアスクール」を募集しているではありませんか!! これは応募しない手はない!と思い応募し、無事応募選考を通り入校させていただきました。 このスクールは自分の時は全体で3ヶ月、1ヶ月半実務期間、1ヶ月半転職サポート期間って感じでした。現在は2ヶ月実務期間、2ヶ月転職サポートとなっているみたいです。 実務案件の詳しい内容は以下にまとめています。 実際実務をやって思ったのは想像の何倍も大変だったということ。しかも山浦さんにアドバイスをもらいつつもそれくらい大変だったので、1人で実務案件をこなすのはどれだけ大変なんだろうと考えるだけでも嫌になったのを覚えています。笑 でも曲がりなりにも実務案件をやり切れたのは自分の中の経験として非常に大きかったし、面接でもこれだけやったから自信を持って実務案件について説明することができました。 そして実務案件と同じくらいすごく良い経験になったのはその後の就職活動サポートです。 現役エンジニアでもあり、採用担当もされていた山浦さんの提出書類、Wantedlyプロフィール添削、面接対策は本当に参考になったし模擬面接を録画して何度も見返すことでかなり面接力みたいなのがかなりついたと思います。 2020年10~11月 エンジニア転職活動2回目 さて、いよいよ2回目の転職活動が始まりました。また別記事に詳しい就活戦略とかは書いていこうと思うので今回はある程度の概要だけ書こうと思います。 また一回目と同じようにスペックを以下に記載していきます。 項目 どのくらいやったか 客観的な評価 職務経歴書 土台をさらに添削してもらい3回くらい修正 9 企業研究 企業ブログ、コーポレートサイトを網羅的に 10 面接対策 頻出質問網羅的に、録画してひたすら見返す 8 ポートフォリオ ちょくちょく修正はしていた 5 GitHub草 ちゃんと生やしていた。平均5、6コミットくらい 7 Qiita記事 15記事書いた 8 エントリー、選考状況は以下でした。 項目 件数 エントリー数 79社 書類選考通過数 30社 一次面接社数 11社 最終面接社数 5社 内定数 4社 最初は最悪開発経験がある程度早い段階でしっかり積める企業であればいいかな程度に思っていましたが、終わってみれば想像の数倍上手くいったなと感じております。もちろん実務が詰めるスクールでの就活対策も非常に役に立ちましたが、DMMWEBCAMPでの職務経歴書の土台作りがあったからこそスムーズに言ったとつくづく感じました。 自分自身最初はSES、受託、自社開発を絞らずとりあえず使いたいサーバーサイド言語で企業を調べていましたが、調べていくうちに自分自身やっている事業への関心がとても高いことに気づきました。「やっている事業に共感できる、面白いと思える企業に行きたい!」と思ったので自社開発企業に段々と絞って就職活動を進めて行きました。 よって面接をする企業もだんだんと絞ったため30社書類通過しても結果的に11社のみしか受けなかったです。それによって一社一社しっかりと準備できたのは良かったかなと思います。 学習していない言語を使う企業も内定をいただけました。聞いてみたらやはり未経験の学習なんてたかが知れているので特に学習してきた言語はそこまで見ていないとのこと。それよりも何を考え学習してきたかという学習のプロセスが大事だと企業の人に言われました。 評価されたポイント 内定をいただけた企業、落ちた企業にフィードバックをひたすら求め評価していただいた点を羅列しておきます。 ・積極的に自ら技術にキャッチアップし自走できるタイプと判断 ・忍耐力と柔軟性を兼ね備えている ・未経験だが努力できる性格 ・人柄も、勉強熱心な姿勢もベンチャー向きな印象 ・受け答えも端的で落ち着いている ・未経験ながら要件定義〜開発と弊社で生かせる実務を経験 ・エンジニアとして大切な技術に対する向上心がある ・一緒に会社を創っていきたいメンバーだと思えた ・Qiita記事を継続的にアウトプットしている ・ポートフォリオのコンセプトは良い 面接に落ちた理由 また面接に落ちた理由もフィードバックを求めたら何社かもらえたので羅列しておきます。 ・技術力を付けたい気持ち、技術的ポテンシャルは感じるが会社への貢献欲求が感じられない ・継続的にうちの会社で働く気があまり感じられない ・実際に面接してみて必要なスキル面がうちの基準に満たない ・サービスに対する見方や志向性の部分がポートフォリオに落とし込み切れていない これらから企業が未経験の中でどういう人材を求めていてどこら辺を軸に活動すれば良いかを最後に記載して終わろうと思います。 これからエンジニア転職活動される方へ まず大前提として意識しておくべきなのは面接を通じて面接官に一緒に働きたいと思ってもらうことです。常にここは頭の片隅に置いておくのが良いかなと思います。面接対策をしているときもこの発言は相手が一緒に働きたいと思える発言なのかという感じで。 2回にわたるエンジニア転職活動で重要だと感じたのはコミュニケーション能力とかそう言った前提のものはもちろん必要だとして企業への熱意をしっかりと伝えられる状態にすること、技術への興味関心をしっかりと伝えていくことの2点が重要だと感じました。ここら辺を深ぼっていきます。 企業への熱意をしっかりと伝えられる状態にするには ここに関しては基本的なことになりますが、企業をよく知ること、自社開発企業であれば自社サービスをよく知ることの2つ重要になってくると思いました。 ・企業をよく知ること とにかく企業のコーポレートサイトを始め、wantedlyの企業サイトでのストーリーや募集要項の読み込み、ブログをやっているならそこら辺もしっかり読み込むことが大事だと思います。 これだけだと普通だし、どこを意識して読めばいいんだよと言われそうなのでもう少し深く記載していきます。 どう言ったところを意識して読めばいいのかというと社員インタビュー、技術ブログ記事は結構読み込んだ方が良いです。 また役員面接とかになってくるとしたらその人の名前で検索して出てきた記事を片っ端から読んでいました。 そこでいろんな価値観や考え方が書かれており、色々見ていくと自分が共感できる部分も何個か出てくると思います。自分は面接時に「この方がこういったことをブログに書かれていて自分もこう言った体験があったので非常に共感できました」とカルチャーへの共感を伝えていました。ただカルチャーや企業理念に共感したとかそう言ったものを伝えてしまうと上部な感じや薄いなと思われるのがオチです。 ・自社サービスをよく知ること これは実際に使ってみる、Twitterとかでそのサービスを調べ他の人がレビューしていたりしていないかなどを探してみる、また強豪他社になるサービスを調べて比較してみたりするのが良いかと思います。 サービスの良かったところ、今後こう言った風に機能改善して行きたいとお伝えできるとちゃんと見てくれてるなと思ってもらえると思います。ここで難しいのが機能改善提案は良いのですが一歩間違えると上から目線に捉えられてしまう可能性もあるので伝えるときには注意が必要です。「未経験なのに何言ってんだみたいな感じで聞いていただければ幸いなんですけど」みたいな感じで枕詞を最初に添えてお伝えしていった方が良いかなと思います。 技術への興味関心を伝えるには まず代表的なのはもちろんポートフォリオだと思います。継続的にブラッシュアップしていき完成度の高いポートフォリオにしていくのは企業評価としても高いのではないかなと思います。 しかしそれ以外にも技術的な興味を伝えるアプローチは沢山あります。自分が力を入れたのはQiitaでのアウトプットです。ただメモ用みたいな感じの記事ではなく、しっかりと学んだ技術を理解しているなと感じさせられるような記事を書けると良いのかなと思いました。そう言った記事が書ければ自然と他の方から見られる回数も多くなりLGTMやストックなど数字としても良いアピールができるかと思います。 あとはIoT機器に触れたり、LINEbotとAWS Lambdaを使用し何か自宅のポストに投函されたらラインに通知がいくような装置を作る、みたいな感じで面白そうだからやってみた的な体験が一つでもできると技術的興味を伝えられると思います。 自分はお風呂の換気扇を自動停止する環境をIoT機器で作ってみました笑 あと学習面で評価されたのは日報作成でした。実務が詰めるエンジニアスクール開始当初から3ヶ月以上日報を書いていて就活が始まった後もずっと書いていたのをWantedlyプロフィールに載せていたのですが、これは思ってたより面接にて触れていただく機会が多く評価されたと思います。 あとがき コロナ影響からか現状かなり未経験からエンジニアを目指す方が増えており、未経験からのエンジニア転職は完全に買い手市場になっているとは思います。 しかしながら継続的に学習し、しっかりとした就活対策をすれば満足のいける企業に入社できる可能性があるのも事実だなと今回改めて転職活動をしてみて思いました。 努力は必ず報われるなんていう無責任なことは言えないけれど、継続的に努力していければ必ず良い方向に向かっていくことができる。自分自身もそういう気持ちで入社後も貪欲に技術力を磨いて行きたいと思います。 最後までご覧いただき本当にありがとうございました!! 少しでも良かったと思っていただけたらLGTMポチッといただけますと幸いです。 Twitterでも今後も転職活動で思ったことを呟いていくのでご覧いただけると幸いです。 @mokio_50
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

インチキをしてRailsでExcelを読み書きする

Excel大好きな人達 多くの案件ではExcel好きなプロパーとかExcel好きなプロパーとかExcel好きなプロパーが跋扈しており、確固たる理由はないがなんとなく「Excelライクで」とか言われることが非常に多いと感じています。 Excelライクと言わないまでも、Excelをアップロードできたりダウンロードできたりと言った要件は、非常にカジュアルに生じています。 「DXの意味わかっているの?」と言いたくなるのですが、これが原状なのでしょうがありません。 Railsライブラリの限界 ただ、Railsエンジニアなら一度は経験したことがあると思うのですが、RailsにはExcelをうまく扱えるライブラリがあまりありません。 ライブラリ 機能 注記 Axlsx 新規作成から書き出しだけ 新規作成のみで、テンプレートファイルからの新規作成もできない。複雑なワークシートを作ろうと思うと、コードが恐ろしく読みにくくなる Roo 読み込みだけ 読み込み専用 RubyXL 読み書き可能 数少ない読み書き可能なライブラリだが、parseが恐ろしく遅いのであまり使い物にならない Pythonにはopenpyxlがある 一方、Pythonは世界中のデータサイエンティストが使っていることもあって、openpyxlという非常に使いやすいライブラリが存在して、ものすごく手軽に扱うことが可能になっています。 今回は、Rubyからopenpyxlを呼び出してみました。 コンテナにpython及びライブラリを入れる 今回はDockerを使っている前提で、Rubyの動いているコンテナにpythonをインストールします。システム管理やaws-cliを動かすためにすでに入っているケースも多いと思います。 Dockerfile FROM ruby:2.7.4-alpine RUN mkdir /app ENV APP_ROOT /app WORKDIR $APP_ROOT RUN apk add --update --no-cache \ ... python3 python3-dev py3-pip && \ pip install openpyxl ... コンテナを使っていない場合はvenvを使ったほうがいいと思いますが、本稿では触れません。 簡単なPythonスクリプトを作成する ここでは、標準入力から{"A1": "Hello, World!"}のようなJSONを受け取り、テンプレートのExcelファイルに書き込んだうえ、そのExcelファイルを標準出力に書き出すスクリプトを作成しました。 メインのロジックをあまりRailsの外におきたくなかったので、極力シンプルにしています。 python/to_excel.py import os import sys import json import openpyxl import tempfile cell_values = json.loads(sys.stdin.read()) wb = openpyxl.load_workbook("spec/fixtures/template.xlsx") ws = wb.worksheets[0] for cell, value in cell_values.items(): ws[cell] = value tmp = tempfile.NamedTemporaryFile(delete=False) wb.save(tmp.name) tmp.close() with open(tmp.name, 'rb') as f: sys.stdout.buffer.write(f.read()) os.unlink(tmp.name) Ruby(Rails)からpopenでpythonを呼び出す excel = IO.popen('python3 python/to_excel.py', 'r+') do |io| io.puts cell_values.to_json io.close_write io.read end excelにはExcelファイルのバイナリが入ります。ActiveStorageに入れるなり、send_dataするなりして料理しましょう。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails 6.0 + Docker + MySQL5x + devise-token-auth での環境構築

この記事の概要 RailsのAPIモードで認証周り作ったときに苦労したので、備忘録メモとして…。 成果物 GitHub: try-rails6-api-with-devise 各種バージョン Ruby 2.7 Rails 6.0.0 mysql 5.7.21 前提条件 Dockerを使える環境が整っていること できること Rails 6.0 + Docker + MySQL5x + devise-token-auth での環境構築 devise-token-authを使った、サインアップ、サインイン、サインアウトができる ユーザがサインインしていることを確認し、サインインしていたらuser情報を取得する できないこと(やらないこと) コピペで環境構築できるように作った記事なので、各項目の詳しい説明は割愛 環境構築手順 1. try-rails6-api のテンプレートを使用し、リポジトリを作成する リポジトリ名は try-rails6-api-with-devise とする 必要に応じて、 try-rails6-api と記載している箇所を自分で作成したリポジトリ名に変更する(当記事であれば try-rails6-api-with-devise に変更) 2. try-rails6-apiのREADME.md に沿って環境構築する 3. 必要なGemを追加する Gemfile Gemfile ・ ・ ・ # 認証 gem "devise" gem "devise_token_auth" # Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible # ※ 疎通確認をPostmanでする場合、必要となる場合があるので追加しておく gem 'rack-cors' 4. ビルド&追加したGemをインストールする docker-compose build --no-cache docker-compose run back bundle exec rails g devise:install docker-compose run back bundle exec rails g devise_token_auth:install User auth 5. devise_token_auth の設定 config/initializers/devise_token_auth.rb config/initializers/devise_token_auth.rb # frozen_string_literal: true DeviseTokenAuth.setup do |config| # By default the authorization headers will change after each request. The # client is responsible for keeping track of the changing tokens. Change # this to false to prevent the Authorization header from changing after # each request. config.change_headers_on_each_request = false # By default, users will need to re-authenticate after 2 weeks. This setting # determines how long tokens will remain valid after they are issued. # config.token_lifespan = 2.weeks # Limiting the token_cost to just 4 in testing will increase the performance of # your test suite dramatically. The possible cost value is within range from 4 # to 31. It is recommended to not use a value more than 10 in other environments. config.token_cost = Rails.env.test? ? 4 : 10 # Sets the max number of concurrent devices per user, which is 10 by default. # After this limit is reached, the oldest tokens will be removed. # config.max_number_of_devices = 10 # Sometimes it's necessary to make several requests to the API at the same # time. In this case, each request in the batch will need to share the same # auth token. This setting determines how far apart the requests can be while # still using the same auth token. # config.batch_request_buffer_throttle = 5.seconds # This route will be the prefix for all oauth2 redirect callbacks. For # example, using the default '/omniauth', the github oauth2 provider will # redirect successful authentications to '/omniauth/github/callback' # config.omniauth_prefix = "/omniauth" # By default sending current password is not needed for the password update. # Uncomment to enforce current_password param to be checked before all # attribute updates. Set it to :password if you want it to be checked only if # password is updated. # config.check_current_password_before_update = :attributes # By default we will use callbacks for single omniauth. # It depends on fields like email, provider and uid. # config.default_callbacks = true # Makes it possible to change the headers names config.headers_names = {:'access-token' => 'access-token', :'client' => 'client', :'expiry' => 'expiry', :'uid' => 'uid', :'token-type' => 'token-type' } # By default, only Bearer Token authentication is implemented out of the box. # If, however, you wish to integrate with legacy Devise authentication, you can # do so by enabling this flag. NOTE: This feature is highly experimental! # config.enable_standard_devise_support = false # By default DeviseTokenAuth will not send confirmation email, even when including # devise confirmable module. If you want to use devise confirmable module and # send email, set it to true. (This is a setting for compatibility) # config.send_confirmation_email = true end 6. rack-cors の設定 rack-cors がインストールされていることを確認する docker-compose run --rm back bundle info rack-cors 設定ファイル作成 touch config/initializers/core.rb config/initializers/core.rb config/initializers/core.rb Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do origins "localhost:3000" # フロント側のポート番号を指定 resource "*", headers: :any, expose: ["access-token", "expiry", "token-type", "uid", "client"], methods: [:get, :post, :put, :patch, :delete, :options, :head] end end 7. Modelの設定 app/models/user.rb app/models/user.rb # frozen_string_literal: true class User < ActiveRecord::Base # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :rememberable, :validatable include DeviseTokenAuth::Concerns::User end 8. Controllerの設定 (01) Registrations Controller コントローラ作成 docker-compose run back rails g controller v1/registrations --no-assets --no-helper app/controllers/v1/registrations_controller.rb app/controllers/v1/registrations_controller.rb module V1 class RegistrationsController < DeviseTokenAuth::RegistrationsController private def sign_up_params params.permit(:email, :password, :password_confirmation, :name) end end end (02) Users Controller コントローラ作成 docker-compose run back rails g controller v1/users --no-assets --no-helper app/controllers/v1/users_controller.rb app/controllers/v1/users_controller.rb module V1 class UsersController < ApplicationController # Sign inしてないと以下のMethodは実行できない before_action :authenticate_v1_user! # 全件検索 def index user = User.all if user render json: { user: user}, status: :ok else render user end end end end (03) Application Controller app/controllers/application_controller.rb app/controllers/application_controller.rb class ApplicationController < ActionController::API include DeviseTokenAuth::Concerns::SetUserByToken rescue_from ActiveRecord::RecordNotFound, with: :render_404 before_action :configure_permitted_parameters, if: :devise_controller? def render_404 render status: 404, json: { message: "record not found." } end def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) end end 9. Routingの設定 config/routes.rb config/routes.rb Rails.application.routes.draw do mount_devise_token_auth_for 'User', at: 'auth' namespace :v1, defaults: { format: :json } do get :healthcheck, to: 'sessions#healthcheck' mount_devise_token_auth_for 'User', at: 'auth', controllers: { registrations: 'v1/registrations', sessions: "devise_token_auth/sessions" } resources :users end end 10. マイグレーション実行 docker-compose run --rm back bundle exec rake db:migrate 疎通確認 Postmanを使用 1. コンテナ起動 docker-compose up 2. サインアップ URL [POST] http://localhost:4000/v1/auth Body: raw(JSON) {"email": "sample@test.com", "password": "xxxxxxxx", "name": "サンプル 太郎"} 3. サインイン URL [POST] http://localhost:4000/v1/auth/sign_in Body: raw(JSON) {"email": "sample@test.com", "password": "xxxxxxxx"} 4. サインアウト URL [DELETE] http://localhost:4000/v1/auth/sign_out Headers サインインで取得した、以下の項目を設定する access-token uid client expiry content-type token-type 5. ユーザ情報取得(サインインしていないと取得できない) URL [GET] http://localhost:4000/v1/users Headers サインインで取得した、以下の項目を設定する access-token uid client expiry content-type token-type
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む