20220113のRailsに関する記事は18件です。

(愚痴)renderやredirect_toの後に書かれた後続処理がケアしないと実行されちゃうってセンス悪いと思う

Slack通知とか非同期処理やページレンダリング後にやって良いことを書けるようにすることは必要だけど、その仕組みは使いたいときに使える仕組みのほうが良いと思う。 なぜならrenderやredirect_toを複数書いたり先に書くケースなんて早期リターンみたいなケースがデフォルトだから。 早期リターン時は後続処理をしてほしくないからその記載をしている。 それにもかかわらず、非同期とかをできるようにするために、多数派の早期リターン的なことを実現するためにredirect_to and returnとかを書かなければいけない、手続き的にデフォルト以外の記法を求められるのはセンスが悪い。 それも呼び出されたコントローラーのpublicメソッドの中で(=切り出された関数で書いてはいけない)書かなければならないのは辛い。 Controller内のrenderやredirect_toなんて、raise並の優先度なんだから。 非同期とかできるようにするなら、デフォルトではなく、メソッドの引数に特殊な引数設定するとか、そのメソッドだけインスタンス変数とかヘルパーの変数でtrueにするとか、特殊なことやりたいときに設定できるようにしてほしい。 まぁこんな愚痴を書いても発信力もなければ、Railsのコミッターにつながる能力もなく自分もコミッターにならないので、垂れ流されるだけの意見だけど。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails db:migrateを実行すると、Warning: the running version of Bundlerと警告が出る

データベースを更新し、usersデータモデルを作成するために下記を実行したところ、、 % rails db:migrate Warning: the running version of Bundler (2.2.32) is older than the version that created the lockfile (2.2.33). We suggest you to upgrade to the version that created the lockfile by running `gem install bundler:2.2.33`. と警告が出る。 ↓ ``` % gem install bundler:2.2.33 Fetching bundler-2.2.33.gem Successfully installed bundler-2.2.33 Parsing documentation for bundler-2.2.33 Installing ri documentation for bundler-2.2.33 Done installing documentation for bundler after 3 seconds 1 gem installed ``` この状態で再度 rails db:migrate を試すも、、 % rails db:migrate Running via Spring preloader in process 1788 == 20220110000241 CreateUsers: migrating ====================================== -- create_table(:users) rake aborted! StandardError: An error has occurred, this and all later migrations canceled: you can't redefine the primary key column 'id'. To define a custom primary key, pass { id: false } to create_table. /Users/chiharatomoya/Desktop/portfolio/mo-vie/db/migrate/20220110000241_create_users.rb:4:in `block in change' /Users/chiharatomoya/Desktop/portfolio/mo-vie/db/migrate/20220110000241_create_users.rb:3:in `change' <internal:/Users/chiharatomoya/.rbenv/versions/3.0.3/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:85:in `require' <internal:/Users/chiharatomoya/.rbenv/versions/3.0.3/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:85:in `require' -e:1:in `<main>' 調べてみたのですが、idをわざわざ定義しようとしなくても、勝手にidは反映されるので再定義しなくていいとのこと。 なので、idを定義していた一文を消します。(画像) https://gyazo.com/5f17f452baa250030e29241b3099b9d1 % rails db:migrate Running via Spring preloader in process 1973 == 20220110000241 CreateUsers: migrating ====================================== -- create_table(:users) -> 0.0043s == 20220110000241 CreateUsers: migrated (0.0047s) ============================= 問題なく実行できました。 一応rails sでサーバーを実行し、/usersを見てみます。 https://gyazo.com/4c30d2ccb3b720d429cf5873d5a1f5fb (userモデルが作成できました。)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】ツイートを作成順ではなく、いいねした順に表示したい

概要 ツイート投稿機能とツイートへのいいね機能を持つアプリケーションを開発中、 いいねした順番にツイートを取得する方法について調べたのでメモ。 環境 ruby 3.0.2 rails 6.1.4 mysql 8.0.26 やりたいこと ツイートの作成順がデフォルトの時に、 ツイートの作成順ではなくユーザーがいいねした順にツイートを取得したい。 先に結論 reorderを使用し、中間テーブルのカラムを直接指定する users_controller.rb # ユーザー詳細画面で表示したい場合 def show @user = User.find(params[:id]) @favorites = @user.favorite_tweets.reorder('favorites.created_at DESC') end 以下、詳細 関連するモデル user.rb class User < ApplicationRecord has_many :tweets, dependent: :destroy has_many :favorites, dependent: :destroy has_many :favorite_tweets, through: :favorites, source: :tweet end tweet.rb class Tweet < ApplicationRecord belongs_to :user has_many :favorites, dependent: :destroy has_many :favorite_tweets, through: :favorites, source: :tweet # ツイートのデフォルトとしては投稿順に並べたいためここで指定 default_scope -> { order(created_at: :desc) } end favorite.rb class Favorite < ApplicationRecord belongs_to :user belongs_to :tweet end ER図 結論に至るまで コンソールで確認しつつ試行錯誤。 # userに一人目のユーザーを取得 user = User.find(1) # favoritesに、userがいいねしたツイートを取得 favorites = user.favorite_tweets これだと、tweetのデフォルトである、 tweetsテーブルのcreated_atカラムの降順 での取得となってしまう。 (このデフォルトはtweet.rbのdefault_scopeで指定しているもの) そもそもどんなクエリが発行されているのか? ActiveRecordで発行されるSQLを確認するのに、to_sqlという便利なメソッドがあるとのこと。 先ほどの中身を確認。 # userに一人目のユーザーを取得 user = User.find(1) # userがいいねしたツイートを取得するSQLを確認 user.favorite_tweets.to_sql # 見やすいよう改行 => "SELECT `tweets`.* FROM `tweets` INNER JOIN `favorites` ON `tweets`.`id` = `favorites`.`tweet_id` WHERE `favorites`.`user_id` = 1 ORDER BY `tweets`.`created_at` DESC" ORDER BY tweets.created_at DESC" とあるように、tweetsテーブルのcreated_atカラムをDESCで並べている。 指定したいのは ユーザーがツイートをいいねした順番 つまり、 中間テーブルのcreated_at なので、 上記ORDER BYの箇所を ORDER BY favorites.created_at DESC にできればいいのでは? defaultを上書きしたい # userに一人目のユーザーを取得 user = User.find(1) # userがいいねしたツイートを取得するSQLを確認 >> user.favorite_tweets.order('favorites.created_at DESC').to_sql # 見やすいよう改行 => "SELECT `tweets`.* FROM `tweets` INNER JOIN `favorites` ON `tweets`.`id` = `favorites`.`tweet_id` WHERE `favorites`.`user_id` = 1 ORDER BY `tweets`.`created_at` DESC, favorites.created_at DESC" ORDER BY tweets.created_at DESC, favorites.created_at DESC" .orderでは、デフォルトの後の指定として追加できるだけのよう。 ここで結論 reorderで初期化の上、順番を指定 # userに一人目のユーザーを取得 user = User.find(1) # userがいいねしたツイートを取得するSQLを確認 >> user.favorite_tweets.reorder('favorites.created_at DESC').to_sql # 見やすいよう改行 => "SELECT `tweets`.* FROM `tweets` INNER JOIN `favorites` ON `tweets`.`id` = `favorites`.`tweet_id` WHERE `favorites`.`user_id` = 1 ORDER BY tweet_bookmarks.created_at DESC" 無事、意図通りのいいね順で取得することができた。 参考にした記事 reorder含む、default_scopeの初期化 【Railsドキュメント】reorderについて 最後に より良い方法や間違い等ありましたらご指摘いただけますと幸いです!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Codecov × SimpleCov × RSpec × CircleCI で README にカバレッジを表示させる

この記事を読むとできること GitHub の README に RSpec のカバレッジのバッジを表示させることができる バッジをクリックするとカバレッジの詳細やグラフを確認することができる はじめに GitHub のリポジトリを見ていると、テストのカバレッジ (全アプリケーションのコードに対するテストコードのカバー率) が表示されたバッジをよく見かける。あれを自分もやってみたいと思い設定をしてみたのだが、思っていた以上に躓くポイントが多かった。そのため、導入方法をここに残しておく。 Codecov も SimpleCov も CircleCI もメジャーなツールではあるのだが、この 3 つを組み合わせた場合の導入方法を紹介している記事がほとんどなかった。この記事が、同じことを実現しようとしている人の役に立てば幸いである。 なお、この記事では、Git のホスティングサービスには GitHub、Ruby のテストツールには RSpec を使用することを想定している。ただ、基本は同じはずなので、異なる部分は適宜、読み替えること。 Codecov の設定 まずは Codecov にサインアップしてバッジを表示させたいリポジトリを登録する。 Codecov のサインアップページ にアクセスし、サインアップする GitHub, GitLab, Bitbucket から選択できる GitHub Enterprise などを利用している場合は セルフホストオプション を利用できる Not yet setup をクリックすると、まだ Codecov が設定されていないリポジトリ一覧が表示されるので追加する プライベートリポジトリを追加したい場合は、画面上にあるリンクからさらに権限を付与する必要がある オーガナイゼーションのリポジトリを追加したいが一覧に表示されないという場合は、そのオーガナイゼーションのオーナーに権限を付与してもらう必要がある Codecov のリポジトリ設定ページ (https://app.codecov.io/gh/<USERNAME_OR_ORGNAME>/<REPOSITORY_NAME>/settings) にアクセスする Activation セクションから Activate ボタンをクリックして有効化する Repository Upload Token セクションからトークンをクリップボードにコピーして控えておく サインアップした直後はプライベートリポジトリは一覧に表示されない (追加で権限を付与する必要がある) のが少しだけわかりづらいので注意。 CircleCI の設定 次に CircleCI の設定を行う。CircleCI は該当のリポジトリですでに稼働していることを前提とする。 環境変数の登録 CircleCI の環境変数の設定ページ (https://app.circleci.com/settings/project/github/<USERNAME_OR_ORGNAME>/<REPOSITORY_NAME>/environment-variables) にアクセスする Add Environment Variable ボタンをクリックする Name に CODECOV_TOKEN と入力する Value に先ほど Codecov のページで控えておいたトークンをコピペする Add Environment Variable ボタンをクリックして環境変数を登録する Orb のセキュリティ設定の変更 Organization Settings の Security セクション (https://app.circleci.com/settings/organization/github/<USERNAME_OR_ORGNAME>/security) にアクセスする Orb Security Settings セクションから Yes を選択する コードの変更 ここからはリポジトリ上のコードを変更していく。 Codecov と SimpleCov のインストール Codecov と SimpleCov の RubyGems をインストールする。RSpec (または minitest などその他のテストツール) はすでにインストール済みであることを前提とする。 Gemfile に以下を記述する。 Gemfile group :test do gem 'codecov', require: false gem 'simplecov', require: false end 以下のコマンドを実行する。 Shell bundle install SimpleCov と Codecov の読み込み RSpec の設定 (spec/spec_helper.rb) から SimpleCov の読み込み設定と Codecov 用のフォーマットを追記する。SimpleCov を読み込むことで、テスト実行後にカバレッジ情報を coverage ディレクトリに出力してくれる。さらに SimpleCov のフォーマットを Codecov にすることで、Codecov で読み取れる形式の JSON ファイルを書き出してくれる。 RSpec ではないテストツールの場合は適宜変更すること。 spec/spec_helper.rb require 'simplecov' SimpleCov.start 'rails' require 'codecov' SimpleCov.formatter = SimpleCov::Formatter::Codecov RSpec.configure do |config| # 割愛 end CircleCI の設定ファイルの変更 CircleCI の設定ファイル (.circleci/config.yml) に必要な情報を追加する。 executors, commands, workflows などは割愛する。なお、以下はあくまで例なので、必要に応じて変更すること。 .circleci/config.yml version: 2.1 orbs: codecov: codecov/codecov@1.0.5 executors: # 割愛 commands: # 割愛 jobs: build: executor: default steps: - setup - checkout - run: name: test command: | mkdir -p reports docker create -v /reports --name reports alpine:3.4 /bin/true docker run --network <NETWORK> --env-file=./.circleci/app.env --volumes-from reports -it <CONTAINER> ./.circleci/docker-test docker cp reports:/reports reports - store_test_results: path: reports - codecov/upload: file: ./reports/reports/coverage/codecov-result.json workflows: # 割愛 いくつかポイントがあるので説明する。 Codecov Orb のバージョン この Orb のスクリプトはバグが多くて、たとえば 1.0.4 だとシンタックスエラーになってしまう。全部のバージョンを試したわけではないが、他にも 1.1.4, 1.1.5, 1.1.6 などでも同じシンタックスエラーが発生することを確認済み。1.0.5 なら正常に動作することを確認している。 Orb doesn't work in Alpine images これは Docker の Alpine イメージ (Bash がない) で発生する問題らしいので、Bash が入っているイメージなら他のバージョンでも正常に動作するのかもしれない。 また、2.x や 3.x だと gpg: not found という別のエラーが発生してしまう。 store_test_results (CircleCI で Docker を利用している場合のみ) Docker コンテナ内のファイルはコマンド終了後に消えてしまう。それを防ぐために、store_test_results を指定する。 path: reports のように記述すると、reports ディレクトリは消えずに残る。ここでは reports というディレクトリ名にしているが、他の名前にすることも可能。その場合は実行するコマンド内の記述も併せて変更すること。 テスト実行用のスクリプトを別途用意 (CircleCI で Docker を利用している場合のみ) 上記の例では ./.circleci/docker-test というスクリプトを実行しているが、このスクリプト内で RSpec (または別のテストツール) を実行する。.circleci/docker-test は以下のように記述する。なお、このファイル名は例なので変更しても良い。 .circleci/docker-test #!/bin/sh set -eux RAILS_ENV=test bundle exec rails db:drop db:create >/dev/null 2>&1 RAILS_ENV=test bundle exec rspec cp -R coverage /reports SimpleCov をインストールしている場合、RSpec を実行するとプロジェクトディレクトリに coverage というディレクトリが生成され、その中にカバレッジの詳細データが格納される。そしてその coverage ディレクトリを、 store_test_results で指定したパス (今回は /reports) にコピーする必要がある。そうしないと Docker コンテナで生成されたカバレッジの詳細データが消えてしまうからである。 筆者はあまり Docker には詳しくないのだが、以下のように docker run コマンドを複数に分けると、RSpec 実行時に生成された coverage ディレクトリが消えてしまう。 docker run --network <NETWORK> --env-file=./.circleci/app.env --volumes-from reports -it <CONTAINER> "bundle exec rspec" docker run --network <NETWORK> --env-file=./.circleci/app.env --volumes-from reports -it <CONTAINER> "cp -R coverage /reports" そのため、RSpec の実行と coverage ディレクトリの退避を単一の docker run コマンドで行うために、別途 .circleci/docker-test というスクリプトを用意してそれを実行している。 そのあとの docker cp reports:/reports reports で、Docker コンテナ側の /reports ディレクトリを、ホスト側の reports ディレクトリに退避している。 Docker コンテナ用の環境変数の追加 (CircleCI で Docker を利用している場合のみ) CircleCI 上で、RSpec などを Docker を使って実行している場合は、必要な環境変数をどこかのファイルに記述しているはずである。 たとえば、CircleCI 上 (.circleci/config.yml) で docker run --env-file=./.circleci/app.env ... のようなコマンドを実行している場合は .circleci/app.env 内に必要な環境変数を記述しているはず。 その場合は、このファイル内に、CircleCI の設定ページで登録したものと同じ環境変数を登録する必要がある。以下のコードブロックのファイル名は .circleci/app.env としているが、適宜変更すること。 .circleci/app.env CODECOV_TOKEN=<REPOSITORY_UPLOAD_TOKEN> codecov/upload codecov/upload を記述することにより、生成されたカバレッジの詳細データを Codecov 上に送信することができる。その際に、file オプションを指定することにより、明示的にどのファイル (カバレッジデータ) を Codecov に送信するのかを指定することができる。 Codecov の RubyGems を使用すると、coverage ディレクトリの中に codecov-result.json というのを生成してくれる。この JSON ファイルを Codecov にアップロードすることで Codecov 上でカバレッジの詳細とグラフを確認することができる。なお、Codecov の RubyGems を使わなかった場合 (SimpleCov のみの場合) は index.html が生成されるが、これを Codecov 上にアップロードしてもエラーとなり詳細やグラフなどを確認することができないので注意。 coverage ディレクトリは、今回の例だと ./reports/reports ディレクトリ以下にコピーしてきたので、./reports/reports/coverage/codecov-result.json を指定する。 README にバッジを追加 最後に、README に Codecov のバッジを追加する。 バッジの画像 URL は Codecov のリポジトリ設定ページの Badge タブ (https://app.codecov.io/gh/<USERNAME_OR_ORGNAME>/<REPOSITORY_NAME>/settings/badge) から取得することができる。Markdown セクションにあるコードをコピーして、README の任意の場所にペーストする。 GitHub にプッシュ ここまでできたら、変更を GitHub にプッシュする。CircleCI が回るはずなので、すべてのジョブが終了するのを待つ。 .circleci/config.yml の codecov/upload は、CircleCI の画面上では Upload Coverage Results という名前で表示される。RSpec を実行するジョブ (本記事の例では test というジョブ名) と、Codecov にカバレッジ情報をアップロードするジョブ (Upload Coverage Results) が両方ともエラーなく通っていれば OK だ。 ただし、codecov/upload で指定したファイルパスが間違っていると、No such file or directory というエラーが出力されるのだが、これが出ていても CI 自体は正常に通ってしまうので注意。Upload Coverage Results のジョブの実行結果の出力を CircleCI 上で確認して何もエラーが出ていないことまで確認する必要がある。 動作確認 以下の 2 点を確認する。 https://app.codecov.io/gh/<USERNAME_OR_ORGNAME>/<REPOSITORY_NAME> にアクセスして、カバレッジのグラフなどが表示されていること README 上のカバレッジのバッジにカバレッジの数値が正しく表示されていること 別ブランチを切っている場合 ここまでの変更を、別ブランチを切って行っている場合は、おそらくどちらも正常に表示されないはずだ。 カバレッジのグラフが表示されない カバレッジのバッジに unknown と表示される URL 内にブランチを明示的に指定しない場合は、デフォルトブランチ (何も設定していない場合は GitHub リポジトリ上のデフォルトブランチと同じ) の内容が表示される。しかし、今回の変更ではじめて Codecov を導入する場合で、その変更用に別ブランチを切っている場合は、デフォルトブランチではまだ Codecov を導入していないことになる。そのため、ブランチを指定しない場合は Codecov のページに何も表示されなかったり、バッジが unknown になってしまう。 今回の変更をデフォルトブランチにマージする前に、正しく表示されるのかどうかを確認するためには、一時的にデフォルトブランチを変更するか、URL 内でブランチを指定してアクセスする。 一時的にデフォルトブランチを変更する場合 Codecov のリポジトリ設定ページ (https://app.codecov.io/gh/<USERNAME_OR_ORGNAME>/<REPOSITORY_NAME>/settings) にアクセスする Default Branch セクションの Branch Name を、今回 Codecov の導入を対応しているブランチに変更する Overview (https://app.codecov.io/gh/<USERNAME_OR_ORGNAME>/<REPOSITORY_NAME>) にアクセスして、グラフなどが表示されていることを確認する Codecov のリポジトリ設定ページの Badge タブ (https://app.codecov.io/gh/<USERNAME_OR_ORGNAME>/<REPOSITORY_NAME>/settings/badge) にある画像 URL にブラウザから直接アクセスし、カバレッジの数値が正しく表示されていることを確認する URL 内でブランチを指定する場合 https://app.codecov.io/gh/<USERNAME_OR_ORGNAME>/<REPOSITORY_NAME>/branch/<BRANCH_NAME> にアクセスして、グラフなどが表示されていることを確認する https://codecov.io/gh/<USERNAME_OR_ORGNAME>/<REPOSITORY_NAME>/branch/<BRANCH_NAME>/graph/badge.svg?token=<TOKEN> にブラウザから直接アクセスし、カバレッジの数値が正しく表示されていることを確認する <TOKEN> は Codecov のリポジトリ設定ページ (https://app.codecov.io/gh/<USERNAME_OR_ORGNAME>/<REPOSITORY_NAME>/settings) の Repository Graphing Token セクションから確認可能 その他の選択肢 今回は Codecov を利用したが、Codecov を利用せず、GitHub Pages で似たようなことを実現するツールがある。 SimpleCovSmallBadge Badge formatter for SimpleCov Codecov ほど視覚的にわかりやすい情報は得られないが、外部サービスに頼りたくない場合や、チームメンバーが 6 人以上いる場合1などはこちらを検討するのも良いだろう。 参考サイト CircleCI のテスト結果(Coverage)を Codecov へ送信し可視化する Codecov Ruby Example Jest+CircleCIなプロジェクトにCodeCov(カバレッジレポート)を導入するまでの手順ハンズオン CircleCIとCodecovでGitHubにカバレッジバッジをつけよう! Codecov は 6 人より多い人数で利用したい場合は有料となる。参考: https://about.codecov.io/pricing/ ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CRUD処理(rails6)エラー解決

CRUD処理を実装中に発生したエラーについてのアウトプット。 エラー内容 投稿した情報を削除しようとした時に発生したエラー。 削除なのにHTTPメソッドがGET、本来はDELETE. 考えられる原因 1.ルーティングが間違っている。 2.コントローラーアクション間違い 3.ビューファイル記述間違い エラー解消の流れ 1~3が間違っていないか確認。 ルーティング delete '/users/:id', to: 'users#destroy' コントローラー def destroy user = User.find(params[:id]) user.destroy end 削除ボタン追加 <%= link_to '削除', "/users/#{user.id}", method: :delete, data: {confirm: "削除しますか?"} %> ビュー <h1>削除完了</h1>   <%= link_to "一覧画面へ", "/users" %> 確認してみたがコードの間違いは見つけられず。 息詰まったのでエラーメッセージでググることに、link_toではなくbutton_toにすれば削除はできるとの記事を発見し、早速実施。 button_toにコードを書き換えると削除はできるようになったが、スッキリとは解決していないので再度情報収集。 結果 エラーの原因としてはRails7がリリースされたことによるdeleteメソッドの記述の仕方の変更。 エラーが発生した時のRails version $ rails -v $ rails 7.0.1 修正 ①インストールされているRailsのバージョン確認 $ gem list rails ②使用したいバージョンがないときはインストール実施 $ gem install rails -v 6.0.4.4 ③rails6で再度作成 $ rails _6.0.4.4_ new sample_app 確認 削除ができる。 エラーを解決しての感想 エラー文を見て、ルーティングエラーなのはわかると思うので、そこから一つ一つ、間違っている場所を潰していくことでエラーが解決できると思っていたが、 今回のエラーに関しては元の記述も間違っているところがなく手詰まり感がすごかった。 なんとか解決することができたのでまた一つ成長できたと思う。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

管理者権限もどき

はじめに 今回は新規登録した時の情報を使って、表示するかしないかを判別していこうと思います。 前提 この機能を実装するに当たって、deviseを使用したマイページ機能の実装はしてあるものとします。 実装 これから実装していきます。 deviseにカラムの追加 rails g migration AddAdminToUsers admin:string rails db:migrate 上記のコードを打ち込んで、adminカラムをstring型で追加します。 parameterに記述します app/controllers/application_controller.rb def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :admin#ここに追加]) devise_parameter_sanitizer.permit(:account_update, keys: [:name, :profile]) end ここに記述することでサインアップ時に情報を入れることができます。 必ず記入してもらうようにします app/models/user.rb validates :name, presence: true #ここから validates :admin, presence: true #ここまで validates :profile, length: { maximum: 200 } validates :admin, presence: true 上記のコードを記述することで、新規登録時に必ず項目を埋めていないとエラーになるようになります。 viewの変更 app/views/users/registrations/new.html.erb #追加 <%= f.label :admin %> <%= f.select :admin, [["社員", "社員"], ["店員", "店員"]], include_blank: "社員ですか?" %><br> #省略 これで、登録時に社員か店員判別ができるようになります。  最後にif文を使用して、条件分岐します app/views/tweets/index.html.erb <% if user_signed_in? && current_user.admin == "社員" %> <%= link_to "新規投稿へ", new_tweet_path %> <% else %> <%= link_to "ログイン", tweets_path %> <%= link_to "新規登録", new_user_registration_path %> <% end %>  余談 if文の解説 <% if user_signed_in? && current_user.admin == "社員" %> ユーザーがログインしているかつ現在のユーザーのadminカラムが"社員"だったら表示する という文章になっています。 これによって、新規登録時のカラムによって権限をかけることができます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】scopeメソッドとクラスメソッドでnilを返す時の挙動が違う

クラスメソッドの場合 class Book def self.published where(published: true) end end Book.published.order(id: :desc) #=> Attendance Load (3.8ms) SELECT `attendances`.* FROM `attendances` WHERE `attendances`.`date` BETWEEN '2022-01-01' AND '2022-01-31' ORDER BY `attendances`.`id` DESC nilの場合はnilが返るのでメソッドチェーンが使えない。 class Book def self.published nil end end Book.published #=> nil Book.published.order(id: :desc) #=> NoMethodError: undefined method `order' for nil:NilClass scopeの場合 class Book scope :published, -> { where(published: true) } end Book.published.order(id: :desc) #=> Attendance Load (3.8ms) SELECT `attendances`.* FROM `attendances` WHERE `attendances`.`date` BETWEEN '2022-01-01' AND '2022-01-31' ORDER BY `attendances`.`id` DESC nilの場合でもallメソッドが実行されるのでメソッドチェーンが使える。 class Book scope :published, -> { nil } end Book.published #=> nil Book.published.order(id: :desc) #=> Attendance Load (3.8ms) SELECT `attendances`.* FROM `attendances` WHERE `attendances`.`date` BETWEEN '2022-01-01' AND '2022-01-31' ORDER BY `attendances`.`id` DESC 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[rails]評価点ごと(星ごと)の一覧画面を実装

はじめに ポートフォリオ作成中に、評価された商品について、評価点ごとに商品を表示する機能を実装しようと試みました。 その際、ちょうどいい記事が見つからなかったので今回まとめてみました。 開発環境 ruby '3.0.0' Rails 6.0.3.4 前提 下のような、評価をするためのモデル及びカラムが作成されており、投稿機能まで実装されているものとする。 ユーザが"ガジェット"を投稿するサイトにて、下のようなER図にてgadjet_pointを今回の評価点とする。 今回は、下画像のように10段階評価されたものについて、点数ごとの一覧画面を作成することを目標とする. ルーティング app/models/favorite.rb class Favorite < ApplicationRecord . . . resources :boards do member do get :stars end end end ボードコントローラに"stars"アクションを追加し、"stars"アクションにて、評価点(星の数)ごとの一覧画面を表示する。 ビューの作成 コントローラの前に、"stars"アクションを呼び出すビューを作成します。 今回は、した画像のようにヘッダーメニューから遷移できるようにする。 <div class="dropdown"> <button class="btn btn-secondary dropdown-toggle margin-left20" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Star </button> <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> <% i = 10 %> <% until i == 0 do %> <%= link_to "#{i}stars" , stars_board_path(id:i), class:"dropdown-item font-black" %> <% i -= 1 %> <% end %> </div> </div> 繰り返し処理にて、最初に"10"を代入し、繰り返す度に-1する。 stars_board_path(id:i)→starsアクションを実行するパスに"id"を評価点として受け渡すようにする。 コントローラ app/controlles/boards_controlle.rb class Favorite < ApplicationRecord . . . def stars @gadjets = Gadjet.where(gadjet_point: params[:id]) @stars = params[:id] end end Gadjetモデルのデータからgadjet_point(カラム名)が受け渡された評価点(:id)であるものを抽出。 評価点ごとの一覧画面 stars.html.erb <div class="album py-5 bg-light"> <div class="container"> <h1 class="text-center margin-bottom25">星<%= @stars %></h1> <%= render "shared/gajets-list", gadjets: @gadjets %>                #評価点別に抽出した@gadjetsをひとつづつ表示するviewを呼び出し。ここはご自身で作成願います。 </div> </div> 結果、以下の画像のような評価点ごとの一覧画面が作成できる。 終わりに この実装方法は完全オリジナルであり、効率がより良い方法等があると思います。 間違い等がありましたら、コメントにてご指摘お願いいたします。 少しでも参考になれば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Stripe::InvalidRequestErrorの対処法

症状 RailsでStripeのCheckoutを組み込んだ際に、下記のエラーが表示されました。 翻訳すると、「(Checkoutを使用するには、アカウントまたは会社名をで設定する必要があります」でした。 error Stripe::InvalidRequestError (In order to use Checkout, you must set an account or business name at https://dashboard.stripe.com/account.): 解決方法 エラーメッセージに合った「https://dashboard.stripe.com/account. 」に飛んで、アカウント設定の項目を埋めたらエラーが表示されなくなりました。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Railsのバージョンダウンの仕方

rails6.1.4.4をインストールします。 最初にrailsのバージョンを指定してインストールを行います。 macはターミナル windowsはコマンドプロンプト を開きます。 そこに、以下のコードを入力していきます。 gem install -v 6.1.4.4 rails その後 rails -v を行うと Rails 7.0.0 と返ってくると思います。 rails7.0.0をアンインストールします。 rails -v を入力をしますと、Rails 7.0.0と返ってくると思います。 そうしましたら、次にrailsをアンインストールしていきます。 gem uninstall rails を入力をすると以下のようなコードが返ってくると思います。 1. rails-6.0.3.7 2. rails-6.1.4.4 3. rails-7.0.0 4. All versions >#ここにrails-7.0.0の左にある数値を入力します その後に以下のコードを実行します。 gem uninstall railties -v '7.0.0' すると、rails7.0.0をアンインストールができました。 その後に rails -v を行うと、rails6.1.4.4と返ってくると思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ruby on rails バージョンを指定してアプリケーション作成

はじめに Macはターミナル Windowsはコマンドプロンプト を開きます。 rails new <アプリ名> で新しいアプリを作成しようとすると、インストール済みの中で最新のバージョンが使用されます。 rails 6.1.4.4でアプリケーションを作成したい場合は、このコードではダメです。 実は、rails 7.0.0だとうまくいかないことがあります。 なので、rails 6.1.4.4のアプリケーション作成できるようにしたいと思います。 gem list rails を記述すると dotenv-rails (2.7.6) haml-rails (2.0.1) importmap-rails (1.0.1) jquery-rails (4.4.0) rails (7.0.0) rails-dom-testing (2.0.3) rails-html-sanitizer (1.4.2) sass-rails (6.0.0) sassc-rails (2.1.2) slim-rails (3.3.0) sprockets-rails (3.4.2, 3.4.1, 3.4.0, 3.3.0, 3.2.2) stimulus-rails (1.0.2) turbo-rails (1.0.0) rails 7.0.0しかない状態ですね。 rails 6.1.4.4のインストール gem install -v 6.1.4.4 rails を行います。 その後、以下のコードを入力してrails (6.1.4.4)が入力させているか確認をします。 gem list rails 以下のように表示されていたらインストールは成功です。 dotenv-rails (2.7.6) haml-rails (2.0.1) importmap-rails (1.0.1) jquery-rails (4.4.0) rails (7.0.0, 6.1.4.4) rails-dom-testing (2.0.3) rails-html-sanitizer (1.4.2) sass-rails (6.0.0) sassc-rails (2.1.2) slim-rails (3.3.0) sprockets-rails (3.4.2, 3.4.1, 3.4.0, 3.3.0, 3.2.2) stimulus-rails (1.0.2) turbo-rails (1.0.0) これでrails (6.1.4.4)がインストールされました。 rails (6.1.4.4)でアプリケーションを作成 cd desktop rails _6.1.4.4_ new rails_pre と入力したら完了です。 cd rails_pre rails s を行って http://localhost:3000/ にアクセスしてみて このような画像が表示されたら成功です。 お疲れ様でした。 サーバーをControl+cで切って終了してください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【個人開発】全くのRails初心者が一人でwebサービスを作ってみた

初投稿です。昨日で、一通り制作が完了したので、11月~1月前半までの二か月半を時期ごとに振り返ってみようと思います。 開発環境 ruby on rails(6.1.4.4) heroku S3 cloudflare 開発開始(11月前半) 掲示板的なそれぞれの人がそれぞれの目的でゆるーく使えるwebサービスを作ろうと思い、開発を開始しました。 開発言語はRailsが一番情報が多そうだと思い、Railsに決定。 どこから制作を初めていいかもわからない状況だったので、「rails webサービス 作り方」でググっていたところこのような記事を発見。 こちらの記事には大変お世話になりました。。。こちらを参考にしながら一通り作ってみようと思いました。 bootstrapとHTMLとCSSに触れる(11月後半) 先程の記事を参考にしながら、順調に開発は進んでいました。 ですが、bootstrapの導入が上手くいかず、ここで1週間ほど苦戦。。。。 それもそのはず、自分はrails6を使っていたのでgemでの導入ではなく、yarnからのインストールが必要でした。その時参考にさせていただいたのが、以下の記事です。 これを参考にして、無事bootstrapが導入できました。 今までPythonしかプログラミング言語に触れてこなかったので、railsどころかHTMLやCSSに関しても全くの無知でした。 この開発を通して、少しは理解できたと思います。。。 開発中盤①(12月前半) 参考にさせていただいた記事を一通り読み終わり、ある程度bootstrapもいじれるようになったので、レイアウトを整えていき、それっぽい見た目になってきました。 ですが、ここで問題が発生。投稿画面にRails6から導入されたAction_Textの導入が上手くいかない。 これで5日間ほど苦戦。。。12月中にはリリースしてみたかったのに。。。。 結局、Railsのファイルを最初から作り直して解決しました。 開発中盤②(12月後半) 結構形になってきました。googleログイン認証とか、当初は予定していなかった機能も結局付けることになりました。 タグ機能もあったら便利だろうな~と思い、以下の記事を参考にしながらタグ機能を付けることができました。 こうして、必要な機能がだんだんと揃ってきたので、正月休みが終わったら公開してみようと決めました。 開発後半(1月前半) 正月休みが終わり、まずは、サーバー選び。今回はherokuとs3を用いて実装を行うことにしました。 理由は、何としてでも無料で運用したかったからです。そして、herokuでは独自ドメインも使えるらしいので、お名前ドットコムにて取得。 クレジットカードも持っていなかったので、即日発行のカードを後先何も考えずに発行してしまいました。。。 準備は完了したので、いざ実装。。。って言っても何をどうすれば良いか分からない。。。 なので、「rails heroku」でググり散らかしていると以下の記事を発見。 さらに独自ドメインをfreeplanで適用するために以下の記事を参考にさせていただきました。 無事に独自ドメインでの公開が完了いたしました。 本当に色々な方の記事を参考にさせていただきました。本当に感謝しています。 完成!! 無事に完成させることができました。これから実装しなくてはならない機能がありますが、キリがないのでこれから修正していきます。もしよろしければ覗いてみてください。。。 日記やブログ、質問や、雑談など、それぞれの人がそれぞれの使い方をゆる~く出来るサービスです。 終わりに 一人での開発で、初めての言語でしたので公開すらできないかもという不安もありました。 この記事がこれからRailsに触るという方やプログラミング初心者の方のお役に立てればそれほど嬉しいことは無いです。 以上、長文、駄文失礼致しました。 以下参考にした記事です。本当に感謝しています。ありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】rake db:seedでCSVからDBに移す際のNameError: uninitialized constantやActiveModel::UnknownAttributeError

ポートフォリオにWebアプリを作っていますが、csvをデータベースに移す際にNameError: uninitialized constantで小一時間詰まりました。 CSVの内容をDBに移す記事はいくつかあるのですが、暗黙的に実行されたコマンドがあったり、Railsのデフォルトではない状態で実行されていたりしたので、ルーキーが読みやすいようにまとめました。 対象者 Railsについてざっと勉強した人 csvファイルを準備できている人 初めてRailsでCSVからDBにデータを移したい人 環境 Windows10 Ruby 2.6.9 Rails 5.2.6 CSVからDBに移す手順 model作成 terminal C:\Users\egacha_app> rails g model red_prob red_probが今回csvの中身を入れるmodel名になります。 app/models/red_prob.rbが作成されます。 次にテーブルにカラムを追加するため、マイグレーションファイルを書き換えます。 db\migrate\20220112134851_create_red_probs.rb class CreateRedProbs < ActiveRecord::Migration[5.2] def change create_table :red_probs do |t| t.string :level t.string :probability t.string :effectjp t.string :effecten end end end マイグレーションファイルを実行します。 terminal C:\Users\egacha_app> rails db:migrate これでテーブルにカラムが追加されました。 db/seeds.rbファイルの編集 まずdbフォルダにcsvファイルを入れてください。 (dbフォルダに入れない場合は、下記のコードのパス部分を書き換えてください。) seedを編集します。 db/seeds.rb require 'csv' CSV.foreach('db/red.csv', headers: true) do |t| RedProb.create( level: t['level'], probability: t['probability'], effectjp: t['effectjp'], effecten: t['effecten'], ) end terminalでseeds.rbを実行します。 terminal C:\Users\egacha_app> rake db:seed これでCSVの内容がDBに移されます。 NameError: uninitialized constant、ActiveModel::UnknownAttributeErrorが出る場合 ①クラス名が違う 今回私はred_probというテーブルを作成しました。 「ということは、seedを'red_prob'というものに対して書けばいいんだな」…と思い込んでseeds.rbを編集しました。 しかし、いくら実行しても terminal C:\Users\egacha_app> rake db:seed rake aborted! NameError: undefined local variable or method `red_prob' for main:Object ・・・ このエラーから抜けられませんでした。 「red_prob.rbは間違いなく存在しているのに、なぜ?」と思っていましたが、red_prob.rbを開いて気付きました。 red_prob.rb class RedProb < ApplicationRecord end class名は'red_prob'ではなく、'RedProb'になっていたのです。 新しいファイルを作成すると先頭文字が大文字になる、程度の名前の変化は経験していたのですが、まさか_を取り除いて2単語目の先頭文字も大文字にするというのは衝撃的でした。 seedファイルのclass名をRedProbに変更して、ここは無事に通れました。 ②マイグレーションが思い通りできていない 私の場合、①を通過してrake db:seedを実行しても terminal C:\Users\egacha_app> rake db:seed rake aborted! ActiveModel::UnknownAttributeError: unknown attribute 'level' for RedProb. ・・・ 今度はActiveModel::UnknownAttributeErrorが出ました。 「なるほど、カラムに'level'が無いらしい。じゃあマイグレーションファイルで追加しよう」とマイグレーションファイルを編集してdb:migrateを実行し直しても、db:seedを実行すると同じエラーが出続けます。 原因は、rails gでmodelを作成した後すぐにdb:migrateを実行していたことでした。 db:migrateを一度実行すると、その後既存のマイグレーションファイルを書き換えてdb:migrateを実行したとしても、「そのマイグレーションファイルは実行済みだよ!」と認識されます。 ですので、マイグレーションファイルをもう一度作って実行しましょう。 terminal C:\Users\egacha_app> rails g migration add_collumn_to_redprob db\migrate\20220113024049_add_collumn_to_redprob.rb class AddCollumnToRedprob < ActiveRecord::Migration[5.2] def change add_column :red_probs, :level, :string add_column :red_probs, :probability, :double add_column :red_probs, :effectjp, :string add_column :red_probs, :effecten, :string end end terminal C:\Users\egacha_app> rails db:migration ちなみにdb:rollbackでマイグレーションをロールバックする手段もありますが、危険です。 参考にさせて頂いた記事 【Rails】rake seedコマンドでCSVファイルからDBに読み込ませる方法 https://qiita.com/mmmasuke/items/545afaf5876d3dc52670 [Ruby on Rails]データベースの作成、カラムの追加 https://qiita.com/sansiro/items/68015f79aaacc1ee8e72 Railsでデータベースの中身を確認する https://qiita.com/mzmz__02/items/558c4e023a1bd0908e4f 後記 DBの操作はExcelと違って直感的にできないので、原因究明に時間がかかりました。 ですが、おかげでマイグレーションファイルについては理解が深まり、重要性も理解しました。 Railsコマンドで作られる名前も面白いですね。規則が多いので、厳密に守っていきましょう。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【個人開発】MySQLにCRUDできるノーコードアプリをRailsで作ってみた

個人開発で作ったサービス【shareCRUD】を先日ベータ版にて公開しました。この記事は、個人開発でサービス作ってる・作りたいけど、事例を参考にしたい人向けに、開発したサービスのご紹介と、それを作るまでの経緯をまとめてみました。 作ったサービス【shareCRUD】 サイトはこちらです→https://sharecrud.com アプリ化したいDB(MySQL)につなげて、必要な設定をすると、ブラウザからGUIでCRUD(登録・検索・更新・削除)できる機能が作れます。イメージとしては、phpMyAdminみたいな機能をノーコードで作れるサービスです。 どんなシーンで役に立つか? 1. プロダクトの運営初期から「管理画面」が手に入る 例えば「toC向け」Webサービスの場合、初期の開発ではフロント向けに専念し、管理画面は作らず直接DBにつなげての運用も多いと思います。shareCRUDでDBを操作できるアプリを作れば、開発コストをかけずに管理画面に似た機能が手に入るので、エンジニアでない方でもデータの管理が可能になります。 2. 管理画面とshareCRUDの「二刀流」で、効率的に運用できる ある程度成長したWebサービスでも、管理画面開発は運営上クリティカルな機能に限定し、一般的なデータの参照や更新はshareCRUDを使う「二刀流」にすることで、管理画面の開発コストを下げながら効率よくサービスを成長できます。 アイデア出しから実装までの道のり ここからは、個人開発ならではのエピソードも交えて、サービス開始までの経緯をまとめてみます。 サービスの「管理画面」に感じていた課題 開発途上のサービスの管理画面について 私は今回の開発以前にも、いくつかの個人開発をしてサービスを作ってきましたが、toC向けサービスはフロント向け機能のみ作り、管理画面は作らずDBを直接参照して対応していました。小規模のサービスでも、非エンジニアの方が運営するには、DB直接参照というわけにも行かないので、簡易な管理ツールを作るか、開発元のエンジニアにメンテを依頼もあると思われます。 過去にActiveAdminなどの利用もしましたが、導入にも環境構築にもそれなりにコストがかかり、私個人としてはあまり好みではありませんでした(一個人の意見です) 小規模で開発途上のサービスの場合、一定量は管理画面がないのではと予想しています。 成長したサービスの管理画面について 以前お世話になった自社サービスを運営している会社では、サービスは成長しているので管理画面も存在し、非エンジニアの方がオペレーションを担っています。しかし、管理画面ですべて対応はできておらず、ちょいちょいエンジニアに依頼が入ってデータメンテをしていました。依頼にすぐ対応ができなかったり、作業が中断したりで、もどかしい部分がありました。 普段の業務から得た着想 一方で、私は普段フリーで受託開発をしていて、業務システムや管理画面をRailsで作ることが多いです。業務・管理画面系のシステムは共通化できる部分が多いので、自分なりにフレームワーク化していました。モデリングした内容をフレームワークに落とし込むと、ベースとなるシステムができます。落とし込むと言っても、案件の都度、決まった流れのコードを手動で書いてたので、これを自動化できれば、管理画面に代替する機能をノーコードで作れるかもと考えました。 ノーコードに対する不信感と向き合う 実は「ノーコード」のサービスにはあまり良いイメージがありませんでした。「エンジニアいらずで、なんでも簡単につくれる」といった謳い方をしているサービスが多いように感じ、違和感を感じました。これからノーコードを作ろうとしているくせに、ノーコードツールにあまりよいイメージがないのはなんとも矛盾していますね そこで、自分がノーコードを作るのなら、この点にきちんと向き合おうと思いました。具体的には なんでもできそうなアプリではなく、CRUDが主目的なことを明確にする 基盤をエンジニアが設定をして、運営者がエンドユーザーになる使い方を想定 といった点です。以上から「DBにCRUDできるアプリをノーコードで生成するプラットフォーム作り」とのアイデアで実装を進めることとしました。 技術的な実現方法を検討 ここからは技術調査です。私にはノーコードツールの開発経験は無かったので、まず実現方法から考えました。といっても、このタイミングで一から新たな技術を学ぶというより、その時点で自分ができることを応用できればと思いました。 RailsのScaffoldから着想を得て、Thorを使うことにした Railsには、コマンドから雛形となるソースコードを生成できる機能(ジェネレータ)があります。scaffoldではベースとなるソースコードを生成しているので、この機能を応用してコードを自動生成すれば、ノーコードのエンジンが作れると考えました。 Railsでジェネレータは普段から使っていましたが、具体的にどのような仕組みで実現しているか把握していませんでした。調査すると「Thor」というツールの上に成り立っていることを知りました。 以下のドキュメントに大変お世話になりました。 また、Rails自体のGenerators部分のコードも大変参考になりました。 ソースコード生成までのフローをまとめる Thorを使って生成する部分はイメージできたので、システムの具体的な設計をしました。以下のフローで実現を図りました。 ① DBの接続情報を入力して、テーブル定義などを読み取る 主に以下の情報を取得しています。 テーブルとフィールド名、型の取得 主キーやNotNull、一意制約、AUTO INCREMENTなどの取得 他テーブルとの外部キー、など ② 読み取ったテーブル定義をもとに、アプリの設定をする 画面から以下のような設定をしてもらいます。 テーブルに対する設定 フィールドのlocale(和名)を設定 表示フォーマットや単位の定義 バリデーションの追加(文字数や最大・最小値など) enumなどの区分値に対する表示名の定義、など アプリに対する設定 検索条件の定義 一覧や詳細画面に表示するフィールド、表示順序 登録フォームのパーツ選択(ラジオボタン or ドロップダウンなど) リレーショナル(1:n)への、親・子データの扱い、など ③ ②で登録した設定内容をもとに、ビルド処理でソースコードを生成する Thorを使って各ファイルを作っていきます。一例ですが、モデルのファイルを生成する場合、以下のようにしています。 ※説明用にアレンジしています。 model.rb.tt <%-# このファイルをテンプレートにして、テーブルごとにmodelファイルを作成しています -%> <%-# @modelは、上記①②で設定したテーブル情報を保持しています -%> class <%= @model.name %> < SharecrudAppModelBase self.primary_key = '<%= @model.pk_column.name %>' <%- @model.columns.select { |c| c.kind_enum? }.each do |column| -%> <%-# コードの文字列が返ってくるメソッドを定義してます-%> <%= column.enum_code -%> <%-# ↑例えば enum gender: { man: 1, woman: 2 } 的なコードが挿入されます -%> <%- end -%> <%- @model.columns.select{ |c| c.unique? }.each do |unique_column| -%> validates :<%= unique_column.name -%>, uniqueness: true <%- end -%> <%- @model.columns.select{ |c| c.kind_number? }.each do |c| -%> <%= c.number_validates_code -%> <%- end -%> ... end model_generator.rb ### 上記テンプレートを呼び出すgeneratorを定義します module Sharecrud class ModelGenerator < Rails::Generators::NamedBase def setup @model = Model.includes(:columns).find(name.to_i) end def create_model_file base_path = "tmp/product/#{@model.project_code}/app/models" model_file_path = File.join(base_path, "#{@model.name.underscore}.rb") template "model.rb", model_file_path, encoding: :utf8 end ... end end そして、ビルド処理の中で Rails::Generators.invoke('sharecrud:model', [model.id.to_s], destination_root: Rails.root) といった形でGeneratorをキックして、テーブルごとにModelのファイルを生成しています。 同様な仕組みで、他にもアプリごとにViewやControllerなどを生成しています。 ノーコード(自動化)の対象をどこまでとするか ソースコードは前述の仕組みでノーコード化できそうですが、生成したコードを動かす「環境」について、自動化の対象に含めるか迷いました。当初は、新規ユーザーが利用する際は、まずお問い合わせをもらい、私が手動で環境を構築してから利用開始のフローを計画していました。個人開発でリソースも限られることから、まずはソースコード自動生成に重点を置き、その他は当面手動でもよいかなと。 しかし、企業が運営するプロダクトであればまだしも、個人開発みたいなプロダクトに対して、機能を試すためにお問い合わせまで要するというのは、ユーザーにとって相当なハードルとなり、結果誰も使ってくれないサービスになると考えました。 そこで、アカウント登録したら、すぐにアプリを使えるフローを目指しました。開発に要する作業量はかなり増えましたが、この実現は必須だったと感じています。個人開発だからやらなくてよいことと、個人開発だからこそやらなきゃいけないこと、この切り分けは重要だと感じました。 Dockerコンテナを使って環境構築を自動化 いくつかの実現方法を試し、最終的にはアプリごとにDockerコンテナをポコポコ立ち上げるようにしました。アプリのベースとなるイメージを一つ作成し、生成したソースコードをアプリ専有のコンテナに COPY してから起動し、リバースプロキシを窓口にしてサブドメインごとにコンテナに振り分けています。 また、気軽に試せるようにしたことで「少し試して終わる」アプリが増えることが予想されます。何も対策をしないと、使われなくなったアプリでサーバーのリソースを使い切ってしまうため、一定期間リクエストが無いアプリは自動でコンテナを停止し、改めてリクエストが来た際にコンテナを自動起動するようにしました。 一つのサーバー上にコンテナをたくさん立ち上げる方式のため、今後サービスがスケールしたら課題が残りますが、将来そんな嬉しい事象が見えてきたら、その時検討しようと思っています。 最終的にRailsのプロジェクトは3つになった 以上の機能を実現するために、Railsのプロジェクトを3つにわけました。 エンジン用プロジェクト アプリの設定入力画面 ビルド・デプロイ機能 アプリ用テンプレートプロジェクト アプリの共通機能などを管理 プロジェクトをDockerイメージにして、アプリごとにコンテナを起動する エンジン用プロジェクトで生成したソースコードをアタッチする リクエスト振り分け用プロジェクト リクエストのサブドメインから、振り分け先のアプリコンテナを特定する コンテナが停止していたら起動する 一定期間リクエストがないコンテナを停止する ドキュメントとチュートリアル用のコンテンツ作成 サービス運営に向けて、LPとドキュメント用サイトを作りました。LPは多くの個人開発でも作ると思いますが、ツール系のサービスなので、ドキュメントサイトも必要だと考えました。せっかく興味をもってくれたのに、使い方がわからずに離脱してしまうユーザーを少しでも減らせたらと思います。まだまだコンテンツ量が少ないですが、今後拡充させていければと思っています。 https://docs.sharecrud.com このドキュメントには、チュートリアルとサンプルDBも用意しました。サービスの特性上、ユーザーのDBに接続する必要がありますが、仮に試用であっても、初見のサービスを自分のDBにつなげることには抵抗があると予想します。そこで、チュートリアルでサンプルDBも公開し、そこに接続して試した後であれば、自分のDBに接続するハードルを下げられるのではないかと考えています。 ドキュメントサイトにはVuePress + AWS Amplifyを採用 ドキュメントサイトを作る際、以下の条件にマッチするサービス/ツールを探しました。 マークダウンで記述できる ドキュメントとして使えるUI 動作環境も簡単に作れる 当初は WordPress や GitBook なども検討しましたが、VuePress が今回のニーズに一番あってると判断しました。また、環境構築は AWS Amplify で速攻ででき、感動しました。このあたりは後日別記事でまとめられたらと思います。 ベータ版の開始 〜 サービスの今後 以上の紆余曲折を経て、先日やっとベータ版として公開することができました。文章にまとめるとスムーズに行ったような雰囲気がありますが、実際は苦難の連続でした。本業が忙しいために個人開発に時間を割けない時期もあったとはいえ、当初の着想からトータルで1年くらい要してしまいました。ずいぶんと時間がかかってしまい、リーン開発でいう「MVPを作ってすぐに検証」の定石からは道を外しまくってます。途中何度も辞めようと思いました。 ベータ版で少しでも多くの方にお試しいただき、目処が立ったタイミングで正式リリースの流れを計画しています。これからは、このサービスのプロモーションにも力を入れていこうと思っています。 おまけ - 周りの意見を聞くために、Zoomインタビューをしてみた 個人開発は孤独です。一人で思考していると、どんどん煮詰まって悪循環に陥るときがあります。そんな時に、一人で考えていては単なる想像の世界を抜け出せないと思い、他のエンジニアの方の意見を聞いてみたいと感じました。 そこでクラウドソーシングの「ランサーズ」を使って、エンジニアの方にお声掛けし、有償でインタビューをさせてもらいました。私自身インタビューの経験はなかったのですが、コロナ禍の影響で「Zoomを使ってミーティングする」ことが当たり前になっていたので、検索したエンジニアの方に依頼すると、結構な確率で快諾してくれました(このときインタビューさせてもらったエンジニアの方々には大変感謝しております。) もちろんインタビューをして、それだけですぐに答えが見つかるほど甘くはありません。ましてや私みたいな素人では、インタビューしても何も引き出せないのではと懸念しましたが、他の方と話すことで、以下のメリットがありました。 思考を整理できたので、気持ちが前向きになった 会話の流れで、見落としていた発想を得られた Zoom等でインタビューして、他の人に話したり意見を聞くことは、手軽に大きな効果を得られる場合もありそうです。個人開発では一つの有効な手段かもしれません。 おわりに 長文にお付き合いいただき、ありがとうございました! 現状の反省点としては、個人開発なのに選択したテーマが重く、開発に時間がかかりすぎてしまった点です。個人開発では、アイデアもさることながら、実現に要するボリュームも見極める必要がありそうです。長くても数ヶ月でリリースまでたどり着くほうが、精神的にも健全です。 この記事を見て、個人開発の参考やモチベーション維持に少しでも貢献できたらとても嬉しいです。 最後に、shareCRUDを是非お試しください!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】mysql2のインストールができない場合の対処法【MySQL】

はじめに  本記事は、プログラミング初学者が、学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。  そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。  間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。 mysql2のインストールができない場合の対処法 環境 OS: MacOS Big Sur 11.6.1(M1 mac) Ruby: 2.7.5 Rails: 5.2.6 MySQL: 5.7(8.0でも確認しました。) 状況 データベースをMySQLに指定した上でrails newをした後にbundle installをしても以下のような文章が出力され、インストールできませんでした。 また、インストールができてもrails sをした際にLoad Errorが出てしまう状況でした。 linking shared-object mysql2/mysql2.bundle ld: library not found for -lzstd clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [mysql2.bundle] Error 1 make failed, exit code 2 Gem files will remain installed in /Users/taichi/.anyenv/envs/rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/mysql2-0.5.3 for inspection. Results logged to /Users/taichi/.anyenv/envs/rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/extensions/x86_64-darwin-21/2.6.0/mysql2-0.5.3/gem_make.out An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue. Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds before bundling. In Gemfile: mysql2 解決した方法 私の場合には、以下の方法で解決しました。 openssl@3とzstdをインストール $ brew install openssl@3 zstd openssl@3のパスを通す $ echo 'export PATH="/opt/homebrew/opt/openssl@3/bin:$PATH"' >> ~/.zshrc LIBRARY_PATHにzstdを追加する $ export LIBRARY_PATH=$LIBRARY_PATH:$(brew --prefix zstd)/lib ld-flags に openssl@3/libを追加する $ bundle config --local build.mysql2 "--with-ldflags=-L$(brew --prefix openssl@3)/lib" ※.bundle/configに   BUNDLE_BUILD__MYSQL2: "--with-ldflags=-L/opt/homebrew/opt/openssl@3/lib" と記述されているのを確認する。 bundle installする $ bundle install
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsチュートリアル第十四章 [Follow]ボタン Ajax編

[Follow]ボタン Ajax編 Ajaxを使ったフォローフォーム app/views/users/_follow.html.erb <%= form_with(model: current_user.active_relationships.build, remote: true) do |f| %> <div><%= hidden_field_tag :followed_id, @user.id %></div> <%= f.submit "Follow", class: "btn btn-primary" %> <% end %> Ajaxを使ったフォロー解除フォーム app/views/users/_unfollow.html.erb <%= form_with(model: current_user.active_relationships.find_by(followed_id: @user.id), html: { method: :delete }, remote: true) do |f| %> <%= f.submit "Unfollow", class: "btn btn-default" %> <% end %> RelationshipsコントローラでAjaxリクエストに対応する app/controllers/relationships_controller.rb class RelationshipsController < ApplicationController before_action :logged_in_user # ログインされていることが前提 def create user = User.find(params[:followed_id]) current_user.follow(user) respond_to do |format| format.html { redirect_to @user } # リクエストされるフォーマットがHTML形式の場合 # @userにリダイレクト format.js end end def destroy user = Relationship.find(params[:id]).followed current_user.unfollow(user) respond_to do |format| format.html { redirect_to @user } format.js end end end JavaScriptが無効になっていたときのための設定 config/application.rb require_relative 'boot' require 'rails/all' # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. Bundler.require(*Rails.groups) module SampleApp class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 6.0 # Settings in config/environments/* take precedence over those specified here. # Application configuration can go into files in config/initializers # -- all .rb files in that directory are automatically loaded after loading # the framework and any gems in your application. # 認証トークンをremoteフォームに埋め込む config.action_view.embed_authenticity_token_in_remote_forms = true end end JavaScriptと埋め込みRubyを使ってフォローの関係性を作成する app/views/relationships/create.js.erb $("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>"); $("#followers").html('<%= @user.followers.count %>'); Ruby JavaScript(RJS)を使ってフォローの関係性を削除する app/views/relationships/destroy.js.erb $("#follow_form").html("<%= escape_javascript(render('users/follow')) %>"); $("#followers").html('<%= @user.followers.count %>'); 演習 1. ブラウザから /users/2 にアクセスし、うまく動いているかどうか確認してみましょう。 確認 2. 先ほどの演習で確認が終わったら、Railsサーバーのログを閲覧し、フォロー/フォロー解除を実行した直後のテンプレートがどうなっているか確認してみましょう。 わからなかった。 フォローをテストする [Follow]/[Unfollow]ボタンをテストする test/integration/following_test.rb require 'test_helper' class FollowingTest < ActionDispatch::IntegrationTest def setup @user = users(:michael) # テストユーザー @other = users(:archer) log_in_as(@user) # ログインさせる end test "following page" do # followページに正確にフォッロワーが表示しているかどうかのテスト get following_user_path(@user) # ユーザーのフォロー数を表示させることを要求 assert_not @user.following.empty? # ユーザーのフォローが0でないか確認? assert_match @user.following.count.to_s, response.body # フォロー数がユーザーページにあるかどうか確認? @user.following.each do |user| # ユーザーのフォローしているユーザー数を一つづつ取り出す assert_select "a[href=?]", user_path(user) # ひとつずつ取り出してaタグにユーザーが書かれているか? end end test "followers page" do get followers_user_path(@user) assert_not @user.followers.empty? assert_match @user.followers.count.to_s, response.body @user.followers.each do |user| assert_select "a[href=?]", user_path(user) end end test "should follow a user the standard way" do assert_difference '@user.following.count', 1 do # フォローがひとつだけ増えたか確認 post relationships_path, params: { followed_id: @other.id } end end test "should follow a user with Ajax" do # Ajax用のテスト assert_difference '@user.following.count', 1 do post relationships_path, xhr: true, params: { followed_id: @other.id } # xhr: true Ajaxでリクエストを発行するように変わります。 end end test "should unfollow a user the standard way" do @user.follow(@other) relationship = @user.active_relationships.find_by(followed_id: @other.id) # フォローさせる assert_difference '@user.following.count', -1 do # フォローが一つだけ減ったか確認 delete relationship_path(relationship) end end test "should unfollow a user with Ajax" do @user.follow(@other) relationship = @user.active_relationships.find_by(followed_id: @other.id) assert_difference '@user.following.count', -1 do delete relationship_path(relationship), xhr: true end end end 演習 1. リスト 14.36のrespond_toブロック内の各行を順にコメントアウトしていき、テストが正しくエラーを検知できるかどうか確認してみましょう。実際、どのテストケースが落ちたでしょうか? ERROR["test_should_follow_a_user_the_standard_way", #<Minitest::Reporters::Suite:0x00005639201cf5e8 @name="FollowingTest">, 6.431756742000005] test_should_follow_a_user_the_standard_way#FollowingTest (6.43s) ActionController::UnknownFormat: ActionController::UnknownFormat: RelationshipsController#create is missing a template for this request format and variant. request.formats: ["text/html"] request.variant: [] test/integration/following_test.rb:40:in `block (2 levels) in <class:FollowingTest>' test/integration/following_test.rb:38:in `block in <class:FollowingTest>' ERROR["test_should_unfollow_a_user_the_standard_way", #<Minitest::Reporters::Suite:0x000056392023fa78 @name="FollowingTest">, 6.489258220000011] test_should_unfollow_a_user_the_standard_way#FollowingTest (6.49s) ActionController::UnknownFormat: ActionController::UnknownFormat: RelationshipsController#destroy is missing a template for this request format and variant. request.formats: ["text/html"] request.variant: [] test/integration/following_test.rb:58:in `block (2 levels) in <class:FollowingTest>' test/integration/following_test.rb:56:in `block in <class:FollowingTest>' 73/73: [===========================] 100% Time: 00:00:07, Time: 00:00:07 Finished in 7.62512s 73 tests, 338 assertions, 0 failures, 2 errors, 0 skips 2. リスト 14.40のxhr: trueがある行のうち、片方のみを削除するとどういった結果になるでしょうか? このとき発生する問題の原因と、なぜ先ほどの演習で確認したテストがこの問題を検知できたのか考えてみてください。 わからない。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsチュートリアル第十四章 [Follow]ボタン(基本編)

[Follow]ボタン(基本編) Follow]/[Unfollow]ボタンを動作させましょう そのために Relationshipsコントローラが必要です。いつものようにコントローラを生成しましょう。 ubuntu:~/environment/sample_app (following-users) $ rails generate controller Relationships Running via Spring preloader in process 4782 create app/controllers/relationships_controller.rb # コントローラ invoke erb create app/views/relationships invoke test_unit create test/controllers/relationships_controller_test.rb # テスト invoke helper create app/helpers/relationships_helper.rb # ヘルパー invoke test_unit invoke assets invoke scss create app/assets/stylesheets/relationships.scss # scss リレーションシップの基本的なアクセス制御に対するテスト test/controllers/relationships_controller_test.rb require 'test_helper' class RelationshipsControllerTest < ActionDispatch::IntegrationTest test "create should require logged-in user" do assert_no_difference 'Relationship.count' do # Relationshipのカウントが変わっていないことを確認 post relationships_path end assert_redirected_to login_url end test "destroy should require logged-in user" do assert_no_difference 'Relationship.count' do delete relationship_path(relationships(:one)) end assert_redirected_to login_url # もしログインしていなければログインページにリダイレクトされる end end リレーションシップのアクセス制御 app/controllers/relationships_controller.rb class RelationshipsController < ApplicationController before_action :logged_in_user # ログインされていることが前提 def create end def destroy end end Relationshipsコントローラ app/controllers/relationships_controller.rb class RelationshipsController < ApplicationController before_action :logged_in_user # ログインされていることが前提 def create user = User.find(params[:followed_id]) current_user.follow(user) redirect_to user end def destroy user = Relationship.find(params[:id]).followed current_user.unfollow(user) redirect_to user end end 演習 1. ブラウザ上から /users/2 を開き、[Follow]と[Unfollow]を実行してみましょう。うまく機能しているでしょうか? 確認 2. 先ほどの演習を終えたら、Railsサーバーのログを見てみましょう。フォロー/フォロー解除が実行されると、それぞれどのテンプレートが描画されているでしょうか? users/show.html.erb
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsチュートリアル第十四章[Following]と[Followers]ページ

[Following]と[Followers]ページ どちらにもフォローの統計情報などのユーザー情報を表示するサイドバーと、ユーザーのリスト サイドバーには小さめのユーザープロフィール画像のリンクを格子状に並べて表示する予定です。 フォロー/フォロワーページの認可をテストする test/controllers/users_controller_test.rb require 'test_helper' class UsersControllerTest < ActionDispatch::IntegrationTest def setup @user = users(:michael) @other_user = users(:archer) # テストユーザー end . . . test "should redirect following when not logged in" do get following_user_path(@user) # フォローの数を表示を要求 assert_redirected_to login_url # ログインフォームに移動するか? end test "should redirect followers when not logged in" do get followers_user_path(@user) # フォワーの数を表示を要求 assert_redirected_to login_url end end followingアクションとfollowersアクション app/controllers/users_controller.rb class UsersController < ApplicationController before_action :logged_in_user, only: [:index, :edit, :update, :destroy, :following, :followers] before_action :correct_user, only: [:edit, :update] before_action :admin_user, only: :destroy # before_actionメソッドを使って何らかの処理が実行される直前に # 特定のメソッドを実行する仕組み # ログインをさせる # :editと:updateアクションだけ . . . def following @title = "Following" @user = User.find(params[:id]) @users = @user.following.paginate(page: params[:page]) render 'show_follow' # show_follow.html.erbへ移動させる end def followers @title = "Followers" @user = User.find(params[:id]) @users = @user.followers.paginate(page: params[:page]) render 'show_follow' # show_follow.html.erbへ移動させる end . . . end フォローしているユーザーとフォロワーの両方を表示するshow_followビュー app/views/users/show_follow.html.erb <% provide(:title, @title) %> <div class="row"> <aside class="col-md-4"> <section class="user_info"> <%= gravatar_for @user %> <h1><%= @user.name %></h1> <!--名前--> <span><%= link_to "view my profile", @user %></span> <!--リンク メッセージ リンク先--> <span><b>Microposts:</b> <%= @user.microposts.count %></span> </section> <section class="stats"> <%= render 'shared/stats' %> <% if @users.any? %> <div class="user_avatars"> <% @users.each do |user| %> <%= link_to gravatar_for(user, size: 30), user %> <% end %> </div> <% end %> </section> </aside> <div class="col-md-8"> <h3><%= @title %></h3> <% if @users.any? %> <ul class="users follow"> <%= render @users %> </ul> <%= will_paginate %> <% end %> </div> </div> テスト ubuntu:~/environment/sample_app (following-users) $ rails t Running via Spring preloader in process 8412 Started with run options --seed 21083 65/65: [===========================] 100% Time: 00:00:06, Time: 00:00:06 Finished in 6.54711s 65 tests, 322 assertions, 0 failures, 0 errors, 0 skips 統合テスト作成 ubuntu:~/environment/sample_app (following-users) $ rails generate integration_test following Running via Spring preloader in process 8684 invoke test_unit create test/integration/following_test.rb # 統合テスト 生成 following/followerをテストするためのリレーションシップ用fixture test/fixtures/relationships.yml one: follower: michael # フォロワー followed: lana # フォローされている人 two: follower: michael followed: malory three: follower: lana followed: michael four: follower: archer followed: michael following/followerページのテスト test/integration/following_test.rb require 'test_helper' class FollowingTest < ActionDispatch::IntegrationTest def setup @user = users(:michael) # テストユーザー log_in_as(@user) # ログインさせる end test "following page" do # followページに正確にフォッロワーが表示しているかどうかのテスト get following_user_path(@user) # ユーザーのフォロー数を表示させることを要求 assert_not @user.following.empty? # ユーザーのフォローが0でないか確認? assert_match @user.following.count.to_s, response.body # フォロー数がユーザーページにあるかどうか確認? @user.following.each do |user| # ユーザーのフォローしているユーザー数を一つづつ取り出す assert_select "a[href=?]", user_path(user) # ひとつずつ取り出してaタグにユーザーが書かれているか? end end test "followers page" do get followers_user_path(@user) assert_not @user.followers.empty? assert_match @user.followers.count.to_s, response.body @user.followers.each do |user| assert_select "a[href=?]", user_path(user) end end end テスト ubuntu:~/environment/sample_app (following-users) $ rails tRunning via Spring preloader in process 10581 Started with run options --seed 6735 67/67: [============================] 100% Time: 00:00:07, Time: 00:00:07 Finished in 7.57755s 67 tests, 332 assertions, 0 failures, 0 errors, 0 skips 演習 1. ブラウザから /users/1/followers と /users/1/following を開き、それぞれが適切に表示されていることを確認してみましょう。サイドバーにある画像は、リンクとしてうまく機能しているでしょうか? 確認 2. リスト 14.29のassert_selectに関連するコードをコメントアウトしてみて、テストが正しく red に変わることを確認してみましょう。 わからない。 困ったこと MiniMagick::Error in ActiveStorage::RepresentationsController#show You must have ImageMagick or GraphicsMagick installed
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む