20210426のRubyに関する記事は20件です。

【Google Maps API】本番環境でGoogle Mapが正しく読み込まれない原因と解決法

本番環境でGoogle Mapを表示できない このページではGoogleマップが正しく読み込まれませんでした。 結論 APIキーを config/credentials.yml.encファイルで管理する (.envファイルでなく) 原因 本番環境にAPIキーを渡せていない 経緯 Google Maps API 導入 ローカル環境でマップ表示できた APIキーを.envファイルで管理していた .envファイルは外部から見えぬよう、Gitの対象から外していた AWSにデプロイ後、ドメイン取得、HTTPS化してアクセスすると、マップ表示できなくなった 本番環境にAPIキーを渡せていないのかも?(仮説) 本番環境からは.envファイルを参照できない! 本番環境にも、APIキーを隠して渡す config.credentials.yml.encファイルにAPIキーを記述 ローカルのターミナル EDITOR=vi rails credentials:edit #vimでファイルを開く config/credentials.yml.enc google_map_api_key: xxxxxxxxxxxxxxxxxxxxxxxx #APIキーを追記 ビューで、config/credentials.yml.encファイルの記述を読み取る map.html.erb <script src="https://maps.googleapis.com/maps/api/js?key=<%= Rails.application.credentials.google_map_api_key %>&callback=initMap" async defer></script> #<%= Rails.application.credentials.google_map_api_key %> #これで「config.credentials.yml.enc」ファイルの「google_map_api_key」を取得できる キーの読み取り方(記述の違い) <%= Rails.application.credentials.google_map_api_key %> #credentials.yml.encファイルからキー取得 <%= ENV['google_map_api_key'] %> #.envファイルからキー取得 Google Mapが表示されない時の確認事項 取得したAPIキーをhtml内に記述しているか 支払い情報を登録しているか 請求先アカウントを未設定の場合、マップが1日1回しか表示できないらしい 表示回数の制限「割り当て」が1回になっていないか 回数制限がかかっているとMapが表示エラーになる可能性がある 請求アカウントとプロジェクトがひも付いているか 参考 GoogleMapが表示されないエラーが出た時の対処法 Rails5.2から追加された credentials.yml.enc のキホン さいごに Google Maps API導入は比較的スムーズに設定できました。(ローカルで) マップがうまく読み込まれない主な原因は、Google Cloud Platformでの設定が多いようですが、 APIキーを本番環境に渡せていないのは盲点でした。 パスワードやキーの管理方法について、セキュリティ面を見直すいい機会とはなりました。 間違っている点がありましたら、ご指摘いただけるとありがたいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Google Maps API】本番環境でGoogle Mapが正しく読み込まれなかった原因と解決法

本番環境でGoogle Mapを表示できない このページではGoogleマップが正しく読み込まれませんでした。 結論 APIキーを config/credentials.yml.encファイルで管理する (.envファイルでなく) 原因 本番環境にAPIキーを渡せていない 新しく取得したキー設定の誤りだと思ったら、キーの管理方法という基礎部分の誤りでした。。 経緯 Google Maps API 導入 ローカル環境でマップ表示できた APIキーを.envファイルで管理していた .envファイルは外部から見えぬよう、Gitの対象から外していた AWSにデプロイ後、ドメイン取得、HTTPS化してアクセスすると、マップ表示できなくなった 本番環境にAPIキーを渡せていないのかも?(仮説) 本番環境からは.envファイルを参照できない! 本番環境にも、APIキーを隠して渡す config.credentials.yml.encファイルにAPIキーを記述 ローカルのターミナル EDITOR=vi rails credentials:edit #vimでファイルを開く config/credentials.yml.enc google_map_api_key: xxxxxxxxxxxxxxxxxxxxxxxx #APIキーを追記 ビューで、config/credentials.yml.encファイルの記述を読み取る map.html.erb <script src="https://maps.googleapis.com/maps/api/js?key=<%= Rails.application.credentials.google_map_api_key %>&callback=initMap" async defer></script> #<%= Rails.application.credentials.google_map_api_key %> #これで「config.credentials.yml.enc」ファイルの「google_map_api_key」を取得できる キーの読み取り方(記述の違い) <%= Rails.application.credentials.google_map_api_key %> #credentials.yml.encファイルからキー取得 <%= ENV['google_map_api_key'] %> #.envファイルからキー取得 Google Mapが表示されない時の確認事項 取得したAPIキーをhtml内に記述しているか 支払い情報を登録しているか 請求先アカウントを未設定の場合、マップが1日1回しか表示できないらしい 表示回数の制限「割り当て」が1回になっていないか 回数制限がかかっているとMapが表示エラーになる可能性がある 請求アカウントとプロジェクトがひも付いているか 参考 GoogleMapが表示されないエラーが出た時の対処法 Rails5.2から追加された credentials.yml.enc のキホン さいごに Google Maps API導入は比較的スムーズに設定できました。(ローカルで) マップがうまく読み込まれない主な原因は、Google Cloud Platformでの設定が多いようですが、 APIキーを本番環境に渡せていないのは盲点でした。 キーやパスワードの管理方法について、セキュリティ面を見直すいい機会とはなりました。 間違っている点がありましたら、ご指摘いただけるとありがたいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

数字の各桁の合計算出方法

概要 数値の各桁を合計するメソッドを作成します。 ex)数値:117 → 合計:9 結論 def num_sum(num) sum = 0 while num > 0 sum += num % 10 num = num / 10 end end 解説 メソッドnum_sumは、各桁合計される数値である引数numを受け取ります。 メソッド内部では、 ①各桁合計の値を格納する変数sumを用意します。 ②各桁合計をする処理をwhile式を用いて算出します。  先頭桁の値は、数値を10で割った余りを足すことで算出できます。  そのため、まず数値numを10で割ったあまりを合計sumに加えます。 sum += num % 10  次に、先頭から2番目の桁の値を算出します。  その方法として、数値numを10で割って、再度、数値numに代入します。  数値を割った時の小数は、変数numが整数型であるため切り捨てられます。 num = num / 10  whileの条件式で、数値numの値が0以下になった時点で合計処理を抜けます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

数値の各桁の合計算出方法

概要 数値の各桁を合計するメソッドを作成します。 ex)数値:117 → 合計:9 結論 def num_sum(num) sum = 0 while num > 0 sum += num % 10 num = num / 10 end end 解説 メソッドnum_sumは、各桁合計される数値である引数numを受け取ります。 メソッド内部では、 ①各桁合計の値を格納する変数sumを用意します。 ②各桁合計をする処理をwhile式を用いて算出します。  数値の先頭桁の値は、数値を10で割った余りを足すことで算出できます。  そのため、まず数値numを10で割ったあまりを合計sumに加えます。 sum += num % 10  次に、数値の先頭から2番目の桁の値を算出します。  その方法として、数値numを10で割って、再度、数値numに代入します。  数値を割った時の小数は、変数numが整数型であるため切り捨てられます。 num = num / 10  whileの条件式で、数値numの値が0以下になった時点で合計処理を抜けます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[メモ]Dockerの環境構築+Rails APIモードのまとめ

初めに 最近はDockerとRailsのAPIモードを学習してるので、 学んだことをまとめてメモしておきます。 まずはDocker環境構築から Dockerの環境構築は主に以下の記事の参考で作成していきます。 最初はまず作業用のファイルを用意します $ mkdir myapp Dockerfile作成 rubyのバージョンは自分が今使ってる2.7.2に変更してみます。 Dockerfile FROM ruby:2.7.2 RUN apt-get update -qq && apt-get install -y nodejs postgresql-client RUN apt-get update && apt-get install -y curl apt-transport-https wget && \ 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 RUN curl -sL https://deb.nodesource.com/setup_7.x | bash - && \ apt-get install nodejs RUN mkdir /myapp WORKDIR /myapp COPY Gemfile /myapp/Gemfile COPY Gemfile.lock /myapp/Gemfile.lock RUN bundle install COPY . /myapp # Add a script to be executed every time the container starts. COPY entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] EXPOSE 3000 # Start the main process. CMD ["rails", "server", "-b", "0.0.0.0"] P.S.Docker 入門 1項目ずつ理解するでは、Dockerfileの書き方について分かりやすく説明していますので、是非ご参考ください。 Gemfile作成 myapp/Gemfile source 'https://rubygems.org' gem 'rails', '~> 6' Gemfile.lock 作成 $ touch Gemfile.lock 中身は空のままでオッケー entrypoint.sh作成 $ touch entrypoint.sh myapp/entrypoint.sh #!/bin/bash set -e # Remove a potentially pre-existing server.pid for Rails. rm -f /myapp/tmp/pids/server.pid # Then exec the container's main process (what's set as CMD in the Dockerfile). exec "$@" docker-compose.yml 作成 $ touch docker-compose.yml myapp/docker-compose.yml version: "3.9" services: db: image: postgres volumes: - ./tmp/db:/var/lib/postgresql/data environment: POSTGRES_HOST_AUTH_METHOD: 'trust' web: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/myapp ports: - "3000:3000" depends_on: - db P.S.Docker 入門 1項目ずつ理解する これで下準備完了 ファイルの中はこんな感じ: myapp - Dockerfile - Gemfile - Gemfile.lock - entrypoint.sh - docker-compose.yml いよいよRails new 今回RailsのAPI開発モードを利用していますので、--apiオプションを使います。 -Tはデフォルトのテスティングフレームワーク「Minitest」をオフにするオプションです。 APIモード使わない場合は--apiを自由に削除してください。 $ docker-compose run web rails new . --force --no-deps --database=postgresql --api -T ls -lコマンドでみると。。。 $ ls -l total 64 -rw-r--r-- 1 tsuki_ staff 831 Apr 24 23:02 Dockerfile -rw-r--r-- 1 tsuki_ staff 1397 Apr 24 23:48 Gemfile -rw-r--r-- 1 tsuki_ staff 4022 Apr 24 23:48 Gemfile.lock -rw-r--r-- 1 tsuki_ staff 374 Apr 24 23:48 README.md -rw-r--r-- 1 tsuki_ staff 227 Apr 24 23:48 Rakefile drwxr-xr-x 8 tsuki_ staff 256 Apr 24 23:48 app drwxr-xr-x 7 tsuki_ staff 224 Apr 24 23:48 bin drwxr-xr-x 16 tsuki_ staff 512 Apr 24 23:48 config -rw-r--r-- 1 tsuki_ staff 160 Apr 24 23:48 config.ru drwxr-xr-x 3 tsuki_ staff 96 Apr 24 23:48 db -rw-r--r-- 1 tsuki_ staff 366 Apr 24 23:29 docker-compose.yml -rw-r--r-- 1 tsuki_ staff 201 Apr 24 23:23 entrypoint.sh drwxr-xr-x 3 tsuki_ staff 96 Apr 24 23:48 lib drwxr-xr-x 3 tsuki_ staff 96 Apr 24 23:48 log drwxr-xr-x 3 tsuki_ staff 96 Apr 24 23:48 public drwxr-xr-x 3 tsuki_ staff 96 Apr 24 23:48 storage drwxr-xr-x 7 tsuki_ staff 224 Apr 24 23:48 tmp drwxr-xr-x 3 tsuki_ staff 96 Apr 24 23:48 vendor 無事にRailsが生成されてますね! bundle install $ docker-compose build ぬぬ!?エラーが出ました ...[前略] ------ > [ 9/12] RUN bundle install: #14 0.294 /usr/local/lib/ruby/2.7.0/rubygems.rb:277:in `find_spec_for_exe': Could not find 'bundler' (1.17.2) required by your /myapp/Gemfile.lock. (Gem::GemNotFoundException) #14 0.294 To update to the latest version installed on your system, run `bundle update --bundler`. #14 0.294 To install the missing version, run `gem install bundler:1.17.2` #14 0.296 from /usr/local/lib/ruby/2.7.0/rubygems.rb:296:in `activate_bin_path' #14 0.296 from ------ ...[後略] run `gem install bundler:1.17.2` と書いたので、追加してみます。 Dockerfile RUN mkdir /myapp WORKDIR /myapp COPY Gemfile /myapp/Gemfile COPY Gemfile.lock /myapp/Gemfile.lock ########追加########### RUN gem install bundler:1.17.2 ###################### RUN bundle install COPY . /myapp はい、$ docker-compose build ぬぬ!?また新しいエラーが出てきました。 ...[前略] ------ > [10/13] RUN bundle install: #14 0.734 Your Ruby version is 2.7.2, but your Gemfile specified 2.6.5 ------ ...[後略] そっか、GemfileのRubyバージョンは2.6.5だったのか はい、変更! Gemfile #変更前 ruby '2.6.5' #変更後 ruby '2.7.2' 。。。 はい、$ docker-compose build! ...[前略] Successfully built..... ...[後略] 今度こそ無事にできたんですね! DBへの接続設定 Railsのconfig/database.ymlファイルを、下記のように書き換えます。 database.yml default: &default adapter: postgresql encoding: unicode host: db username: postgres password: pool: 5 development: <<: *default database: myapp_development test: <<: *default database: myapp_test Dockerコンテナの起動 では、Dockerを起動してみます。 $ docker-compose up したら、安心する画面ができましたね! ...[前略] web_1 | => Booting Puma web_1 | => Rails 6.1.3.1 application starting in development web_1 | => Run `bin/rails server --help` for more startup options web_1 | Puma starting in single mode... web_1 | * Puma version: 5.2.2 (ruby 2.7.2-p137) ("Fettisdagsbulle") web_1 | * Min threads: 5 web_1 | * Max threads: 5 web_1 | * Environment: development web_1 | * PID: 1 web_1 | * Listening on http://0.0.0.0:3000 web_1 | Use Ctrl-C to stop http://0.0.0.0:3000にアクセスしてみると ぬぬ!?またエラーの画面が出てきました。 ...[前略] web_1 | ActiveRecord::NoDatabaseError (FATAL: database "myapp_development" does not exist web_1 | ): ...[後略] そかそかdatebaseの問題ね! では一旦 $ docker-compose down P.s.筆者はもう一つターミナルを開いて実行していますが、 こちらの【Docker超入門 #7】Docker ComposeでRailsを構築しようの19:55からのところは、 docker-compose upをバックグラウンドで実行してくれることについて説明がありますので、 必要な方は是非参考してみてください。 DB作成 $ docker-compose run web rails db:create そして $ docker-compose up 無事に環境構築できたそうですね!! Dockerの環境でAPIモードでAPIを作ってみよう この記事の参考で、Docker内でAPIを作っていきます。 テスト環境 まずはテスト環境を先に用意していきます。今回はRspecを使います。 Gemfile group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] #⇩追加 gem 'rspec-rails' end そしてdocker-compose buildでbundle install 次はこちらの記事:dockerでよく使うコマンド一覧【Rails】で学んだDockerのコマンドで Rspecのインストールを行います。 $ docker-compose run web bundle exec rails g rspec:install それでspecファイルが生成されます。 モデル.コントローラの作成 では今回は簡単なタスク機能のアプリを作っていきます。 $ docker-compose run web bundle exec rails g model post title:string content:text $ docker-compose run web bundle exec rails g controller posts $ docker-compose run web bundle exec rails db:create $ docker-compose run web bundle exec rails db:migrate ルーティングの設定 config/routes.rb Rails.application.routes.draw do namespace 'api' do namespace 'v1' do resources :posts end end end コントローラの設定 ルートで設定した名前空間に合わせてディレクトリの構成を以下のようにします。 controllers/api/v1/posts_controller.rb module Api module V1 class PostsController < ApplicationController before_action :set_post, only: [:show, :update, :destroy] def index posts = Post.order(created_at: :desc) render json: { status: 'SUCCESS', message: 'Loaded posts', data: posts } end def show render json: { status: 'SUCCESS', message: 'Loaded the post', data: @post } end def create post = Post.new(post_params) if post.save render json: { status: 'SUCCESS', data: post } else render json: { status: 'ERROR', data: post.errors } end end def destroy @post.destroy render json: { status: 'SUCCESS', message: 'Deleted the post', data: @post } end def update if @post.update(post_params) render json: { status: 'SUCCESS', message: 'Updated the post', data: @post } else render json: { status: 'SUCCESS', message: 'Not updated', data: @post.errors } end end private def set_post @post = Post.find(params[:id]) end def post_params params.require(:post).permit(:title,:content) end end end end 初期データ作成 今回はseedで作ってみます。 seedの書き方はこの記事の参考しています→railsのseedの書き方いろいろ config/db/seeds 15.times do |i| Post.create!( title: "title#{i+1}", content: "テキスト#{i+1}" * 10 ) end seed書いたら $ docker-compose run web rails db:seed エラーが出ないので、無事にできたようです。 postmanを使用して動作の確認 データはseedで生成したので Railsのサーバーを動かしてみます。 $ docker-compose up 次はPostmanを開きます。 GET まずはGETの方にhttp://localhost:3000/api/v1/posts 、もしくは http://0.0.0.0:3000/api/v1/posts と記述していきます。 下の方にidの1〜15番のデータを取得することができました。 今度はidを指定します。 POST 次はデータ作成してみましょう。 JSONのデータ形式で渡します。 Sendするとちゃんとid16が表示されました。 PUT 今回はURLをidを16に指定します http://0.0.0.0:3000/api/v1/posts/16 登録したデータをupdate更新してみます。 PUTの選択とJSON形式の設定を忘れないように DELETE 最後に削除(Destroy)してみます。 同じURLをidを16に指定します http://0.0.0.0:3000/api/v1/posts/16 DELETEの選択で実行すれば、 無事に削除できたようですね まとめ 以上、Dockerの環境構築+RailsのAPIモードのまとめでした。 今回Rspecのテストは書かないのですが、 こちらの記事:【Rails】APIテストの書き方がありますので、興味がある方はご参考ください もし内容の誤りがありましたら、ご指摘いただければ幸いです。 最後まで読んでいただき、ありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails6】ActiveRecord::RecordInvalid: Validation failed:の対処法

症状 rails db:seedを実施したところ下記エラーが表示されてしまい、テストデータの作成ができませんでした。(Rails6.0.3) ターミナル bundle exec rails db:seed rails aborted! ActiveRecord::RecordInvalid: Validation failed: Foods is invalid C:/Users/ユーザー名/environment/プロジェクト名/db/seeds.rb:23:in `block in <main>' C:/Users/ユーザー名/environment/プロジェクト名/db/seeds.rb:8:in `times' C:/Users/ユーザー名/environment/プロジェクト名/db/seeds.rb:8:in `<main>' bin/rails:4:in `<main>' Tasks: TOP => db:seed (See full trace by running task with --trace) seeds.rb 3.times do |n| restaurant = Restaurant.new( name: "testレストラン_#{n}", fee: 100, time_required: 10, ) 12.times do |m| restaurant.foods.build( name: "フード名_#{m}", price: 500, description: "フード_#{m}の説明文です。" ) end restaurant.save! end restaurant class Restaurant < ApplicationRecord has_many :foods end food class Food < ApplicationRecord belongs_to :restaurants end エラーメッセージを見ると、Foodsで何かしらエラーが発生してそうです。 解決方法 belongs_toの後に、sをつけていたためエラーが起きていたようです。 1対nの関係で、1のほうが複数形になると、validateエラーになってしまうようです。 restaurant class Food < ApplicationRecord belongs_to :restaurant end 参考 【Rails 5】ActiveRecord::RecordInvalid: Validation failed: Hoge must exist https://qiita.com/jagio/items/5510917f80ca130cbd33
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby】クラスとインスタンスの違い

今回はRubyにおけるクラスとインスタンスの違いを整理します。 結論:クラスは設計図・仕様、インスタンスは個別のデータ クラスは設計図・仕様、インスタンスはクラスを元に生成される個別具体的なデータです。 逆に言えば、クラスは個別具体的なデータを生成するための設計図・仕様とも言えますね。 クラスとは クラスは、個別のデータ(値)の生成するための設計図・使用を指します。 この設計図・仕様では共通の属性と処理(メソッド)を定義します。 オブジェクト指向では、互いに関連するデータと、データを操作するメソッドを一つのオブジェクトと呼ばれる単位に一体化(カプセル化)して取り扱う。あるオブジェクトがどのようなデータとメソッドから作られるのかを定義した、言わば雛形にあたるものをクラスという。(IT用語辞典 e-Wordsより) たとえば「人クラス」という、人を作るための設計図を作るとします。 人には以下のような属性が与えられます。 名前 性別 年齢 身長 体重 これらをプロパティと言います。 また、人は以下のような動作をすることができます。 歩く ジャンプする 投げる しゃべる これらの動作(処理)を定義したものをメソッドと言います。 これらの属性や動作は人に関する共通の情報としてまとめたものをクラスと言います。 クラスで共通の情報をまとめ、個別の情報は各データごとに分けることで、アプリケーションサービスの開発・管理・保守がし易くなるという利点があります。 上記のとおり、クラスは共通の属性と処理を決めるだけで、個別のデータがありません。 つまり、具体的な人という姿を持っていません。 そこでインスタンスが登場します。 インスタンスとは インスタンスとは、クラスを元にして作られる個別具体的なデータのことです。 オブジェクト指向プログラミングで、クラス定義に基いてメモリ上にデータと手続きの集合として実体化されたオブジェクトのことをインスタンスという。クラスからインスタンスを生成することを「インスタンス化」(instantiation)という。(IT用語辞典 e-Wordsより) インスタンスは、クラスと異なり実体を持ちます。 先ほどの「人クラス」の例で、ぼく(yamaday0u)を作るとすると以下のようになります。 名前:yamaday0u 性別:男 年齢:27才 身長:165cm 体重:58kg これらは属性という、ぼくの基本情報で、必要に応じて「歩く」「ジャンプする」「投げる」「しゃべる」という動作(メソッド)を実行するわけです。 そして、属性はメソッドの中に組み込むことができます。 「自己紹介する」というメソッドを定義して実行すれば、以下のように動作することができます。 human.rb class Human def initialize(name) @name = name #属性(プロパティ)を定義 end def introduce #自己紹介のメソッドを定義 puts "ぼくの名前は#{@name}です" #メソッドの中に属性(プロパティ)を入れている end end yamada = Human.new("yamaday0u") #インスタンスを生成 yamada.introduce #自己紹介のメソッドを実行 ターミナル $ ruby human.rb #human.rbを実行 ぼくの名前はyamaday0uです #実行結果 まとめ 冒頭の、「クラスは設計図・仕様、インスタンスはクラスを元に生成される個別具体的なデータ」、という結論の意味がつかめたでしょうか? 最後のところで使用しているHuman.newやyamada.introduceのようなクラスメソッド、インスタンスメソッドについて過去に記事を投稿しているので、ご興味があれば読んでみてください。 関連投稿記事:【Ruby】クラスメソッドとインスタンスメソッド、クラス変数とインスタンス変数の違い(Qiita) 参考資料 【Ruby】クラスとかインスタンスについて改めて学習してみた(Qiita) クラス(IT用語辞典 e-Words) インスタンス(IT用語辞典 e-Words)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

非同期通信を使って簡単な投稿機能のアプリを作ってみる(Rails6)

※この記事はrails初学者の方に向けて書いたものです。間違った解釈などあればご指摘いただければ幸いです。 非同期通信とは? 非同期通信とは、コンピュータ間で送信者のデータ送信タイミングと受信者のデータ受信タイミングを合わせずに通信を行う通信方式である。 つまり、送信者と受信者の両方がオンラインである必要がなく、片方が接続しているだけで通信が成立する。 非同期通信の対義語として、同期通信というものがある。 分かりやすく言うと、、、 相手に要求を出したら、(相手からの応答を待たないで)さっさと次の処理を進めることができる通信と表現できる。 非同期通信では、相手に要求(リクエスト)を投げたら、応答(レスポンス)が返ってくるまで待ちません。 通信というのは基本的にキャッチボールです。 相手に「要求」を投げて、「応答」を受け取ります。 要求を投げてから応答を受け取るまでには時間がかかります。要求の投げ方は2種類存在します。 1,応答が来るまで、何も処理を行わず待つ→同期通信 2,応答を待たずに、処理を進める→非同期通信 非同期通信を使用するメリット メリット 説明 操作性の向上 サーバーが処理を行っている間に操作できる パフォーマンスの向上 ページの一部のみ更新するため、通信量の削減が可能 機能を実現しやすくなる 編集中の文章を一時保存するなどの機能をユーザーに意識させることなく実装することができる バックエンドエンジニアを目指す際のポートフォリオに積極的に実装することで「サーバーへの負担」や「UXの向上」にまで気を遣っているのだというアピール材料になるそうなので今一度その概要をアウトプットしたいと思います。ここでは簡単な投稿アプリを作って動作確認をしながら非同期通信の基本的流れをおさらいしたと思います。 開発環境 ・Rails: 6.1.3.1 ・ruby: 2.7.2 ・jquery: 3.6.0 手順 1, アプリの準備 $ rails new ajax_sample $ cd ajax_sample $ rails g controller posts index $ rails g model Message title:string content:text $ rails db:migrate 2,bootstrapの導入 以下の記事を参考に導入しました。今回は本筋からそれてしまうので割愛します。 ・Rails 6にjQueryとBootstrapを入れる 3,postsコントローラの設定 posts_controller.rb class PostsController < ApplicationController def index @posts = Post.all @post = Post.new end def create Post.create(post_params) @posts = Post.all # redirect_toの代わりに入れる end private def post_params params.require(:post).permit(:title, :content) end end 4,ルーティングの設定 routes.rb Rails.application.routes.draw do root 'posts#index' resources :posts, only: [:index, :create] end 5,viewの作成 まずは投稿一覧画面に各記事を表示する部分テンプレートの_post.html.erbと投稿用のフォームとしてモーダルを配置します。 views/posts/index.html.erb <div class="container mt-5"> <div class="row"> <div class="col-3 sidebar"> <button type="button" class="btn btn-primary w-100" data-toggle="modal" data-target="#exampleModal"> 投稿 </button> </div> <div class="col-9 sidebar posts"> <%= render 'posts', posts: @posts %> </div> </div> </div> <!-- Modal --> <div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="exampleModalLabel">新規投稿</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">&times;</span> </button> </div> <%= form_for @post, remote: true do |f| %> <div class="modal-body"> <div class="form-group"> <%= f.label :title, "タイトル" %> <%= f.text_field :title, class:"form-control" %> </div> <div class="form-group"> <%= f.label :content, "本文" %> <%= f.text_area :content, class:"form-control" %> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">閉じる</button> <%= f.submit "投稿する", class:"btn btn-primary" %> </div> <% end %> </div> </div> </div> モーダルのデザインはbootstrapのチートシートから持ってきたものにアレンジを加えただけです。 ・Modal - Bootstrap 4.2 - 日本語リファレンス 次にindex.html.erbに配置した部分テンプレートを用意します。この中にはpostsテーブルの各要素を表示するためにeachメソッドを使用しています。 views/posts/_posts.html.erb <% posts.each do |post| %> <div class="card mb-1"> <div class="card-body"> <p class="card-text"><%= post.title %></p> <p><%= post.content %></p> </div> </div> <% end %> これで投稿一覧はひとまず表示することはできますが、このままでは非同期処理にはできません。同期処理であればpostsコントローラにredirect_toメソッドを記述して再度投稿一覧を描画し直せばいいのですが今回はページ遷移をなくしたいので追加でjavascriptのファイルが必要です。 views/posts/create.js.erb $("textarea").val(""); $("input").val(""); $('#exampleModal').modal('hide') $('.posts').html("<%= escape_javascript(render 'posts', posts: @posts) %>") 上記のファイルでは投稿フォームのリセット、モーダルウィンドウの終了、新しい投稿一覧の書き換えを行っています。 終わりに 非同期通信は実装できれば画面遷移でユーザーにストレスを与えることもサーバーに必要以上に負荷をかけることなくサービスを運用できるため重宝されているそうです。まだまだ私も理解が追いついていない部分も多いので今後も積極的に実装していこうと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Apple M1でJekyllを使えるようにする

Apple M1でJekyllを動かすのに少し手間取ったのでここに対処法書きます。 自分はrubyの環境も無かったのでその作り方も載せておきます。 homebrewインストール ターミナルを起動し、以下叩きます。 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/kohei/.zprofile rbenvをインストール brew install rbenv /Users/(ユーザ名)/.zshrc に以下追加します。 eval "$(rbenv init -)" 以下コマンドでrbenvのバージョンが表示されればOK. exec $SHELL -l rbenv --version rubyをインストール 以下にて、インストール可能なrubyのバージョンを確認します。 rbenv install --list 以下のように表示されます。 自分は2.7.3のバージョンをインストールしました。 2.5.9 2.6.7 2.7.3 3.0.1 jruby-9.2.17.0 mruby-2.1.2 rbx-5.0 truffleruby-21.0.0 truffleruby+graalvm-21.0.0 Only latest stable releases for each Ruby implementation are shown. Use 'rbenv install --list-all / -L' to show all local versions. 以下にてインストール、デフォルトのバージョンを2.7.3にしました。 rbenv install 2.7.3 rbenv global 2.7.3 exec $SHELL -l ruby --version jekyllを起動 Gemfile.lockがある場合はそれを削除し、以下実行。 色々試したのですが、依存gemのバージョン固定では実行できず。。 sudo gem install bundler jekyll bundle exec jekyll serve メモから復元した情報なので、ちょっと不足あるかもしれません。。。 参考程度にしていただけるとありがたいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]ActiveHash使用の際のエラー(undefined method `current_scope' )

はじめに とてもしょーもないミスで1時間も浪費しましたので、二度と内容にこちらに備忘としてアウトプットいたします。 発生したエラー 以下のようなエラーが出ました。最初は誤字等を睨んだのですが、、そんなことはなく、、 解決方法 こちらの一文を書くことを忘れていました。 game.rb class Game < ApplicationRecord #この一文 extend ActiveHash::Associations::ActiveRecordExtensions  belongs_to :level; ActiveHashを用いて、belongs_toを設定するには、 extend ActiveHash::Associations::ActiveRecordExtensionsと記述してmoduleを取り込む必要がありました。 終わりに エラーが出たときは、基礎の基礎から立ち返ることをここに誓います(笑) 時間は大切に。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on rails 結合テスト

勉強用に残して置きたかったやつです 初心者なので間違ってる箇所があると思います。 結合テストコード 結合テストコードは、ユーザーがたどる一連の流れを確認するもの。 System Spec System Spec(システムスペック)は結合テストコードを記述するための仕組みのことを言います。大枠の記述はこれまでのRSpecと変わりません。 System Specを記述するためには、CapybaraというGemを用います。これはすでにデフォルトでRuby on Railsに搭載されています。 すなわち導入済みなのでそのままいけます!! テストコードを書くためのファイルを用意しよう 以下のコマンドを実行して、ユーザーに関する結合テストコードを書くためのファイルを生成しましょう。 % rails g rspec:system users 新規登録がうまくいくときのテストコードを書こう visit 〇〇_pathのように記述すると、〇〇のページへ遷移することを表現できます。 it '正しい情報を入力すればユーザー新規登録ができてトップページに移動する' do # トップページに移動する visit root_path # トップページにサインアップページへ遷移するボタンがあることを確認する # 新規登録ページへ移動する # ユーザー情報を入力する # サインアップボタンを押すとユーザーモデルのカウントが1上がることを確認する # トップページへ遷移したことを確認する # カーソルを合わせるとログアウトボタンが表示されることを確認する # サインアップページへ遷移するボタンや、ログインページへ遷移するボタンが表示されていないことを確認する end expect(page).to have_content('X')と記述すると、visitで訪れたpageの中に、Xという文字列があるかどうかを判断する. it '正しい情報を入力すればユーザー新規登録ができてトップページに移動する' do # トップページに移動する visit root_path # トップページにサインアップページへ遷移するボタンがあることを確認する expect(page).to have_content('新規登録') # 新規登録ページへ移動する # ユーザー情報を入力する # サインアップボタンを押すとユーザーモデルのカウントが1上がることを確認する # トップページへ遷移したことを確認する # カーソルを合わせるとログアウトボタンが表示されることを確認する # サインアップページへ遷移するボタンや、ログインページへ遷移するボタンが表示されていないことを確認する end fill_in 'フォームの名前', with: '入力する文字列'のように記述することで、フォームへの入力を行うことができます フォームの名前は検証ツールで調べよう it '正しい情報を入力すればユーザー新規登録ができてトップページに移動する' do # トップページに移動する visit root_path # トップページにサインアップページへ遷移するボタンがあることを確認する expect(page).to have_content('新規登録') # 新規登録ページへ移動する visit new_user_registration_path # ユーザー情報を入力する fill_in 'Nickname', with: @user.nickname fill_in 'Email', with: @user.email fill_in 'Password', with: @user.password fill_in 'Password confirmation', with: @user.password_confirmation # サインアップボタンを押すとユーザーモデルのカウントが1上がることを確認する # トップページへ遷移したことを確認する # カーソルを合わせるとログアウトボタンが表示されることを確認する # サインアップページへ遷移するボタンや、ログインページへ遷移するボタンが表示されていないことを確認する end 続いて、「サインアップボタンを押すとユーザーモデルのカウントが1上がることを確認する」へ取り組みます。まずは「サインアップボタンを押すと」の部分を考えましょう。この時に使用するものがfind().clickです。 find('クリックしたい要素').clickと記述することで、実際にクリックができます find('input[name="commit"]').clickという記述になります。 続いて、「ユーザーモデルのカウントが1上がる」をどうやるかその時に用いるものが、changeマッチャです。 expect{ 何かしらの動作 }.to change { モデル名.count }.by(1)と記述することによって、モデルのレコードの数がいくつ変動するのかを確認できます。 そして、{ 何かしらの動作 }の部分にfind('input[name="commit"]').clickが入ります。 it '正しい情報を入力すればユーザー新規登録ができてトップページに移動する' do # トップページに移動する visit root_path # トップページにサインアップページへ遷移するボタンがあることを確認する expect(page).to have_content('新規登録') # 新規登録ページへ移動する visit new_user_registration_path # ユーザー情報を入力する fill_in 'Nickname', with: @user.nickname fill_in 'Email', with: @user.email fill_in 'Password', with: @user.password fill_in 'Password confirmation', with: @user.password_confirmation # サインアップボタンを押すとユーザーモデルのカウントが1上がることを確認する expect{ find('input[name="commit"]').click }.to change { User.count }.by(1) # トップページへ遷移したことを確認する # カーソルを合わせるとログアウトボタンが表示されることを確認する # サインアップページへ遷移するボタンや、ログインページへ遷移するボタンが表示されていないことを確認する end 次にトップページであることを確かめたいです。その時に使用するものが、current_pathです。 文字通り、現在いるページのパスを示します。expect(current_path).to eq(root_path)と記述すれば、今いるページがroot_pathであることを確認できます。 it '正しい情報を入力すればユーザー新規登録ができてトップページに移動する' do # トップページに移動する visit root_path # トップページにサインアップページへ遷移するボタンがあることを確認する expect(page).to have_content('新規登録') # 新規登録ページへ移動する visit new_user_registration_path # ユーザー情報を入力する fill_in 'Nickname', with: @user.nickname fill_in 'Email', with: @user.email fill_in 'Password', with: @user.password fill_in 'Password confirmation', with: @user.password_confirmation # サインアップボタンを押すとユーザーモデルのカウントが1上がることを確認する expect{ find('input[name="commit"]').click }.to change { User.count }.by(1) # トップページへ遷移したことを確認する expect(current_path).to eq(root_path) # カーソルを合わせるとログアウトボタンが表示されることを確認する # サインアップページへ遷移するボタンや、ログインページへ遷移するボタンが表示されていないことを確認する end find('ブラウザ上の要素').hoverとすることで、特定の要素にカーソルをあわせたときの動作を再現できます。 it '正しい情報を入力すればユーザー新規登録ができてトップページに移動する' do # トップページに移動する visit root_path # トップページにサインアップページへ遷移するボタンがあることを確認する expect(page).to have_content('新規登録') # 新規登録ページへ移動する visit new_user_registration_path # ユーザー情報を入力する fill_in 'Nickname', with: @user.nickname fill_in 'Email', with: @user.email fill_in 'Password', with: @user.password fill_in 'Password confirmation', with: @user.password_confirmation # サインアップボタンを押すとユーザーモデルのカウントが1上がることを確認する expect{ find('input[name="commit"]').click }.to change { User.count }.by(1) # トップページへ遷移したことを確認する expect(current_path).to eq(root_path) # カーソルを合わせるとログアウトボタンが表示されることを確認する expect( find('.user_nav').find('span').hover ).to have_content('ログアウト') # サインアップページへ遷移するボタンや、ログインページへ遷移するボタンが表示されていないことを確認する end spanクラスは他の要素でも使っているので親要素から見つける 最後に、「サインアップページへ遷移するボタンや、ログインページへ遷移するボタンが表示されていないことを確認する」へ取り組みます。 存在しない事を確かめるために、have_no_contentを用います。 it '正しい情報を入力すればユーザー新規登録ができてトップページに移動する' do # トップページに移動する visit root_path # トップページにサインアップページへ遷移するボタンがあることを確認する expect(page).to have_content('新規登録') # 新規登録ページへ移動する visit new_user_registration_path # ユーザー情報を入力する fill_in 'Nickname', with: @user.nickname fill_in 'Email', with: @user.email fill_in 'Password', with: @user.password fill_in 'Password confirmation', with: @user.password_confirmation # サインアップボタンを押すとユーザーモデルのカウントが1上がることを確認する expect{ find('input[name="commit"]').click }.to change { User.count }.by(1) # トップページへ遷移したことを確認する expect(current_path).to eq(root_path) # カーソルを合わせるとログアウトボタンが表示されることを確認する expect( find('.user_nav').find('span').hover ).to have_content('ログアウト') # サインアップページへ遷移するボタンや、ログインページへ遷移するボタンが表示されていないことを確認する expect(page).to have_no_content('新規登録') expect(page).to have_no_content('ログイン') end そして、テストコードを実行。 忘れないように書きました。 間違えてるところもあるかもしれません
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【初学者向け】Rubyにおける@nameとself.nameの違い 〜なぜ@なしで puts"#{name}"としてもちゃんと出力されるの?〜

概要 @nameとself.nameの挙動の違いをまとめます。 初学者の方向けの記事です。 以下のようなコードをたまに見かけることがありました。 class User attr_reader :name def initialize(name) @name = name end def introduce puts "#{name}です" #@がなくても参照できてる! end end user = User.new ("川上") user.introduce 出力結果 川上です 「introduceメソッドの中のnameはローカル変数なの??@が付いてないのに,なぜ値が入っているの?」 と思ってた謎が解けたので,まとめます。 結論 上記の"#{name}です"は,実は"#{self.name}です"の略。 self.nameは,値を参照するnameメソッド(ゲッターメソッド)を呼び出している。 nameメソッド(ゲッターメソッド)の戻り値は@nameなので,initializeメソッドで@nameに格納した値が返る。 (なんのことかサッパリですよね^^; 詳しくは後述します) それに対し,@nameはクラスの中で共有される変数。 同じ挙動をするように見えるけど,全くの別物。 @name(インスタンス変数)を使用する書き方 まず,よく見るインスタンス変数を使った書き方から見てみます。 @nameを使用する書き方 class User def initialize(name) @name = name end def introduce puts "#{@name}です" end end user = User.new ("川上") user.introduce 出力結果 川上です インスタンスを生成した際,initializeメソッド内で@nameに実引数の値川上がセットされます。 クラスの中ではインスタンス変数の値が保持されるので,introduceメソッド内の@nameの値も川上です。 こちらは問題なさそうです。 self.nameを使用する書き方 self.nameを使用する書き方 class User attr_accessor :name def initialize(name) self.name = name end def introduce puts "#{self.name}です" end end user = User.new ("川上") user.introduce 出力結果 川上です introduceメソッドの中だけでなく,initializeメソッドの中もself.nameとなっています。 すっかり忘れていたのですが,ProgateのRubyの演習ではこの形式で書かれているそうです。 (教えていただき見直してみると,確かにそうなっています。※2021年4月26日時点) ここで注意したいのが,さりげなくattr_accessor :nameと書かれている点です。 実は,この記述がない場合はエラーになってしまうんです。 もし,attr_accessor :nameがなかったらどうなるか試してみます。 self.nameを使用する書き方 class User # attr_accessor :name # コメントアウト def initialize(name) self.name = name end def introduce puts "#{self.name}です" end end user = User.new ("川上") user.introduce 実行してみると,以下のエラーが出ました。(2つのうちの1つ目) 出力結果 Traceback (most recent call last): 2: from user.rb:12:in `<main>' 1: from user.rb:12:in `new' user.rb:4:in `initialize': undefined method `name=' for #<User:0x00007f7eec13c348> (NoMethodError) name=メソッドが定義されていない,という内容ですね! self.name = はname=メソッド(セッターメソッド)を呼び出している では,name=メソッドを追加してみましょう。 ちなみにname=メソッド(セッターメソッド)は何かというと,@nameに値をセットするメソッドです。 self.nameを使用する書き方(セッターメソッドを追加) class User def initialize(name) self.name = name # 実はセッターメソッドを呼び出している end # セッターメソッドを追加 def name=(name) @name = name end def introduce puts "#{self.name}です" end end user = User.new ("川上") user.introduce これでもう一度実行すると,上記のエラーに関してはなくなります。 実は,initializeメソッドの中のself.name =はname=メソッド(セッターメソッド)を呼び出しています。 (self.name =,name=と両方イコールがついている点に注意してください) name=メソッドが定義されていないと,呼び出すことができないのでエラーになっていました。 self.name =がname(川上という値が入った変数)を実引数としてname=メソッドを呼び出す →@nameに川上という値がセットされる,という流れです。 では,この状態でもう一度実行してみましょう。 すると,次は以下のエラー(2つ目のエラー)が出ます。 出力結果 Traceback (most recent call last): 1: from user.rb:17:in `<main>' user.rb:12:in `introduce': undefined method `name' for #<User:0x00007fbcf209ff90 @name="川上"> (NoMethodError) Did you mean? name= 今度はnameメソッドが定義されていない,という内容です。 self.nameはnameメソッド(ゲッターメソッド)を呼び出している では,nameメソッド(ゲッターメソッド)を定義してみましょう。 nameメソッド(ゲッターメソッド)は@nameを戻り値とするメソッドです。 self.nameを使用する書き方(ゲッターメソッドを追加) class User def initialize(name) self.name = name # 実はセッターメソッドを呼び出している end # セッターメソッド def name=(name) @name = name end # ゲッターメソッドを追加 def name @name #戻り値 end def introduce puts "#{self.name}です" # 実はゲッターメソッドを呼び出している end end user = User.new ("川上") user.introduce これでエラーはなくなります。 出力結果 川上です introduceメソッドの中のself.nameはnameメソッド(ゲッターメソッド)を呼び出しています。 (こちらはイコールなしです) こちらも,メソッドが定義されていなかったので,呼び出すことができずエラーになっていました。 self.nameがnameメソッド(ゲッターメソッド)を呼び出す →@nameに格納されていた川上という値が戻り値としてself.nameに入る,という流れです。 セッターとゲッターをあわせてattr_accesorと書き換えることができる まず,セッターメソッドは以下のように書き換えることができます。(class User の直下) self.nameを使用する書き方(セッターメソッドを書き換え) class User attr_writer :name # 裏でセッターメソッドを呼び出す def initialize(name) self.name = name end # セッターメソッド # def name=(name) # @name = name # end # ゲッターメソッド def name @name end def introduce puts "#{self.name}です" end end user = User.new ("川上") user.introduce そして,ゲッターーメソッドは以下のように書くことができます。 self.nameを使用する書き方(ゲッターメソッドを書き換え) class User attr_writer :name # 裏でセッターメソッドを呼び出す attr_reader :name # 裏でゲッターメソッドを呼び出す def initialize(name) self.name = name end # セッターメソッド # def name=(name) # @name = name # end # ゲッターメソッド # def name # @name # end def introduce puts "#{self.name}です" end end user = User.new ("川上") user.introduce attr_writer :nameとattr_reader :nameをあわせてattr_accessor :nameと書くことができます。 これが「self.nameを使用したコード」に出てきた書き方になります。 self.nameを使用する書き方(attr_accessorに書き換え) class User attr_accessor :name # 裏でセッターとゲッターを呼び出す def initialize(name) self.name = name end # セッターメソッド # def name=(name) # @name = name # end # ゲッターメソッド # def name # @name # end def introduce puts "#{self.name}です" end end user = User.new ("川上") user.introduce 出力結果 川上です 【補足1】selfはインスタンス自身を表している では,「このselfって何?」というところなんですが,selfはuserというインスタンスを表しています。 クラスの外でインスタンスメソッドを呼び出す際,例えば user.introduce というように,インスタンス.インスタンスメソッドという形で書きますが,クラスの中ではインスタンス部分をself(インスタンス自身)と書きます。 クラスの中で self.name と書くと,userというインスタンス自身に対してnameメソッドを呼び出していることになります。 言われてみれば「なるほど!」と納得できますが,なかなか見かけないので馴染みがありませんでした^^; 【補足2】self.nameのself.は省略することができる self.nameのself.は,意味が曖昧にならない限り省略することができます。 ただし,self.name =のself.は省略することができません。(ローカル変数nameへの代入とみなされます) self.を省略する書き方 class User attr_accessor :name def initialize(name) self.name = name # self.を省略できない end def introduce puts "#{name}です" # self.を省略できる end end user = User.new ("川上") user.introduce ちなみに,私が疑問に思っていた冒頭のコードは,@nameへの値のセットはセッターを介さずに行い,値を参照する時だけゲッターを介している形でした。 値を参照する時だけself.nameを使用する書き方 class User attr_reader :name #ゲッターのみ def initialize(name) @name = name end def introduce puts "#{name}です" # self.を省略している end end user = User.new ("川上") user.introduce 謎が解けてスッキリ! (ただ,この書き方をされている場合,意図してこうされているわけではなく,「@をつけ忘れているけど,他の目的でattr_reader :nameと書いてるから偶然参照できている」ケースが多いのかな,と思いました) 【補足3】@nameとself.nameは全く異なるもの とても極端でありえない例ですが,attr_readerを使わずにnameメソッドを書くとき,メソッドの中が def name @name end ではなく,例えば以下のような値だった場合, def name 1000 end self.nameでnameメソッドを呼ぶと 1000 が戻り値として返ります。 このように,純粋な挙動を見ると,self.nameは単に「nameメソッドを呼ぶ」という処理をするだけで,メソッドの中身は関係ありません。 (同様に,self.name =も,全く異なる名前のインスタンス変数(たとえば@age)に値をセットすることができてしまいます) attr_accessorを使用すれば上記のようにメソッドの中身がおかしくなることはありませんが,ゲッターメソッド(もしくはセッターメソッド)を呼ぶ,という挙動自体は変わりません。 インスタンス変数を使用する場合は,@nameを直接定義するし,一度定義されたら@name自身が値を保持します。 両者は全くの別物です。 【補足4】同じ使用法であれば,@nameを使用したほうが良い クラスの中で共有する値をセットしたり参照する場合は,普通に@nameを使用したほうが良いです。 self.name =で値をセットしたりself.nameで値を取得する場合,それぞれセッター,ゲッターを呼び出す必要があり,その分の処理が増えるからです。 逆に,self.nameを使用したほうが良いケースが思い浮かばず・・ありましたらぜひ教えていただけたら幸いです?‍♀️ 参考 Progate RubyⅣ (有料部分なのでURL添付なし) ドットインストール Ruby入門 #20 アクセサを使ってみよう (同上) やんばるエキスパート 講座 終わりに 以上,私自身が疑問に思っていた部分だったのでまとめました。 もし内容に間違いがありましたら,ご指摘いただけますと幸いです☺️
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

form_withのデフォルト設定でハマった話

実装環境 Ruby 2.6.5 Rails 6.0.3.5 発生した不具合 form_withを用いた新規登録ページのバリデーションによるエラー表示ができなくなった。 問題点 # 新規登録のviewでの記述 <%= form_with model: @user, url: user_registration_path, class: "sign-up-form", id: 'form' do |f| %> 解決 早速答えですが、form_withはデフォルトだとAjax処理を行うという仕様で引っ掛かっていました。 これを踏まえてviewの記述を見れば分かる通りlocal: trueが抜けているためAjax処理を行なっています。 そのためterminalでもProcessing ~ as JSとある様にJavaScriptでの処理が行われています。 非同期に対応したコントローラーを作成していないのにAjax処理をしたところでデータは受け取れないし、返ってくる訳無いです。はい。 そしてコントローラーでモデルへアクセスする事も無いため当然バリデーションも動かないということになります。 振り返り viewの記述の確認は何度もしたつもりでしたが、完全に抜け落ちていた様です。思い込みって怖い... それによりterminalのJS表記に気を取られ、Javascriptの実装を片っ端から消してみたり、gitでフロント実装前まで巻き戻してみたり、あっちこっち飛び回る泥沼状態でした。挙句正常に動作するのがフロント実装前のデータだったがためにもう諦めて別のアプリ作成まで考える始末でした。 使用するものは公式ドキュメントでしっかり仕様を把握してから使うことを改めて肝に命じた出来事になりました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【個人開発】ポモドーロテクニックとTodoリストを組み合わせた時間管理アプリを作りました

はじめに ポモドーロテクニックxTodoリストを組み合わせた作業効率化アプリ「pomotto」をリリースしました! 25分集中して5分休憩するサイクルを繰り返すことでメリハリをつけて集中力を高めるポモドーロ・テクニック。 Todoリストと掛け合わせたアプリケーションが意外となかったことがきっかけで作り始めました。 一週間作業時間のログが残るので自分の勉強ペースも確認することができます。 自分が欲しかった機能を詰めて作ったものなので、誰かのもくもく勉強や作業のお供になればとても嬉しいです。 サービス概要 pomotto ターゲット層 自宅などで1人でもくもく勉強や作業をしている方。 ユーザーが抱える問題 長時間作業をしていると休憩時間をとるタイミングを見失う。 休憩するとつい長々と休憩してしまう。 集中力が途切れやすく、作業効率が下がってしまう。 自分がどの作業にどれくらい時間をかけたのか見直したい。 上記の問題を解決するために「pomotto」をリリースしました。 使い方 タスクを作成 「タスクを作成」ボタンからやることを書きます。 作成ボタンをクリック ポモドーロタイマースタート タスクごとにある「▶︎」ボタンをクリックしてタイマーをスタート。 すると25分のタイマーモーダルが表示されます。 25分経過すると音が鳴り、完了ボタンが表示される仕組みになっています。 完了ボタンをクリックするとタスク詳細ページのグラフに25分加算されます。 ポモドーロ完了後は5分休憩タイマーが表示されます。 経過時間を確認 プロフィールページで一週間の作業時間を確認できるようになっています。 タスク詳細ページでも一週間での経過時間を確認できます。 使用技術 rails 6.0.3 ruby 2.7.2 Vue.js vuetify bootstrapvue axios(API) Vuex Vee-validate Vue-router Firebase storage(音楽ファイル管理) 主要gem sorcery(ログイン認証) vue-cahrtkick(グラフ) rspec-rails(テスト) meta-tags(メタタグ) 工夫したところ UI/UX なるべく直感的に操作できるように実装しました。 タイマーモーダルを閉じても小さなタイマーブロックを表示したり、タイマー完了ボタンを押したら休憩タイマーを表示させるなど、なるべく同一ページで動くように実装しています。 実際にユーザーに使っていただき、操作がわかりにくかったところなどを修正しました。 ・チェックリストでタスク完了が分かりづらい →チェックボックスをボタンに改良することで分かりやすくしました。 ・ タスク締め切り日を入力しないとタスクが作成できないということがわかりづらい →デフォルトで入力日を設定しておくことで改善 Vue.jsを導入 タイマーを使ったアプリケーションを実装するにあたって、Railsのみでは実装できる機能に限界を感じたため、Vue.jsを導入しました。 Railsのみに比べてブラウザ上での画面の動きがスムーズになるので導入して本当に良かったと感じています。 アプリで望む未来 自分もどうしても長時間作業を続けていくとだれてしまったり休憩時間とのメリハリがつけられなくなってしまったりしてしまっていました。そのときにポモドーロ・テクニックと出会い、やる気がない時でもメリハリをつけて勉強できるようになりました。 正直自分自身が「pomotto」を一番使っていますが、このアプリで長時間もくもく作業する人の手助けになればいいなと願っております。 ポートフォリオを作る上で気を付ければよかったこと テストは機能ごとに毎回書く 機能をまとめて実装してからテストをまとめて書こうとしたのですが、まとめて書くと実装したことを遡って書かないといけないためかなり大変でした。 テストは機能ごとに一つずつ確実に書いていくことが一番やりやすいです。急がば回れというのはこのことですね。 完璧を求めずにフィードバックを貰うこと(MVP開発) まだ未経験のうちに完璧を求めて1人で長い間試行錯誤してしまっていましたが、最低限の機能を実装して実際に使っていただいた方が様々な意見がもらえる上に自分では思いつかないようなアイデアを頂いたりすることもあったのでMVP開発は今後意識して開発していこうと考えました。 今後の改善に向けて タイマー 現在、ブラウザのローカルストレージにてタイマーの経過時間を管理しています。 こちらのタイマーの経過時間をバックエンド側でDBで管理したいと考えております。 テーブル設計予定図 上記の仕様に変更した上での改善したい点 - タイマーを途中で止められるように設計 - タイマー実行中に実行中のタスクを削除したらタイマーを止められない問題を改善 レスポンシブデザイン 現状、PCでのみ画面デザインが適用されるようになっていますが今後はスマホでも使用できるように画面比率の調整を行っていきたいです。 ブラウザを少し縮小してしまうとレイアウトが崩れてしまうのでその部分も直していきたいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

オリジナルアプリ開発【ユーザー視点で考える】

エンジニア転職をするにあたって、転職先の企業へのアピールポイントになるポートフォリオ作成(オリジナルアプリ開発)をしていきます。 オリジナルアプリのペルソナを考える ペルソナとはマーケティングの用語で、「サービスを使用するユーザー」のことです。 似た言葉に「ターゲット」などがありますが、ペルソナはそれらよりも詳細に「サービスを使用するユーザー」を決めます。 年齢層や、職業。性別や、現在の境遇などまで決めることで、よりリアルに使用者の目線でサービスを考案できます。 設定方法 性別・年齢 職業 趣味 日頃の生活 ペルソナの課題を洗い出し、解決する機能を考える(ユーザーストーリー) ユーザーストーリーとは、「ペルソナの課題に対して、どのような機能で解決していくのか」を明確にしたものです。 ペルソナが感じるであろう課題を、以下のようにテーブル形式で洗い出します。 この作業を行わないと、「思いついた機能をとりあえず実装する」という開発になり非効率です。 解決したい課題 なぜその課題解決が必要なのか 課題を解決する実装の内容 まとめ ペルソナとユーザーストーリーを詳細に考えることで、後々に非効率な開発にならなくて済みますが、 最初はざっくりと考え作っていくうちに修正を加えていく感じで良いと思います。 じゃないと、明確に『こんなアプリを作りたい!!』というイメージがない人は、ペルソナとユーザーストーリーを考える時点で、 時間が掛かり過ぎてしまい早々に挫折なんてこともあるかもしれないので、、、。 次回は、テーブル設計について書きたいと思います。 ではでは!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails 勉強日記 1日目(4/23)

内容 Railsの学習の予定を立てた。 メモ Rails(Ruby on Rails)を段階的に学んでいくための予定を以下でまとめる。 目標 簡単なWebアプリケーションを作れるレベルになる 自分のブログを構築する 現状 HTMLやCSSを読むことはできるが、実際に書いたことはほとんどない Rubyも雰囲気はわかるが、実際に書いたことはほとんどない JavaScriptは全くわからない Railsはチュートリアルの初めの方だけやったことがある 段階 HTML、CSS、Ruby、JavaScript、Railsに慣れる Progateを数回やる 段階的にそれぞれの技術のレベルを上げる Rails Girlsを進める Railsチュートリアルを進める 目標となる物を作る (目標の通り)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

sketchupでruby その16

概要 sketchupでrubyやってみた。 rotation使ってみた。 写真 サンプルコード def kai model = Sketchup.active_model entities = model.active_entities unit = 10 p = Array.new p[0] = ORIGIN p[1] = [unit, 0, 0] p[2] = [unit, unit, 0] p[3] = [0, unit, 0] group = entities.add_group face = group.entities.add_face p face.reverse! if face.normal.z < 0 face.pushpull unit * 2 rot = Geom::Transformation.rotation [0, 0, 0], [0, 1, 0], 45.degrees group.transform! rot end 以上。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

sketchupでruby その15

概要 sketchupでrubyやってみた。 translation使ってみた。 写真 サンプルコード def ido model = Sketchup.active_model entities = model.active_entities unit = 10 p = Array.new p[0] = ORIGIN p[1] = [unit, 0, 0] p[2] = [unit, unit, 0] p[3] = [0, unit, 0] group = entities.add_group face = group.entities.add_face p face.reverse! if face.normal.z < 0 face.pushpull unit trans = Geom::Transformation.translation [10, 0, 0] group.transform! trans end 以上。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

sketchupでruby その14

概要 sketchupでrubyやってみた。 scaling使ってみた。 写真 サンプルコード def bai model = Sketchup.active_model entities = model.active_entities unit = 10 p = Array.new p[0] = ORIGIN p[1] = [unit, 0, 0] p[2] = [unit, unit, 0] p[3] = [0, unit, 0] group = entities.add_group face = group.entities.add_face p face.reverse! if face.normal.z < 0 face.pushpull unit scale = Geom::Transformation.scaling Geom::Point3d.new(0, 0, 0), 2, 2, 2 group.transform! scale end 以上。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

草野球の出欠確認Webアプリを作ろう! part.1

これから作っていく簡単なWebアプリの作成メモ(自分の備忘)です。 自分用なのであまり凝りすぎないように書いていきたい。 環境などメモ ・WSLのUbuntu(20.04.2 LTS (Focal Fossa)) ・Ruby on Rails(ruby 3.0.1p64 / Rails 6.1.3.1) ・PostgreSQL(psql (PostgreSQL) 12.6 (Ubuntu 12.6-0ubuntu0.20.04.1)) 今回やったこと 環境構築 DB関連 以下の記事を参考にした。 Windows10のWSL(Ubuntu)にPostgreSQLをインストールしたときのメモ Rails環境構築 以下の記事を参考にした。 [Rails] Windows10 で WSL を使って Rails 環境を構築したときのメモ ※Yarnをインストールしないとエラーになったのでバージョンによっては注意が必要。 Rails6 開発時につまづきそうな webpacker, yarn 関係のエラーと解決方法 Rails初期セットアップ 以下は前述の手順と被りもあるが一応書いておく。 $ bundle install $ rails new SampleApp $ bin/rails db:create $ bin/rails db:migrate $ bin/rails s 機能作成 Userモデルの作成 以下の記事を参考にした。 Rails「ユーザーのモデルを作成する」 Userコントローラーの作成 以下の記事をコントローラー生成時に参考にした。 Rails generate の使い方とコントローラーやモデルの命名規則 $ rails g controller Users index show new create edit update delete ルートファイルを編集した。 routes.rb Rails.application.routes.draw do # ルート root "users#index" # Users resources :users end viewsにユーザー一覧を追加した。 users/index.html.erb <h1>メンバーの一覧</h1> <% if @users.empty? %> <div><%= "表示できるメンバーがいません。" %></div> <% else %> <table align="center"> <thead> <tr> <th>ユーザー名</th> <th>メールアドレス</th> </tr> </thead> <tbody> <% @users.each do |lst| %> <tr> <td><%= lst.name %></td> <td><%= lst.email %></td> </tr> <% end %> </tbody> </table> <% end %> コントローラーのindexアクションにUserモデルの値を渡すよう編集する。 controllers/users_controller.rb def index @users = User.all end ※初回動作確認時にrails serverは再起動しておくといいかも(bycryptのbundleのタイミング次第ではエラーになる) このあと、コンソール経由でユーザーを登録して動作確認した。 $ rails c $ User.new(name:"admin",email:"admin@example.com",password:"administrator",password_confirmation:"administrator").save テーブルのデザインが気に入らなかったので、Webから適当に探してきて試す(以下を参照)。 【コピペOK】CSSだけで実装できるおしゃれテーブルデザイン10つ ↑こんなふうになった。(テーブルサイズは画面幅の7割) 今回はここまで。 次回の記事>>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む