20211012のRailsに関する記事は20件です。

Docker × rails6 × mysql8.0 環境構築

windowsで開発進めていたがMacbook(intel)買ったので改めて環境構築した。 ファイルを作る dockerfile docker-compose.yml entrypoint.sh Gemfile Gemfile.lock(空) ファイルの書き方は公式ドキュメントを参考。 新しい技術にチャレンジする時ってqiitaに頼りがちだけど、とりあえず公式ドキュメント見てみる事を最近覚えました。 https://docs.docker.com/samples/rails/ ↓ railsアプリを作成 ターミナルで docker-compose run web rails new . --force --database=mysql (— force は既存のGemfileを上書きする) 実行。 railsアプリができる。 ↓ Gemfileやdocckerfileが更新されているので、 docker-compose build  (Gemfileやdocckerfileが更新されるたびにビルドする必要有) database.yml を修正 データベースの設定ファイルだよ default: &default adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: password host: db 下線部を追加、修正。 下線部はcompose.ymlで記載したやつと同じものにする↓ environment: MYSQL_ROOT_PASSWORD: password データベース作成 docker-compose run web rails db:create コンテナ起動 docker-compose up -d (-d はデタッチド・モード: バックグラウンドでコンテナを実行) ローカルサーバー立ち上がれば終わり。 デプロイはまた今度。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsチュートリアル第七章 flash

flash ユーザー登録フォームが実際に動くようになった。 それにより登録することができるよになった。 登録完了後に表示されるメッセージを二度目以降に表示させないようにさせる。 それを使うには flashという変数を使う。 ハッシュのように使う。 ユーザー登録ページにフラッシュメッセージを追加する app/controllers/users_controller.rb class UsersController < ApplicationController . . . def create @user = User.new(user_params) # 外部メソッドを使う if @user.save # 保存の成功をここで扱う。 flash[:success] = "Welcome to the Sample App!" # 成功時一度だけ表示されるメッセージ redirect_to @user # urlを指定して表示する # 保存成功したらurlを表示する else render 'new' # 保存に成功しなければnewアクションに移動する # 失敗したらまた戻る end end private #外部から使えないようにする def user_params # Usersコントローラの内部でのみ実行される # Web経由で外部ユーザーにさらされない params.require(:user).permit(:name, :email, :password, :password_confirmation) end end >> flash = {success: "It worked!", dager: "It failed." } # ハッシュを作った。 => {:success=>"It worked!", :dager=>"It failed."} >> flash.each do |key, value| # each文を作成 繰り返し ?> puts "#{key}" >> puts "#{value}" >> end success It worked! dager It failed. :successキーのメッセージが表示される場合、適用されるCSSクラスは次のようになります。 alert-success flash変数の内容をWebサイトのレイアウトに追加する app/views/layouts/application.html.erb <!DOCTYPE html> <html> <head> <title><%= full_title(yield(:title)) %></title> <%= render 'layouts/rails_default' %> <%= render 'layouts/shim' %> </head> <body> <%= render 'layouts/header' %> <div class="container"> <% flash.each do |message_type, message| %> <div class="alert alert-<%= message_type %>"><%= message %></div> <!--これがデータ送信成功時メッセージのためのHTML--> <!--message_typeにsuccess代入, message 成功時メッセージに代入--> <% end %> <%= yield %> <%= render 'layouts/footer' %> <%= debug(params) if Rails.env.development? %> <!--デバッグ情報はRailsの3つのデフォルト環境のうち、開発環境(development)だけで表示されるようになります--> </div> </body> </html> 演習 1.コンソールに移り、文字列内の式展開(4.2.1)でシンボルを呼び出してみましょう。例えば"#{:success}"といったコードを実行すると、どんな値が返ってきますか? 確認してみてください。 >> "#{:success}" => "success" 2.先ほどの演習で試した結果を参考に、リスト 7.28のflashはどのような結果になるか考えてみてください。 >> flash => {:success=>"It worked!", :dager=>"It failed."} #ハッシュのキーとバリュー >> "#{flash[:success]}" #ハッシュのキーでバリューを呼び出す => "It worked!" >> "#{flash[:dager]}" => "It failed."
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsチュートリアル第七章 ユーザー登録成功

ユーザー登録成功 新規ユーザーを実際にデータベースに保存できるようにし、ユーザー登録フォームを完成させる。 ユーザー情報は自動的にデータベースに登録させる。 ブラウザの表示をリダイレクトして、登録されたユーザーのプロフィールを表示 ウェルカムメッセージも表示させる。 登録 require 'test_helper' class UsersSignupTest < ActionDispatch::IntegrationTest test "invalid signup information" do get signup_path # signupのページにアクセス assert_no_difference 'User.count' do # ユーザー数が変わらないかをテストする post users_path, params: { user: { name: "", # ハッシュのハッシュのようになっているように見える email: "user@invalid", password: "foo", password_confirmation: "bar" } } # postリクエストを送信 フォーム送信をテストする # データの投稿した後 assert_no_difference で違いを比べるらしい。 end assert_template 'users/ne end end redirect_to @User 上と下は等価のコード redirect_to user_url(@user) 演習 1.有効な情報を送信し、ユーザーが実際に作成されたことを、Railsコンソールを使って確認してみましょう。 >> User.second User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ? [["LIMIT", 1], ["OFFSET", 1]] => #<User id: 4, name: "aa", email: "abc@def.com", created_at: "2021-10-04 13:16:25", updated_at: "2021-10-04 13:16:25", password_digest: [FILTERED]> 2.リスト 7.26を更新し、redirect_to user_url(@user)とredirect_to @userが同じ結果になることを確認してみましょう。 class UsersController < ApplicationController . . . def create @user = User.new(user_params) # 外部メソッドを使う if @user.save # 保存の成功をここで扱う。 redirect_to user_url(@user) # urlを指定して表示する # 保存成功したらurlを表示する else render 'new' # 保存に成功しなければnewアクションに移動する # 失敗したらまた戻る end end private #外部から使えないようにする def user_params # Usersコントローラの内部でのみ実行される # Web経由で外部ユーザーにさらされない params.require(:user).permit(:name, :email, :password, :password_confirmation) end end 新しくデータを保存して同じ画面が表示されたので確認
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsチュートリアル第七章 失敗時のテスト

失敗時のテスト 有効、無効のデータどちらでも正常にアプリが動くようにする。 アプリケーションの変更をするたびにテストを繰り返さなければならず大変である。 Railsではフォーム用のテストを書くことができ、こういったプロセスを自動化することができる。 今回は無効の送信をした時に正しい振る舞いについてテストを書いていく。 新規ユーザー登録用の統合テストを生成する 統合テストのファイル名はusers_signup rails generate integration_test users_signup 無効なユーザー登録に対するテスト test/integration/users_signup_test.rb require 'test_helper' class UsersSignupTest < ActionDispatch::IntegrationTest test "invalid signup information" do get signup_path # signupのページにアクセス assert_no_difference 'User.count' do # ユーザー数が変わらないかをテストする post users_path, params: { user: { name: "", # ハッシュのハッシュのようになっているように見える email: "user@invalid", password: "foo", password_confirmation: "bar" } }  # postリクエストを送信 フォーム送信をテストする  # データの投稿した後 assert_no_difference で違いを比べるらしい。 end assert_template 'users/new' end end テストは、ユーザ数を覚えた後にデータを投稿してみて、ユーザ数が変わらないかどうかを検証するテスト ubuntu:~/environment/sample_app (sign-up) $ rails t Running via Spring preloader in process 8623 Started with run options --seed 50070 20/20: [==============================] 100% Time: 00:00:01, Time: 00:00:01 Finished in 1.38444s 20 tests, 40 assertions, 0 failures, 0 errors, 0 skips テスト成功 演習 1.リスト 7.20で実装したエラーメッセージに対するテストを書いてみてください。どのくらい細かくテストするかはお任せします。リスト 7.25にテンプレートを用意しておいたので、参考にしてください。 require 'test_helper' class UsersSignupTest < ActionDispatch::IntegrationTest test "invalid signup information" do get signup_path # signupのページにアクセス assert_no_difference 'User.count' do # ユーザー数が変わらないかをテストする post users_path, params: { user: { name: "", # ハッシュのハッシュのようになっているように見える email: "user@invalid", password: "foo", password_confirmation: "bar" } } # postリクエストを送信 フォーム送信をテストする # データの投稿した後 assert_no_difference で違いを比べるらしい。 end assert_template 'users/new' assert_select 'div#error_explanation' assert_select 'div.alert' end end ちょっとわからない。 解けなかった。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsチュートリアルでbundle installがうまくいかないときは

簡潔にまとめます railsのバージョンやGemfileでのバージョン指定を確認しましょう エラーログで検索してみましょう Gemfileのバージョン指定を変更してみましょう 概要 ローカル環境でRailsチュートリアル6版の2週目に挑戦中です。3章まで終わりましたが、Gemfileの内容を更新した後のbundle install / updateが度々エラーになります。対処法と原因についてまとめてみます。 以下は今回出てきたエラーの一例です。 $ bundle update Fetching gem metadata from https://rubygems.org/............ Resolving dependencies... Bundler found conflicting requirements for the Ruby version: In Gemfile: Ruby guard (= 2.16.2) was resolved to 2.16.2, which depends on Ruby (>= 1.9.3) listen (= 3.1.5) was resolved to 3.1.5, which depends on Ruby (>= 2.2.3, ~> 2.2) pg (= 1.1.4) was resolved to 1.1.4, which depends on Ruby (>= 2.0.0) 確認すべきこと・原因 「Railsチュートリアルの通りに進めているのに」と思いつつも、実は「RubyやRails、Gemfile各gemのバージョンが異なっている。」なんてことがあります。   ちなみに私は以下の環境で進めています。 ruby 3.0.2p107 Rails 6.1.4.1   チュートリアルの指定のバージョンではないですね。 …はい、チュートリアルの「エラーが出ないように指定のバージョンを使いましょう」という指示を無視した結果、エラーが出てきます(笑)   あとは、コピペしていたら起きにくいとは思うのですが、Gemfileの記述が間違っていないか確認してみましょう。もしかしたら存在しないgemの名前が書かれていたり、凡ミスのような打ち間違いをしているかもしれません。 対処法1:エラーログを読む、調べる 上でエラーの一例を示しました。例ではgemのバージョンによる依存関係が原因でエラーが起きているようです。 私は英語が苦手なので、とりあえず「読めない!」と思ったらgoogle先生に翻訳してもらいます。   翻訳結果から対処法が分かればいいのですが、初心者故にどうやって対処すればいいのか分かりません。ですので、エラーログをそのままgoogle検索してみます。エラーログが長すぎる場合は、重要な情報を示していそうな部分で調べてみます。   同じようなエラーが出ていて、解決方法を公開してくださっている方を見つけることができたらラッキーです。感謝しながら不具合を解消していきましょう。 対処法2:Gemfileのバージョン指定を変更する。 Rails newコマンドを実行したときに、Gemfileにはさまざまなgemの名前やバージョンが保存されます。Railsチュートリアルでは、チュートリアルを進める上で必要なgemとバージョンが記載されていますが、Gemfileの中身を見てみると必要なものが入っていなかったり、違うバージョンを指定していることがあります。   以下のGemfileのコード(一部)は、私が3章を終えた時点での状態です。Railsによって自動的に記述されたもの、チュートリアルに沿って導入したもの、バージョンの競合が起きたためにバージョンの指定を削除(最新版を導入するように)したものが書いてあります。 Gemfile group :test do gem 'capybara', '>= 3.26' gem 'selenium-webdriver' gem 'webdrivers' #以下はチュートリアルに沿って導入。 gem 'rails-controller-testing', '1.0.4' #以下、versionによる衝突を起こしたため最新版を導入 gem 'minitest' gem 'minitest-reporters' gem 'guard' gem 'guard-minitest' end まずはRailsで生成されたGemfile + 足りないものはチュートリアルの指示通りに記述 うまくいかないときは、gemのバージョン指定を消してみる 1週目を完走したときは、一部はチュートリアルの指示通りのバージョンにしているものもありますが、ほぼすべてのgemを最新版の状態にしてみました。しかし、特に進行に影響のあるようなエラーが出たことはありません。 私の場合はバージョン指定をつけたり消したりしているうちに、うまくいく場合が多いです。 (おまけ) 第3章の初テスト実行時にエラー せっかくなのでタイトルとは関係ないのですが、3章で体験した別のエラーについても書いておきます。 中盤に差し掛かってテストを実行した際にエラーが出ました。 $ rails test /Users/(中略)/kernel_require.rb:34:in `require': cannot load such file -- rexml/document (LoadError)   英語読めないんですけど、なんとなく「読み込めないよ、ロードできてないよ」って言われている気がします。 エラー文の以下の部分をコピペして検索してみます。  `require': cannot load such file -- rexml/document (LoadError) すると同じエラーについてまとめてくださっている方を発見しました。    Rails 6.1 + Ruby 3.0.2でテスト時にエラーがでる   対処法:「rexml」を導入  上記のページを参考に、Gemfileにrexmlを追記 Gemfile #rails test実行時にエラー、必要みたいなので導入 gem 'rexml'   これでbundle installするとテストが無事実行できるようになりました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

動的と静的を学ぶ!

Webで様々なページを見たり、サービスを利用したりすることがあります! そこには、静的と動的という分類があります! それぞれの特徴を書いて行こうと思います! ①.動的 動的とは、Twitterのように、常に最新のツイートを取得し表示する仕組みや、ユーザーごとで表示されるものが変わるような仕組みです! そのような仕組みのサービスは、動的サイトや動的コンテンツと呼ばれます! Webアプリケーションは、動的コンテンツであることがほとんどです! ②.静的 静的とは、誰がいつ見ても、常に同じ内容が表示されるような仕組みです! そのような仕組みのサービスは、静的サイトや静的コンテンツと呼ばれます! HTMLとCSSで作成したWebページは、静的コンテンツです! ③.まとめ どちらも簡単に言うと、 動的コンテンツとは、ユーザーごとで表示されるものが切り替わるような仕組みのこと! 静的コンテンツとは、誰がいつ見ても、常に同じ内容が表示されるような仕組みのこと! こんな感じですね! 基本的な事なので、これはしっかり把握しておこうと思います! なにか説明が間違っていたら教えてください(_ _)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WSL2(Ubuntu)環境下でのDockerを使ったRailsの開発環境構築

概要 初投稿です。 WSL2(Ubuntu)の環境下でDockerを使ったRailsの開発環境の記事が無くて、構築が面倒だったので作りました。 作成する開発環境 Ruby 3.0.2 Rails 6.1.4 MySQL 8.0 ソースコード ソースコードは下記のとおりです。 docker-rails.sh 使い方 前提条件 WSL2(Ubuntu) Docker version 20.10.8以降 Docker Compose v2.0.0-rc.1以降 shellの実行 ディレクトリを作成しdocker-rails.shを配置します。 mkdir sample_app mv docker-rails.sh ./sample_app/ 作成したディレクトリへ移動し、docker-rails.shを実行します。 cd sample_app bash docker-rails.sh -n {project_name} -p {mysql_password} {project_name}は作成するRailsプロジェクトの名前になります。 {mysql_password}は作成するMySQLのrootパスワードになります。 ディレクトリ構成 shellを実行すると下記のようなディレクトリ構成が作成されます。 sample_app ──| ├── README.md ├── docker-compose.yml ├── docker-rails.sh ├── mysql │ ├── Dockerfile | ├── .dockerignore │ ├── data │ ├── docker-entrypoint-initdb.d │ └── mysql-confd ├── rails │ ├── Dockerfile | ├── .dockerignore │ └── entrypoint.sh └── {project_name} ├── Gemfile ├── Gemfile.lock ├── README.md ├── Rakefile ├── app ├── babel.config.js ├── bin ├── config ├── config.ru ├── db ├── lib ├── log ├── node_modules ├── package.json ├── postcss.config.js ├── public ├── storage ├── test ├── tmp ├── vendor └── yarn.lock 個人的なこだわりですが、Docker関連のファイルをプロジェクトのソースコードと 同じディレクトリに置きたくないので分けました。 また、rootもあまり使いたくないので、可能な限り使わない形にしました。 解説 shellで何をやっているか学びたい人向けに解説していきます。 shellの作成方針 Mac環境だとDockerの権限などを自動で上手くやってくれますが、 WSL2(Ubuntu)やLinux環境はDocker Deamonが全てrootで動くため権限で引っかかったりします。 このような場合、Rootless Dockerを使うといいのですがWSL2には対応していませんでした。 権限設定など手動で開発環境を構築するのが面倒だったのもあったので、自動構築するshellを作成しました。 1.Rails環境用entrypoint.sh,Gemfile,Dockerfileの作成 DockerにRails環境を作成するにあたり、下記のファイルを作成します entrypoint.sh Gemfile & Gemfile.lock Dockerfile entrypoint.sh gosuを使ってroot以外の任意のユーザーでRailsを実行するshellファイルです。 今回は「rails」というユーザーを作成しています。ユーザーIDはLinuxデフォルトの1000を設定しています。 cat <<'EOF' > entrypoint.sh #!/bin/bash # Railsの仕様でDocker上だと余分なserver.pidが残り続けてエラーになるため、 # Railsを実行するたびに削除する rm -f /$project_name/tmp/pids/server.pid # デフォルトUID&GIDを設定 USER_ID=${LOCAL_UID:-1000} GROUP_ID=${LOCAL_GID:-1000} # Railsを実行するユーザーを作成 groupadd -r --gid $GROUP_ID rails useradd -u $USER_ID -o -m -g $GROUP_ID -G sudo rails export HOME=/home/rails # ユーザーrailsに/usr/srcへの権限を付与 chown -R rails:rails /usr/src # Railsはsudo以上の権限でないとインストールできないため、 # 作成したユーザーrailsにsudo権限の付与 echo "rails ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers # 作成したユーザーrailsでDockerを実行 exec /usr/sbin/gosu rails "$@" EOF こちらはほぼDocker公式のRails Quickstartのとおりです。 Gemfile & Gemfile.lock RailsをインストールするためのGemfileです。 Rubyがこれらを参照してRailsをインストールします。 cat <<EOF > Gemfile source 'https://rubygems.org' gem 'rails', "~>6.1.4" EOF Gemfile.lockは空で作成します。 こちらもほぼDocker公式のRails Quickstartのとおりです。 Dockerfile Rails環境のDockerfileです。 こちらもほぼDocker公式のRails Quickstartのとおりです。 cat <<EOF > Dockerfile FROM ruby:3.0.2 ENV LANG C.UTF-8 ENV TZ Asia/Tokyo WORKDIR $app_root # gosuなど必要なライブラリのインストール RUN set -ex && \ apt-get update -qq && \ apt-get install -y sudo && \ : "Install node.js" && \ curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash - && \ apt-get update -qq && \ apt-get install -y nodejs && \ : "Install yarn" && \ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list && \ apt-get update -qq && \ apt-get install -y yarn && \ apt-get -y install gosu # ローカルのGemfileおよびGemfile.lockをDockerコンテナにコピー COPY ./$project_name/Gemfile $app_root/Gemfile COPY ./$project_name/Gemfile.lock $app_root/Gemfile.lock # 上記のGemfileを元にDockerコンテナへRailsをインストール RUN bundle install # ローカルのentrypoint.shをDockerコンテナへコピーし、 # Dockerコンテナ上で実行できるように権限を付与。 # DcokerコンテナのENTRYPOINTで実行するように設定。 COPY ./rails/entrypoint.sh /usr/bin/entrypoint.sh RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["/usr/bin/entrypoint.sh"] EXPOSE 3000 CMD ["rails", "server", "-b", "0.0.0.0"] EOF 2.MySQL用のlocale.gen,my.cnf,init_mysql.sql,Dockerfileを作成 DockerにMySQL環境を作成するにあたり、下記のファイルを作成します locale.gen my.cnf init_mysql.sql Dockerfile locale.gen,my.cnfの作成 locale.gen cat <<EOF > locale.gen ja_JP.UTF-8 UTF-8 EOF my.cnf cat <<EOF > my.cnf [mysqld] default_authentication_plugin=mysql_native_password character-set-server=utf8mb4 collation-server=utf8mb4_general_ci [client] default-character-set=utf8mb4 EOF locale.genとmy.cnfはmysqlの設定ファイルです。 init_mysql.sqlの作成 init_mysql.sql cat <<EOF > init_mysql.sql # ユーザーが存在しない場合のみ、新規ユーザーを作成するsql SET @sql_found='SELECT 1 INTO @x'; SET @sql_fresh='GRANT ALL ON *.* TO "$project_name"@''%'''; SELECT COUNT(1) INTO @found_count FROM mysql.user WHERE user='"$project_name"' AND host='%'; SET @sql=IF(@found_count=1,@sql_found,@sql_fresh); PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s; EOF init_mysql.sqlはmysqlで最初に実行されるsqlです。 これでmysqlユーザーを作成します。 Dockerfileの作成 cat <<EOF > Dockerfile FROM mysql:8.0 # ユーザーmysqlのUID,GIDをLinuxのUID,GIDと合わせる RUN groupmod -g 1000 mysql && usermod -u 1000 -g 1000 mysql # ユーザーrailsにsudo権限を付与します。 # ユーザーrailsにsudo権限を付与していないと、rails db:createコマンドでエラーになります。 RUN echo "rails ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers COPY ./mysql/mysql-confd/locale.gen /etc/locale.gen RUN sed -i 's@archive.ubuntu.com@ftp.jaist.ac.jp/pub/Linux@g' /etc/apt/sources.list RUN set -ex && \ apt-get update -qq && \ : "Install locales" && \ apt-get install -y --no-install-recommends locales && \ : "Cleaning..." && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* && \ locale-gen ja_JP.UTF-8 ENV LC_ALL ja_JP.UTF-8 COPY ./mysql/mysql-confd/my.cnf /etc/mysql/conf.d/my.cnf COPY ./mysql/docker-entrypoint-initdb.d/init_mysql.sql /docker-entrypoint-initdb.d/init_mysql.sql EOF mysqlのDockerファイルです。 MySQL Daemonもrootユーザーで動作するので、 Dockerファイルでsudo権限を付与します。 プロジェクトの作成&docker-composeの起動 Dockerコンテナでrails newを実行し、プロジェクトを作成します。 その後、docker-compose buildを行うことでbundle installが実行されます。 docker-compose run --no-deps web rails new . --force --database=mysql docker-compose build --no-cache 続いて、下記のコマンドでrailsプロジェクトのdatabase.ymlの内容を書き換えます。 docker-compose run web /bin/sh -c "sed -ie '0,/password:/ s/password:/password: <%= ENV.fetch('\"'MYSQL_PASSWORD'\"') { '\"'$root_password'\"' } %>/g' ./config/database.yml" docker-compose run web /bin/sh -c "sed -ie 's/host: localhost/host: <%= ENV.fetch('\"'MYSQL_HOST'\"') { '\"'db'\"' } %>/g' ./config/database.yml" docker-compose run web /bin/sh -c "sed -ie 's/username: root/username: <%= ENV.fetch('\"'MYSQL_USER'\"') { '\"'$project_name'\"' } %>/g' ./config/database.yml" docker-compose run web /bin/sh -c "sed -ie 's/username: $project_name/username: <%= ENV.fetch('\"'MYSQL_USER'\"') { '\"'$project_name'\"' } %>/g' ./config/database.yml" その後、db:createを実行DBを作成します。 docker-compose run web rails db:create 最後にdocker-compose buildをもう一度行なったあとに コンテナを起動すると、完了です。 docker-compose build --no-cache docker-compose up -d 以上が完了後、localhost:3000へアクセスすると、RailsのTOP画面へ遷移します。 参考 参考にした記事は下記のとおりです。作者様からは許可をいただいております。 丁寧すぎるDocker-composeによるrails5 + MySQL on Dockerの環境構築(Docker for Mac)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WSL2(Ubuntu)環境下でのDockerを使ったRailsの開発環境構築するshellを作った

概要 初投稿です。 WSL2(Ubuntu)の環境下でDockerを使ったRailsの開発環境の記事が無くて、構築が面倒だったのでshellを作りました。 作成する開発環境 Ruby 3.0.2 Rails 6.1.4 MySQL 8.0 ソースコード ソースコードは下記のとおりです。 docker-rails.sh 使い方 前提条件 WSL2(Ubuntu) Docker version 20.10.8以降 Docker Compose v2.0.0-rc.1以降 shellの実行 ディレクトリを作成しdocker-rails.shを配置します。 mkdir sample_app mv docker-rails.sh ./sample_app/ 作成したディレクトリへ移動し、docker-rails.shを実行します。 cd sample_app bash docker-rails.sh -n {project_name} -p {mysql_password} {project_name}は作成するRailsプロジェクトの名前になります。 {mysql_password}は作成するMySQLのrootパスワードになります。 ディレクトリ構成 shellを実行すると下記のようなディレクトリ構成が作成されます。 sample_app ──| ├── README.md ├── docker-compose.yml ├── docker-rails.sh ├── mysql │ ├── Dockerfile | ├── .dockerignore │ ├── data │ ├── docker-entrypoint-initdb.d │ └── mysql-confd ├── rails │ ├── Dockerfile | ├── .dockerignore │ └── entrypoint.sh └── {project_name} ├── Gemfile ├── Gemfile.lock ├── README.md ├── Rakefile ├── app ├── babel.config.js ├── bin ├── config ├── config.ru ├── db ├── lib ├── log ├── node_modules ├── package.json ├── postcss.config.js ├── public ├── storage ├── test ├── tmp ├── vendor └── yarn.lock 個人的なこだわりですが、Docker関連のファイルをプロジェクトのソースコードと 同じディレクトリに置きたくないので分けました。 また、rootもあまり使いたくないので、可能な限り使わない形にしました。 解説 shellで何をやっているか学びたい人向けに解説していきます。 shellの作成方針 Mac環境だとDockerの権限などを自動で上手くやってくれますが、 WSL2(Ubuntu)やLinux環境はDocker Deamonが全てrootで動くため権限で引っかかったりします。 このような場合、Rootless Dockerを使うといいのですがWSL2には対応していませんでした。 権限設定など手動で開発環境を構築するのが面倒だったのもあったので、自動構築するshellを作成しました。 1.Rails環境用entrypoint.sh,Gemfile,Dockerfileの作成 DockerにRails環境を作成するにあたり、下記のファイルを作成します entrypoint.sh Gemfile & Gemfile.lock Dockerfile entrypoint.sh gosuを使ってroot以外の任意のユーザーでRailsを実行するshellファイルです。 今回は「rails」というユーザーを作成しています。ユーザーIDはLinuxデフォルトの1000を設定しています。 cat <<'EOF' > entrypoint.sh #!/bin/bash # Railsの仕様でDocker上だと余分なserver.pidが残り続けてエラーになるため、 # Railsを実行するたびに削除する rm -f /$project_name/tmp/pids/server.pid # デフォルトUID&GIDを設定 USER_ID=${LOCAL_UID:-1000} GROUP_ID=${LOCAL_GID:-1000} # Railsを実行するユーザーを作成 groupadd -r --gid $GROUP_ID rails useradd -u $USER_ID -o -m -g $GROUP_ID -G sudo rails export HOME=/home/rails # ユーザーrailsに/usr/srcへの権限を付与 chown -R rails:rails /usr/src # Railsはsudo以上の権限でないとインストールできないため、 # 作成したユーザーrailsにsudo権限の付与 echo "rails ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers # 作成したユーザーrailsでDockerを実行 exec /usr/sbin/gosu rails "$@" EOF こちらはほぼDocker公式のRails Quickstartのとおりです。 Gemfile & Gemfile.lock RailsをインストールするためのGemfileです。 Rubyがこれらを参照してRailsをインストールします。 cat <<EOF > Gemfile source 'https://rubygems.org' gem 'rails', "~>6.1.4" EOF Gemfile.lockは空で作成します。 こちらもほぼDocker公式のRails Quickstartのとおりです。 Dockerfile Rails環境のDockerfileです。 こちらもほぼDocker公式のRails Quickstartのとおりです。 cat <<EOF > Dockerfile FROM ruby:3.0.2 ENV LANG C.UTF-8 ENV TZ Asia/Tokyo WORKDIR $app_root # gosuなど必要なライブラリのインストール RUN set -ex && \ apt-get update -qq && \ apt-get install -y sudo && \ : "Install node.js" && \ curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash - && \ apt-get update -qq && \ apt-get install -y nodejs && \ : "Install yarn" && \ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list && \ apt-get update -qq && \ apt-get install -y yarn && \ apt-get -y install gosu # ローカルのGemfileおよびGemfile.lockをDockerコンテナにコピー COPY ./$project_name/Gemfile $app_root/Gemfile COPY ./$project_name/Gemfile.lock $app_root/Gemfile.lock # 上記のGemfileを元にDockerコンテナへRailsをインストール RUN bundle install # ローカルのentrypoint.shをDockerコンテナへコピーし、 # Dockerコンテナ上で実行できるように権限を付与。 # DcokerコンテナのENTRYPOINTで実行するように設定。 COPY ./rails/entrypoint.sh /usr/bin/entrypoint.sh RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["/usr/bin/entrypoint.sh"] EXPOSE 3000 CMD ["rails", "server", "-b", "0.0.0.0"] EOF 2.MySQL用のlocale.gen,my.cnf,init_mysql.sql,Dockerfileを作成 DockerにMySQL環境を作成するにあたり、下記のファイルを作成します locale.gen my.cnf init_mysql.sql Dockerfile locale.gen,my.cnfの作成 locale.gen cat <<EOF > locale.gen ja_JP.UTF-8 UTF-8 EOF my.cnf cat <<EOF > my.cnf [mysqld] default_authentication_plugin=mysql_native_password character-set-server=utf8mb4 collation-server=utf8mb4_general_ci [client] default-character-set=utf8mb4 EOF locale.genとmy.cnfはmysqlの設定ファイルです。 init_mysql.sqlの作成 init_mysql.sql cat <<EOF > init_mysql.sql # ユーザーが存在しない場合のみ、新規ユーザーを作成するsql SET @sql_found='SELECT 1 INTO @x'; SET @sql_fresh='GRANT ALL ON *.* TO "$project_name"@''%'''; SELECT COUNT(1) INTO @found_count FROM mysql.user WHERE user='"$project_name"' AND host='%'; SET @sql=IF(@found_count=1,@sql_found,@sql_fresh); PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s; EOF init_mysql.sqlはmysqlで最初に実行されるsqlです。 これでmysqlユーザーを作成します。 Dockerfileの作成 cat <<EOF > Dockerfile FROM mysql:8.0 # ユーザーmysqlのUID,GIDをLinuxのUID,GIDと合わせる RUN groupmod -g 1000 mysql && usermod -u 1000 -g 1000 mysql # ユーザーrailsにsudo権限を付与します。 # ユーザーrailsにsudo権限を付与していないと、rails db:createコマンドでエラーになります。 RUN echo "rails ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers COPY ./mysql/mysql-confd/locale.gen /etc/locale.gen RUN sed -i 's@archive.ubuntu.com@ftp.jaist.ac.jp/pub/Linux@g' /etc/apt/sources.list RUN set -ex && \ apt-get update -qq && \ : "Install locales" && \ apt-get install -y --no-install-recommends locales && \ : "Cleaning..." && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* && \ locale-gen ja_JP.UTF-8 ENV LC_ALL ja_JP.UTF-8 COPY ./mysql/mysql-confd/my.cnf /etc/mysql/conf.d/my.cnf COPY ./mysql/docker-entrypoint-initdb.d/init_mysql.sql /docker-entrypoint-initdb.d/init_mysql.sql EOF mysqlのDockerファイルです。 MySQL Daemonもrootユーザーで動作するので、 Dockerファイルでsudo権限を付与します。 3.プロジェクトの作成&docker-composeの起動 Dockerコンテナでrails newを実行し、プロジェクトを作成します。 その後、docker-compose buildを行うことでbundle installが実行されます。 docker-compose run --no-deps web rails new . --force --database=mysql docker-compose build --no-cache 続いて、下記のコマンドでrailsプロジェクトのdatabase.ymlの内容を書き換えます。 docker-compose run web /bin/sh -c "sed -ie '0,/password:/ s/password:/password: <%= ENV.fetch('\"'MYSQL_PASSWORD'\"') { '\"'$root_password'\"' } %>/g' ./config/database.yml" docker-compose run web /bin/sh -c "sed -ie 's/host: localhost/host: <%= ENV.fetch('\"'MYSQL_HOST'\"') { '\"'db'\"' } %>/g' ./config/database.yml" docker-compose run web /bin/sh -c "sed -ie 's/username: root/username: <%= ENV.fetch('\"'MYSQL_USER'\"') { '\"'$project_name'\"' } %>/g' ./config/database.yml" docker-compose run web /bin/sh -c "sed -ie 's/username: $project_name/username: <%= ENV.fetch('\"'MYSQL_USER'\"') { '\"'$project_name'\"' } %>/g' ./config/database.yml" その後、db:createを実行DBを作成します。 docker-compose run web rails db:create 最後にdocker-compose buildをもう一度行なったあとに コンテナを起動すると、完了です。 docker-compose build --no-cache docker-compose up -d 以上が完了後、localhost:3000へアクセスすると、RailsのTOP画面へ遷移します。 参考 参考にした記事は下記のとおりです。作者様からは許可をいただいております。 丁寧すぎるDocker-composeによるrails5 + MySQL on Dockerの環境構築(Docker for Mac)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Railsのアクション】newとcreateの違い

こんにちは!テックアカデミーのWebアプリコースを受講している駆け出し高校生エンジニアの安田駿介です。 今回は、「Railsのアクション newとcreateの違い」というテーマで解説していきます。 createアクション レコードの新規作成するアクションです。 個々で言う作成とは、データベースにデータを保存するということだと考えてください。 newアクション 新規投稿用の画面を表示するためのアクションです。 開発環境 ・Cloud9 ・Ruby 3.0.0 ・Rails 6.1.3.1
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MVCについてとブラウザからのリクエスト→サーバーへのレスポンスまでの流れ

MVCについて webでは、ブラウザ(Safari,Chomeなど)とサーバーの間で ブラウザ→サーバへのリクエストと、それに対しての サーバー→ブラウザへのレスポンスのやりとりが行われています。 その内部ではMVCが大きな役割を果たしています。 MVCとは ソフトウェアの設計モデルの一つで、機能をモデル・ビュー・コントローラーの3つの役割に分けて実装するという方法のことです。 モデル・ビュー・コントローラーとは? ではモデル・ビュー・コントローラーとはどのような役割を果たすものなのでしょうか? それぞれの役割について説明します。 モデル コントローラーとデータベースとのやりとりを介している。ビジネスロジックの実装に関わっています。 ビュー DBから取得したデータなどを元にHTMLを作成する。ブラウザへの反映に大きく関与する。 コントローラー モデルの内容についての指揮をおこうなう。この中に実行したいアクションの内容が含まれている。 また、コントローラーの部分が肥大化してしまう傾向がある ブラウザからのリクエストからサーバーへのレスポンスまでの流れ では実際にブラウザからリクエスト→サーバーへのレスポンス、その情報がブラウザに表示されるまでの流れについて説明して行きたいと思います。 ①URIとしてリクエストを送る 例えばAmazonのログインを行いたいとします その場合、 ②初期処理 ここではLaravelやRailsなどのフレームワークで必要な機能の読み込みが行われます。 ③URLからのルーティング リクエストされたURIの情報をもとにルーティングを行います。 ルーティングとはどのコントローラからどのアクションを実行すればいいの?を判断すること。 このURIの中にはポート番号や、プロトコル(ネットワークの規約のようなもの)、ドメイン名の情報が含まれています。 ④コントローラとモデル、データベースのやりとり コントローラーには様々なアクションがあり、ルーティングにより特定のアクションが呼び出されます。コントローラーは呼び出されたアクションを元にモデルを介してデータベースとのやりとりを行います。具体的にはデータの保存や取得を行なったりします。 ⑤ビューに取得したデータを渡す コントローラーは取得したデータをビューに渡し、そのデータを元にビューはHTMLの生成を行います ⑥コントローラーに作成したHTMLの情報を渡す ビューはコントローラーに作成したHTMLの情報を渡します。 ⑦HTMLの情報をブラウザに返す コントローラーはそのHTMLの情報をブラウザに返します。 ⑧ブラウザに表示 このようにしてリクエストされたURIのデータはブラウザに表示されます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

カラム数に制限を設ける

モデルに独自のバリデーションを書かずにコントローラー内で処理をする方法を考えてみました。 環境 ruby 2.6.5 rails 5.2 Mac OS 必要な gem 無し テーブルは Post : comment が 1対多になってます。 実装したいこと userの投稿にたとえばコメントがあったとして、そのコメント数を制限する。 みたいな感じの機能です。 大雑把な流れとして userが投稿詳細ページからコメントを追加 ↓ createアクションが動く ↓ 投稿に対するコメント数が条件より少ない場合、そのまま作成され 条件を超えた場合はflashと共に元のページにリダイレクトさせる 何を使うか コメントのカラムには自身が持つ"id"の他に外部キーとして"post_id"を持たせています。 これによって「post_idがn番のコメント」と表現することができます。 今回数えたいのはまさにこのpost_idです。 情報を取得するメソッドはたくさんあるのでそのなかから最適なものを探します。 all find または find_by select where くらいでしょうか。 allはモデルの情報全て持ってくるし、findはidのレコード持ってくるだけだし、find_byも同じく使わないし、selectは指定したカラムの情報を全て返すし、みたいな感じでいろいろ試していったところ 「where」が1番適していました。 各メソッドの書き方 ALL: @posts = Post.all   インスタンス  =  モデル名 FIND: @post = Post.find(id)     #引数には必要なレコードのidを指定 FIND_BY: @post = Post.find_by(email: params[:email]) ←他にも指定できます。     #カラムと実際の値を記載する SELECT: @comment = Post.select(:post_id) #カラムを指定 WHERE: @comments = Post.where(post_id: params[:post_id]) #カラムと実際の値を記載 みてわかる通り、find_byは1件のレコードを返すのに対して、whereは指定された値のカラムを全て返します。 Commentモデル内に10個くらいデータがあったとして、そのうちpost_idが"3"のものがいくつあるか知りたい場合は @comments = Comment.where(post_id: 3) とすることでpost_idが3のものが帰ってきます。 注意としてはここで返ってきた情報に対して、他のカラムを参照したりすることはできないです。 あくまでpost_idが3のものを表示しているだけなので 、 findやfind_byなどはidに対応するレコードを持ってくるので @user = User.find(1) @user.id @user.nickname @user.age こう書いてカラムを呼び出すことができます。 実装 さっき書いた comments = Comment.where(post_id: post_id) これをコントローラーのcreateアクションに書いて def create @comment = Comment.new(comment_params) comments = Comment.where(post_id: params[:post_id]) if comments.count < 10 if @comment.save? flash[:notice] = "成功しました" redirect_to root_path else flash[:alert] = "失敗しました" redirect_to post_path(@post) end else flash[:alert] = "これ以上追加できません" redirect_to post_path(@post) end end こんな感じで10件まで追加できるようになりました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Docker】起動してもすぐ落ちるときの解決法

環境 Docker version 20.10.7 docker-compose version 1.29.2 状況 Dockerを起動してもすぐに落ちる % docker-compose up -d Creating XXXXX_db_1 ... done Creating XXXXX_redis_1 ... done Creating XXXXX_worker_1 ... done Creating XXXXX_app_1 ... done Creating XXXXX_webpacker_1 ... done Creating XXXXX_web_1 ... done % docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES XXXXXXXXXXXX XXXXX_web "/docker-entrypoint.…" 4 seconds ago Up 2 seconds 80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp XXXXX_web_1 XXXXXXXXXXXX XXXXX_webpacker "/bin/bash -c 'rm -r…" 4 seconds ago Exited (7) 2 seconds ago XXXXX_webpacker_1 XXXXXXXXXXXX XXXXX_app "/bin/bash -c 'rm tm…" 5 seconds ago Exited (7) 2 seconds ago XXXXX_app_1 XXXXXXXXXXXX XXXXX_worker "/bin/bash -c 'bundl…" 5 seconds ago Exited (7) 2 seconds ago XXXXX_worker_1 解決法 Docker Desktopでログを確認すると下記のエラー Could not find  XXXXX in any of the sources Run `bundle install` to install missing gems. 指示どおりbundle install実行 次のコマンドでbundle installしようとするので、Gemfileを更新したらbuildし直す % docker-compose build 次のエラー出現 The git source https://github.com/XXX/XXXXXXXXXXXXX.git is not yet checked out. Please run `bundle install` before trying to start your application Gemfile修正 gem 'XXXXXXXXXXXXX', github: 'XXX/XXXXXXXXXXXXX' ↓ gem 'XXXXXXXXXXXXX', git: "https://github.com/XXX/XXXXXXXXXXXXX" ここでDockerfile内でbundle installしないと意味ないことに気づく… % docker-compose run app bundle install もう一度buildしてupしてみる % docker-compose build % docker-compose up -d 成功!! 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails 「link_to」と「image_tag」を使用して画像にリンクを持たせる 「link_to do」 使い方

概要 link_to の使い方で知らなかった方法があったので記録する link_to 基本的な使い方 link_to(リンクテキスト, パス [, オプション, HTML属性 or イベント属性]) ex) link_to "Top", "root_path"(URLでもok) オプション ・methodを指定する methodをdeleteにすれば削除のアクションを実行できる <%= link_to “削除”, user_path(params[:id]), method: :delete %> ・属性を指定する class属性を指定する <%= link_to "Top", "root_path", class: “nav-menu" %> link_to doでブロックを囲む ・HTMLやimageタグをdo〜end内に記載することによってクリックした時にリクエストを実行できるようになる。 ・HTML部分にFontAwesomeを指定するコードを記載すれば、アイコンからリクエストを実行できる。 ex)画像アイコンをクリックするとroot_pathに遷移できるようにする <%= link_to root_path, class: 'navbar-brand' do %> <%= image_tag "logo.png" %> <% end %> 「link_to do」を使用せずimageをリンクにする <%= link_to image_tag("〇〇/〇〇.png", class: "card-img-top", alt: "Card image cap"), "〇〇_path" %> 参照
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsのセキュリティについて

Railsのセキュリティについて勉強した時のメモです。 セッションハイジャック セッションハイジャックとは? セキュリティに問題のあるネットワークを使用するとCookieの内容を盗み取られる可能性がある。 Cookieの中にセキュリティIDがあるのでそれを奪われると代わりにログインされてしまうこと。 対策 Railsにはconfig/environments/production.rbに config/environments/production.rb config.force_ssl = true というオプションがありこれを追加することでssl通信(セキュリティ的に安全な通信)しか受け付けないようにできる。 CSRF CSRFとは? Cross Site Request Forgeriesと言い、攻撃者が他人のサイトにコードを埋め込むことでユーザーが操作した際に意図しない挙動を生み出す攻撃のこと。 例えば、ECサイトで戻るボタンが購入ボタンになっていて、戻るを押すと決済されていたみたいな感じ。 対策 post,put,deleteなどのデータに変更を加えるものは、tokenと一緒にリクエストしないといけないようにする。 Railsにはapp/views/layouts/application.html.erbに app/views/layouts/application.html.erb <%= csrf_meta_tags %> という記述があり、ここでtoken(鍵のようなもの)が生成されるのでこれを取得してリクエストを送れば対策できる。 SQLインジェクション SQLインジェクションとは? SQLを操作するパラメーターなどを送ることでデータベースを操作して攻撃をする手法。 データベースを操作されるので場合によっては全てのデータを削除したり取り出されてしまう恐れがある。 具体的には、 User.where("name = '{params[:name]}'") のようにwhereにハッシュではなく文字列を渡した場合、 params[:name]に' OR 1 --のように送られてきた場合 SELECT * FROM user WHERE name = " OR 1 --' という全てのデータを取得するクエリが発行されるらしい‥ やばすぎ‥ 対策 ユーザーから送られてくる値を直接使ってSQLのクエリを作らない。 find、find_by、where(name:params['name'])など限定的なメソッドを使う。 Rails、Rubyっぽい書き方をする。 XSS XSSとは? Cross Site Scriptingと言い、コード付きのリンクなどを攻撃者が掲示板などに書き込み、そのリンクを踏んだユーザーに対して不正なプログラムを実行する手法。 ユーザー投稿型サービスではユーザーが投稿した内容をそのまま表示するので、ユーザーが投稿した内容にコードが含まれていた場合、投稿内容をクリックなどした人がプログラムを実行してしまう。 対策 投稿時にコードを入力してもコードではなく文字列として表示するようにする。 例えば以下のようにjQueryでコメントした内容を追加する処理の場合、 pタグに${comment.content}のように書くとコメントにコードを書いた場合そのままコードが反映されプログラムが実行される恐れがある。 const appendNewComment = (comment) => { $('.comments-container').append( `<div class="article_comment"><p>${comment.content}</p></div>` ) } escapeを使うことでコードではなく文字列に変換してくれるので対策できる。 const appendNewComment = (comment) => { $('.comments-container').append( `<div class="article_comment"><p>${escape(comment.content)}</p></div>` ) }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails4.2】Postgresqlの配列リテラルを配列に変換

背景 少々古いプロジェクトでPostgresqlの配列型が使われていた。 ActiveRecord経由であれば取得カラムは自動で配列に変換されるが個別に変換したい場合があった 概要 Rails側で以下の変換を行いたい 半角スペースや改行などの要エスケープ文字がある要素だけダブルクォート囲みされたりしている アポストロフィーエス 's なども少々変換が必要らしい input output {} [] {1,2,3} [1,2,3] {赤,青,緑} ["赤","青","緑"] {"徳川 家康",豊臣秀吉,"織田 信長"} ["徳川 家康","豊臣秀吉","織田 信長"] 実装 モデルのconcernを追加する形にしてみた app/models/concerns/varying_array_parsable.rb module VaryingArrayParsable extend ActiveSupport::Concern class VaryingArrayParser # @see {https://github.com/rails/rails/blob/4-2-stable/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb} # Loads pg_array_parser if available. String parsing can be # performed quicker by a native extension, which will not create # a large amount of Ruby objects that will need to be garbage # collected. pg_array_parser has a C and Java extension begin require 'pg_array_parser' include PgArrayParser rescue LoadError require 'active_record/connection_adapters/postgresql/array_parser' include ActiveRecord::ConnectionAdapters::PostgreSQL::ArrayParser end end module ClassMethods private # @param value [String] varying arrayカラムの値 # @return [Array] 型キャスト後の配列 def cast_to_array(value) @pg_parser ||= VaryingArrayParser.new @pg_parser.parse_pg_array(value) end end end 使用例 app/models/hoge.rb class Hoge < ActiveRecord::Base include VaryingArrayParsable class << self # @param str [String] # @return [Array] def hogehoge(str) cast_to_array(str) end end end まとめ? pgのarray型の文字列→railsの配列 への変換ができるようになった エスケープなどの考慮もされていた postgresqlには array_to_string 関数や unnest 関数があるのでSQL側でこれを使うのもアリだった もっと良い書き方がありそう。ActiveRecordにすでに実装済みのものを真似ているだけなので 参考 rails4.2がActiveRecordでやってる部分 https://github.com/rails/rails/blob/4-2-stable/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb pg_array_parseのgem https://github.com/DavyJonesLocker/pg_array_parser#usage
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]validatesについて

初めに なぜこの記事を書きたかったのか modelでなにをするかまとめたかったから 環境 ・Macbook Air (Retina, 13-inch,2019) ・プロセッサ 1.6GHz デュアルコアIntel Core i5 ・メモリ 8GB 2133 Mhz LPDDR3 ・MacOS Big Sur バージョン 11.5.2 記事の目次 1)Validatesとは 2)できることリスト+使い方 3)最後に Validatesとは イメージは、controller内で設定した内容にルールをつけてDATABASEと情報のやり取りができる機能を持つ。 条件が複数ある場合におすすめな書き方! [+α]with_option内に別のwith_optionを設定しても大丈夫! with_options ルール: true do validates :条件, :条件, :条件, :条件 end できることリスト+使い方 指定した条件の有無を設定する [when?]=ユーザに記入してほしいものは必須条件にするとか。 validates :条件, :条件, presence: true with_optionを使った例 指定した条件の完了後にメッセージを出力させる [when?]=新規登録/ログイン時にユーザの記入事項に誤りがあればエラー文を、ないときは”成功!”と表示させれる validates :条件, ルール: {message: "出力したい文章"} データベースで保存するものを重複しないようにできる [when?]=会社名やメールアドレスの重複を防げれる validates :条件, uniqueness: true, on: :アクション **新規登録/ログイン時にemailを保存するときに重複しないようにするの例 記入事項を数字だと限定する [when?]=誕生日や値段の記入時に数字以外の記入をぺけにすることができる validates :条件, numericality: true validates :条件, numericality: {only_integer: true} 文字数の制限を設定する [when?]=パスワードの文字数制限、値段記入欄の上限、ジャンケンアプリとか 〜以上と設定したいとき numericality: {greater_than: 数字} 〜以下と設定したいとき numericality: {less_than: 数字} 条件より大きく+等しいと設定したいとき numericality: {greater_than_or_equal_to: 数字} 等しいと設定したいとき numericality: {equal_to: 数字} 条件より小さく+等しいと設定したいとき numericality: {less_than_or_equal_to: 数字} 奇数と設定したいとき numericality: {odd: true} 偶数と設定したいとき numericality: {even: true} ぺけにしたい条件を事前に準備したい場合 numericality: {other_than: 数字} **other_thanでの例 記入事項の文字や数字の形態を制限することができる=[正規表現] [when?]=全角、半角英数字など状況に応じて文字の形態を制限することができる {with}で囲むと正規表現に一致するものを制限することができる。 validates :条件, format: {with: 正規表現} {without}で囲むと正規表現に一致しないものを指定することができる。 validates :条件, format: {without: 正規表現} withで囲んで正規表現を使った例 最後に modelでできることをまとめてみたが、まだvalidatesがあるとのこと。。使い勝手がわかったらもう一回別の記事に書いてみようと思う! よくつかう正規表現についてのリンク → https://qiita.com/janani/items/aeb139516c8bb8e70661 ココまで読んでいただきありがとうございます!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]よくつかう正規表現について

初めに なぜこの記事を書きたかったのか 自分がよくつかう正規表現のリストのチートシートを残したかった。 環境 ・Macbook Air (Retina, 13-inch,2019) ・プロセッサ 1.6GHz デュアルコアIntel Core i5 ・メモリ 8GB 2133 Mhz LPDDR3 ・MacOS Big Sur バージョン 11.5.2 記事の目次 1)正規表現とは? 2)条件に合わせた正規表現リスト 3)最後に 正規表現とは? イメージは、作成した記入欄の文字、数字、記号に対してルールを設けられる。 不安なときもしくは試したい正規表現があれば”正規表現チェッカー”で検索すると試せれるよb 条件に合わせた正規表現リスト 携帯電話の正規表現1 /^0[789]0-\d{4}-\d{4}$/ 郵便番号の正規表現 /^\d{3}-\d{4}$/ 全角の正規表現 /\A[ぁ-んァ-ン一-龥々]/ カナ表記の正規表現 /\A[ァ-ヶー-]+\z/ 半角の正規表現 /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]+\z/i 最後に 何を制限したいかを言語化させて、書き方の基本を覚えて試す。でもやはり正規表現の書き方はかなりあるので、新しい表現の仕方を使用するときは”rubyリファレンス”もしくは”基本的な正規表現”と検索をかけることをおすすめしますb
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails] 退会機能(論理削除)

ポートフォリオに実装した退会機能のメモです。 実装 Userモデルにカラムを追加 Userが退会済みかどうかを判断するためのbooleanカラムを追加していきます。 ちなみにUserモデルはdeviseで追加したことを想定しています。 ターミナル rails g migration AddIsValidToUsers is_valid:boolean db/migrate/20210617022549_add_is_valid_to_users.rb class AddIsValidToUsers < ActiveRecord::Migration[6.1] def change add_column :users, :is_valid, :boolean, default: true, null: false end end ターミナル rails db:migrate 退会処理 退会画面と退会処理を作っていきます。 config/routes.rb get '/accounts/:id/unsubscribe' => 'accounts#unsubscribe', as: 'unsubscribe' patch '/accounts/:id/withdrawal' => 'accounts#withdrawal', as: 'withdrawal' 退会画面を表示する画面用のgetリクエストのunsubscribeと先程作成したUserカラムのbooleanを更新するpatchリクエストのwithdrawalのルーティングを作ります。 続いてController app/controllers/accounts_controller.rb def unsubscribe @user = User.find(params[:id]) end def withdrawal @user = User.find(params[:id]) @user.update(is_valid: false) reset_session flash[:notice] = "退会処理を実行いたしました" redirect_to root_path end unsubscribeではuser_idを取得 withdrawalでは退会のためのbooleanを更新して退会したらroot_pathに飛ばしているだけです。 次にviewです。 app/views/accounts/unsbscribe.html.haml .container %h2 退会お手続き %p 退会手続きをされますと、全てのサービスがご利用いただけなくなります。 %br 再度ご利用をいただく場合には、新規登録のお手続きが必要になります。 %br 本当に退会してよろしいですか? = link_to "退会する", withdrawal_path, method: :patch, data: { confilm: "本当に退会しますか?" } = link_to "退会しない", root_path 退会するを押したらlink_toで先程のControllerのwithdrawalアクションに飛んでbooleanを更新する流れです。 退会ユーザーはログインできなくする 退会したらログインできなくしていきます。 app/models/user.rb def active_for_authentication? super && (is_valid == true) end モデルに制約を設定します。 app/controllers/users/sessions_controller.rb class Users::SessionsController < Devise::SessionsController protected def reject_user @user = User.find(params[:id]) if @user if @user.valid_password?(params[:user][:password]) && (@user.active_for_authentication? == true) redirect_to new_user_registration end end end end Controllerで退会済みUserはログインできなくしていきます。 valid_password?でパスワードが正しいかどうか、 active_for_authentication? == trueで先程設定したモデルの制約がtrueの場合はログインせずログインページにリダイレクトされるようにしています。 これで完成です。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RubyとStimulusを使って勤怠打刻システムを個人開発した話

これはなに? DHHとBasecampが開発しているJavascriptフレームワークStimulusを使ってみて、勤怠打刻システムを個人開発したのでその紹介とStimulusに対する感想です。 Stimulusとは StimulusはHTMLタグのアノテーションに設定された内容に応じてDOMに挙動を実装できるフレームワークです。 https://stimulus.hotwired.dev/ 作ったもの 打刻修正もこんな感じで可能 こだわったポイント タイムライン表示 よくあるテーブルに数字が羅列した画面でなく、このようにタイムラインで表示されたほうがチームメンバーの状況把握をしやすいんじゃないか?ということで、稼働時間をタイムラインで表示する形式にしました。 スクショがありませんが、月間表示・週間表示・メンバー一覧表示などあります。 カレンダーは日本の祝日に対応 カレンダーにはdaterangepickerを使っているのですが、サーバーから返した祝日データと照らし合わせて、祝日なら赤くするような実装になっています。 https://www.daterangepicker.com/ これらのサードパーティライブラリもStimulusでラップしてDOMに振る舞いとして実装しています。 Stimulusの標準のライフサイクルを使えば大体のことは困らなそうかなと思います。 祝日データの生成はholidays Gemを使っています。 https://github.com/holidays/holidays Stimulusの感想 ReactやVueも普段から使うのですが、Railsを使って小規模でサクッと開発するにはとても使いやすいと思います。 ただ他のJavascriptフレームワークと流儀が異なりすぎていて、なかなか広まりにくそうな気がします。 (HTMLのアノテーションにDOMの振る舞いを定義できるので)RailsにおいてはStimulusとヘルパーメソッドとの相性がよく、「viewでヘルパーメソッドに情報を渡したら、その情報がStimulusまで到達して渡した情報をjsで扱える」という状態まで簡単に持っていけるので生産性は高そうです。 コード 実はこれを作ったのは1年ほど前なので、Railsは6系でした。 今なら(まだアルファですが)Rails 7はStimulusが使えるようになるgemがデフォルトで入っていますし、Stimulusも 2.0 3.0が出ているので新しい環境で作りたい。 コードはこちら https://github.com/ryooo/timestamper なお、ログイン機能、組織ごとでのユーザー管理機能、組織管理機能とか、一通り必要そうなものは入っています。 以上、読んでくださりありがとうございました
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】Active_hashの結合テストコードの書き方【Rspec】

ユーザー新規登録を例に、Active_hashを含む結合テストコードのやり方をアウトプットしていきます。 前提条件 ・Rubyバージョン2.6.5 ・Railsバージョン6.0.0 ・Gemファイル内の:development, :testに  「gem 'rspec-rails'」「gem 'factory_bot_rails'」を導入し、bundle install済み ・Active_hashを作成してページに表示済み 結論 select '選択肢', from: 'name属性'とする。 書き方 フォームに入力する動作をテストしたい時はfill_inを用いますが、 Active_hashのプルダウン形式は「入力」ではなく「選択」となります。 そのためselectを使って選択する動作をテストしていきます。 require 'rails_helper' RSpec.describe "ユーザー新規登録", type: :system do before do @user = FactoryBot.build(:user) sleep 0.2 end context 'ユーザー新規登録ができる時' do it '正しい情報を入力すればユーザー新規登録ができてトップページに移動する' do # トップページに移動する visit root_path # トップページにサインアップページへ遷移するボタンがあることを確認する expect(page).to have_content('新規登録') # 新規登録ページへ移動する visit new_user_registration_path # ユーザー情報を入力する fill_in 'email', with: @user.email fill_in 'password', with: @user.password fill_in 'password-confirmation', with: @user.password_confirmation select "男性", from: 'user[gender_id]' //ここから下4行がselectの例です select '1994', from: 'user[birthday(1i)]' select '9', from: 'user[birthday(2i)]' select '18', from: 'user[birthday(3i)]'   〜省略〜 <「選択肢」と「name属性」の調べ方> 検証ツールを活用してselect '選択肢', from: 'name属性'に必要な情報を集めます。 ①Active_hashの選択ボックスが表示されているページで「⌘ + option + i」(もしくは右クリックから選択)を実行して検証ツールを起動します。 ②検証ツール枠内の一番左上にある矢印をクリックすると、ページ内のあらゆる要素に照準を合わせることができるので、その状態で選択ボックスをクリックします。 ③すると検証ツールのElements内に、フォームのHTMLコードが表示されます。 これは性別のフォームをクリックした時の表示です。 ここから次の2つのことがわかります。 ・optionタグに囲まれている3つの選択肢(---, 男性, 女性) ・name属性に指定されているuser[gender_id] ぶっちゃけoptionタグに囲まれている選択肢はここを見ずとも、自分で設定したものなので分かると思います。 それよりも大事なのはname属性です。 下記のように、erbファイルのコードではname属性を記述していないのに、HTMLコードに変換されたものではしっかりとname属性が表示されています。 //name属性の記述はどこにも見当たらない <%= f.collection_select(:gender_id, Gender.all, :id, :name, {}, {class:"select-box"}) %> この現象にはform_withの特性が関与しています。 form_withの特性 実はform_withで作成されているフォームには、何も指定しなくてもid名とname属性が自動で付与されるようになっています。 ・id名:modelオプションに指定されている変数名_カラム名 ・name属性:modelオプションに指定されている変数名[カラム名] 今回で言えば、 ①form_withのmodelオプションに指定されている@user ②入力された値を保存するカラム名gender_id そのため次のようになります。 ・id名:user_gender_id ・name属性:user[gender_id] なので仮に「model: @post」と「カラム名 :prefecture_id」であれば、 ・id名:post_prefecture_id ・name属性:post[prefecture_id] 以上のことから、select '選択肢', from: 'name属性'に必要な情報は、検証ツールを使うことで見つけることができ、Active_hashを含む結合テストコードが可能となります。 これでActive_hashを含む結合テストコードの書き方の説明は終わりです!お疲れ様でした。 ご指摘などあれば、ご教授いただけると幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む