- 投稿日:2021-03-22T23:20:01+09:00
フォームに入力した値の重複の確認
写真のようにフォームに入力した値に重複があるのかを、保存前に確認する方法を見つけることができたので記録します。
ポジションは、f.selectを使用して、選択した値に対応する数字が、
選手名は、f.collection_selectを使用して、対応する選手ID(player.id)が送られるようにしています。フォームから送られるparamsは、以下のようにタイトル、ポジション、名前が存在します。
(starting,relief,closerは、対応する投手の選手IDが入っています。)
今回は、ポジションと選手名に重複がないかを確認します。{"title"=>"サンプル1", "one_position"=>"6", "one_name"=>"11", "two_position"=>"4", "two_name"=>"11", "three_position"=>"4", "three_name"=>"5", "four_position"=>"5", "four_name"=>"14", "five_position"=>"3", "five_name"=>"27", "six_position"=>"7", "six_name"=>"12", "seven_position"=>"9", "seven_name"=>"17", "eight_position"=>"8", "eight_name"=>"3", "nine_position"=>"2", "nine_name"=>"19", "starting"=>"20", "relief"=>"21", "closer"=>"22"}手順
1.処理しやすいように
ポジションと選手名を別々の配列に振り分ける
・ 交互にポジションと選手名に振り分けたいが、starting,relief,closerと連続で選手のIDが入っているので、一旦切り分ける
2.ポジションと選手名を分ける。
3.重複の確認処理しやすいように分ける
field_player = params[:best_nine].values[1..-4] #タイトルと投手情報以外をいれる pitcher = params[:best_nine].values[-3..-1] #投手の選手IDをいれるポジションと選手を分ける
each_slice(n)で、n要素ずつブロックに渡してを繰り返す。- ・野手のポジションと選手IDがブロックに渡される(
[[one_position, one_name],[two_position, two_name], ・・・])- ・ブロックの1つ目をポジション、最後(2つ目)を選手名として扱う
- ・Ruby 3.0.0 リファレンスマニュアル
playerには、投手の選手IDを追加する。- ・配列に配列をpushで挿入すると、二重配列のような形になるので、
flattenを用いて平坦化するposition = field_player.each_slice(2).map(&:first) # field_player.each_slice(2).map {|n| n.first} と同じ処理 player = field_player.each_slice(2).map(&:last).push(pitcher) player.flatten!重複がないか確認
配列の要素の数と、配列内で重複していない要素の数の差が0でなければ、重複した値があると判定します。
if ((position.count - position.uniq.count) != 0 || (player.count - player.uniq.count) != 0)全てのコード
field_player = params[:best_nine].values[1..-4] pitcher = params[:best_nine].values[-3..-1] position = field_player.each_slice(2).map(&:first).push(pitcher) # {|n| n.first} position.flatten! player = field_player.each_slice(2).map(&:last) if ((position.count - position.uniq.count) != 0 || (player.count - player.uniq.count) != 0)参考記事
Ruby | 配列の奇数番目と偶数番目を取り出す方法
Ruby 3.0.0 リファレンスマニュアル (※each_slice)
Rubyで複数の配列を1つの配列に結合するために色々やってみた
重複した要素を取り除く
- 投稿日:2021-03-22T19:47:31+09:00
【超かんたん】Railsのscopeってなんぞや?
scopeの使い方をレシピアプリを例に解説、設定していきます。
scopeとは
そもそもscopeとは何なのか? Railsガイドでは以下のように説明されています。
スコープを設定することで、関連オブジェクトやモデルへのメソッド呼び出しとして参照される、よく使用されるクエリを指定することができます。スコープでは、where、joins、includesなど、これまでに登場したすべてのメソッドを使用できます。どのスコープメソッドも、常にActiveRecord::Relationオブジェクトを返します。このオブジェクトに対して、別のスコープを含む他のメソッド呼び出しを行なうこともできます。
単純なスコープを設定するには、クラスの内部でscopeメソッドを使用し、スコープが呼び出されたときに実行して欲しいクエリをそこで渡します。
出典:Railsガイドむむ、なんか難しそう...
と思われる方も多いかもしれませんが簡潔にまとめるとscopeとはwhere、order、limitなどの複数のクエリをまとめたメソッドになります。文章だけでは難しく感じると思うので実際にコードを見ていきましょう。
scopeの使い方の例
例えば以下のようにしてレシピ情報を取得するとします。
app/controllers/recipes_controller.rbclass RecipesController < ApplicationController ... def index @recipes = Recipe.order(created_at: :desc).limit(10) end ... end上記のコードの
order(created_at: :desc).limit(10)の部分をrecentと命名しモデルにまとめていきます。app/controllers/recipes_controller.rbclass Recipe < ApplicationRecord ... scope :recent, -> {order(created_at: :desc).limit(10} ... end上記で定義したscopeを使用します。
app/controllers/recipes_controller.rbclass RecipesController < ApplicationController ... def index @recipes = Recipe.recent end ... end以上が使い方の例になります。
scopeのメリット
scopeを使うことによって以下のようなメリットがあります。
・ コードが簡潔になる
・ 修正する場合修正箇所が少なくなる
・ 自分で命名できるので直感的に扱いやすくなる先ほどの例で説明すると以下のコードは同じ意味になりますが、scopeを使用した方がより簡潔になります。
app/controllers/recipes_controller.rbclass RecipesController < ApplicationController ... def index #scopeを定義しなかった場合 @recipes = Recipe.order(created_at: :desc).limit(10) #scopeを定義した場合 @recipes = Recipe.recent end ... endscopeの設定方法
scopeがどんなものか理解できてきたと思うので、設定の仕方について説明していきます。
基本的な設定方法
class モデル名 < ApplicationRecord scope :スコープ名, -> { 条件式 } end第一引数にシンボルを使ってスコープ名設定し、第二引数は-> { 条件式 }とします。
先ほどの例でいうと条件式はorder(created_at: :desc).limit(10)になります。引数を使う場合
->のあとに引数を定義すると引数を渡すことができます。
class モデル名 < ApplicationRecord scope :スコープ名, -> (引数) { 条件式 } end先ほどの例で説明するとlimitで取得したい数を引数にします。
app/controllers/recipes_controller.rbclass Recipe < ApplicationRecord ... scope :recent, -> (count) {order(created_at: :desc).limit(count)} ... endapp/controllers/recipes_controller.rbclass RecipesController < ApplicationController ... def index @recipes = Recipe.recent(10) end ... end
- 投稿日:2021-03-22T18:46:50+09:00
解決!Rubyのバージョンアップに伴うトラブル|rails コマンドが動かない
1. 状況
1) 開発環境にあったプロジェクトをherokuにpushしようとしたところ、ruby のバージョンが 2.6.3 になっているけど、2.6.6 を使用しろと言われた。
2) これは、なんとか解決。その時の戦記はこちら。
3) 無事にherokuにpushはできた。
4) しかし、そのあと、rails s しようとしたところ、謎のエラーが出た。環境% ruby -v ruby 2.6.6p146 (2020-03-31 revision 67876) [x86_64-darwin20] % rbenv versions system 2.5.1 2.6.3 * 2.6.6 (set by /Users/randytozuka/.rbenv/version) % gem -v 3.2.15エラー文
ターミナル% rails s /Users/randytozuka/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-1.17.2/lib/bundler/rubygems_integration.rb:200: warning: constant Gem::ConfigMap is deprecated Traceback (most recent call last): 71: from bin/rails:3:in `<main>' 70: from bin/rails:3:in `load' 69: from /Users/randytozuka/Desktop/deskschedule2-master/bin/spring:15:in `<top (required)>' (中略) 2: from /Users/randytozuka/Desktop/deskschedule2-master/vendor/bundle/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/loaded_features_index.rb:89:in `register' 1: from /Users/randytozuka/Desktop/deskschedule2-master/vendor/bundle/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi' /Users/randytozuka/Desktop/deskschedule2-master/vendor/bundle/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require': cannot load such file -- etc (LoadError)2. 対応
ググってみたところ、先人がこのようなアドバイスを残してくれていた。
・bundle install をしろ
・gem install bundler を試してみろ
・gem を update したら bundler も update せよ
・RubyGemsのバージョンをupdate か downgradeして、bundlerのバージョンと相性のよいバージョンに合わせろターミナル% gem update --system Latest version already installed. Done. % gem update bundler Updating installed gems Nothing to update % gem list rubygems-update *** LOCAL GEMS *** rubygems-update (3.2.15)状況変わらず…(TT)
ここでメンターさんから、これやってみと教えていただいた事をやってみる。その1gem uninstall -I -a -x --user-install --force ERROR: While executing gem ... (Errno::ENOTEMPTY) Directory not empty @ dir_s_rmdir - /Users/randytozuka/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rails-6.1.3エラーか強い心でスルーする。
その2gem install bundler Fetching bundler-2.2.15.gem Successfully installed bundler-2.2.15 1 gem installedその3、ここでGemfile.lock を削除して,
その4% bundle install % rails sどうじゃ!! お?? エラーがちょっと変わった。
ん〜〜〜となったところで,たまたま見た記事 にあった ↓ を試してみる。ターミナル% bundle install --redownload解決! やった!
3. まとめ
丸一日彷徨いました。
今回のトラブルは、ruby 及び rails のバージョンを上げたが、gem がそれについてきていなかったので、もう一回最新の gem のライブラリを読み込んだら解決した…ということだったのかなと。安易にrubyのバージョンあげると大変だよということでいい勉強させてもらいました。
- 投稿日:2021-03-22T18:38:57+09:00
【Rails】投稿したURLをリンク可能にする方法
投稿したURLをリンクにしたい!!!
結論からいうと、Gemをインストールすれば簡単に解決できます!
イメージが湧きやすいように実際の画像で説明します。
↓↓↓↓↓↓
②このような感じでリンクが押せない状態で投稿されてしまう。
rinku というGemをインストールすれば問題は解決できる。
③Gemfileにrinkuを追加。
gem 'rinku'bundle installこれでrinkuをインストールできました。
viewのコードをrinkuに対応した形式に書き換える。
④erbファイルを、rinkuに対応したコードに書き換えます。
<%= post.link %>↓↓↓↓↓
<%= Rinku.auto_link(post.link, :all, 'target="_blank"').html_safe %>これだけでリンクとして反映されています。
ただこれだけだと、もしもリンクを投稿しない場合、「データがnilですよ」というエラーが発生する可能性があります。
そんな時はlinkの投稿フォームにあらかじめバリデーションをかけておくか、<% if post.link.nil? %> <%= post.link %> <% else %> <%= Rinku.auto_link(post.link, :all, 'target="_blank"').html_safe %> <% end %>...と、if文でlinkというカラムにデータが存在するか否かを条件分岐してあげれば解決できます。
ちなみに、'target="_blank"'があると外部リンク、無いと内部リンクになるようです。確認してみると、このようにリンクといえばお馴染みの青色が着色されました。
リンクを押せば、外部のサイトにも飛べるようになるはずです。
- 投稿日:2021-03-22T17:57:50+09:00
ユーザー管理機能をDeviseを使って実装する方法(Rails)
RailsにDeviseを導入する方法(学習記録)
![]()
1: Gemのインストール
まずdeviseというGemをインストールします
# Gemfile # 追記 gem 'devise # Gemのインストール % bundle install2: rails g devise:installコマンドの実装
# deviseの設定ファイルを作成 % rails g devise:install3: rails g deviseコマンドでdeviseに管理させたいモデルを生成
# deviseコマンドでUserモデルを作成 % rails g devise user # マイグレーションファイルも自動生成される4: マイグレーションの実行
# マイグレーションを実行 % rails db:migrate5: deviseのビューを作成
※ deviseでログイン機能を実装すると、ログイン/サインアップ画面が自動的に生成されますがビューファイルとしては生成されません。これは、deviseのGem内に存在するビューファイルを読み込んでいるためです。deviseのビューファイルに変更を加えるためには、deviseのコマンドを利用して、ビューファイルを生成する必要があります。
% rails g devise:views # 生成されたビューファイルを独自に編集5: カラムの追加
※ 現在、サインアップ時に登録する情報はメールアドレスとパスワードの2つです。これに加えて名前を登録できるようにしましょう。
テーブルにカラムを追加するために、マイグレーションを生成する必要があります。1.rails g migrationコマンド
マイグレーションを生成するコマンドです。
マイグレーションはこれまで、rails g modelコマンドでモデルと一緒に生成されていましたが、すでに作成されたテーブルの内容を変更する際などに使用します。2.usersテーブルにnameカラムをstring型で追加
# usersテーブルにnicknameカラムをstring型で追加するマイグレーションファイルを作成 % rails g migration AddNameToUsers name:string # 作成したマイグレーションを実行 % rails db:migrate3.ストロングパラメーターを使えるようにする
※ サインアップ時に入力する情報はパラメーターとしてサーバーに送信されます。deviseを使わない通常のリクエストの場合は、コントローラーにストロングパラメーターを記述し、受け取れるパラメーターを制限していました。deviseに関しても、同様にストロングパラメーターをコントローラーに記述します。しかし、deviseの処理を行うコントローラーはGem内に記述されているため、編集することができません。
4.devise_parameter_sanitizerメソッド
deviseにおけるparamsのようなメソッドです。deviseのUserモデルに関わる「ログイン」「新規登録」などのリクエストからパラメーターを取得できます
# application_controller.rbを編集 # sign_up(新規登録の処理)に対して class ApplicationController < ActionController::Base before_action :configure_permitted_parameters, if: :devise_controller? private def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) end end以上がユーザー管理機能をDeviseを使って実装する方法です!参考までにどうぞ!!
- 投稿日:2021-03-22T17:30:43+09:00
【Rails】credentials.yml を使って管理画面を作る(その1)
■ はじめに
皆さん、こんにちは。
コロナの影響もあって外出するのも、スティホームするのも大変ですよね。さて、皆さんは管理機能ってどうされてます?
'rails_admin'などのgemを使ったり、独自に同様の機能を実装されてたりしていますか?私もそうしたgemを使ったことがあるのですが、特定のカラムに特定の値が入っているかどうかで、管理画面へのアクセスにできてしまうことに、ちょっと怖さを感じてしまうことがあります(汗)
そこで、特定の管理者にのみ完全な管理画面へのアクセスを許可し、その管理者から一部のアクセス権を付与するのはどうだろうかと考えました。
(*以下、アクセス権を付与できる者を管理者、管理者からアクセス権を付与されたユーザーをパートナーとします。)
具体的には、
- 管理者のみ、完全な管理画面へのアクセスを可能にする。
- その管理者はアクセス権を他者に付与することができる。
- アクセス権を付与されたパートナーは管理画面の一部にアクセスすることができ、一部の管理機能を使うこともできる。
- 管理者でもなく、アクセス権を持っていない一般ユーザーは管理画面にアクセスできない。上記の形であれば、仮にパートナーのIDが第三者に乗っ取られてしまっても、被害をある程度限定することができるし、管理者がアクセス権を早急に剥奪してしまえば、事態の収束も早くできるかと考えました。
今回のテストアプリケーションは、そうした考えを元に管理画面の分岐を自前で実装したものになります。そのため注力していない部分はあっさりしておりますが、温かい目で見て頂けると嬉しいです。また、ご意見やご感想、セキュリティ部分でのご指摘等々頂けると幸いです。
■ 本記事での試み
本記事ではRils5.2から追加された「credentials.yml」を使って、特定のメールアドレスからログインしたユーザーを管理者として扱い、管理画面を作成します。
管理画面は管理者のみアクセス可能で、一般ユーザーがアクセスを試みるとトップページヘリダイレクトするようにします。
*管理者がパートナーにアクセス権を付与する機能の実装は別記事にて記載します。
[DEMO]
下の動画では、左側が管理者でログインした場合、右側はそれ以外でログインした場合になります。管理者にはヘッダーの部分に'管理画面'が表示されていますが、一般ユーザーの方には表示されていません。また、一般ユーザーが管理画面にアクセスすると、「アクセスをブロックしました」というメッセージ表記と共にトップページが表示されます。
■ 開発環境
- OS:macOS Big Sur 11.2.3
- Ruby:3.0.0
- Ruby on Rails:6.1.3
- ローカル環境DB:Mysql
- テキストエディタ:Visual Studio Code ***
■ アプリの立ち上げからデータベースの作成まで
まずは rails new を使ってアプリケーションを作成しましょう。今回はmysqlをデータベースに使用しますが、データベースはお好みのものをお使いください。
$ rails new access_test -d mysql $ cd access_test(以降の作業でmysqlのエンコードがuft8mb4だとエラーが起きてしまうので、rails db:createを行う前に config/database.yml を編集します。仮に先に db:create を行ってしまった場合は、db:drop で一度データベースを破棄してください。)
config/database.ymlencoding: uft8 # utf8mb4から変更database.ymlを変更したら、 rails db:create でデータベースを作成します。
$ rails db:create
■ gem 'devise'の導入から rails db:migrateまで
今回はgem 'devise'を利用してログイン機能を実装します。
まずはGemfileの最下部にgem 'devise'を追記します。gem 'devise'次にターミナルで bundle install、rails g devise:install、rails g devise User を実行します。
$ bundle install $ rails g devise:install $ rails g devise User- 参考記事 -
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
(*)今回は仮のメールアドレスを使用するためメール認証を実装しませんが、devise のメール認証を実装すると、仮に管理者用に設定したメールアドレスが特定されてしまったとしても、認証で送られてきたメールを開いて認証行動を行わない限り、そのメールアドレスはサービス内で利用できない状態を保てます。その後は管理者用に設定するメールアドレスを変更したり、一定回数ログインに失敗したアカウントをロックしたりすることで、安全性を保った状態でサービスを運用できるかと思います。
参考記事
(1)Rails deviseによるユーザー認証 メールによる認証、emailとusernameのどちらでもログイン可能にするまで
(2)【Rails】メール送信設定 〜gmail利用〜
(3)How To: Add :lockable to Users
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
次に一般ユーザーが利用できる架空のサービスとして、Post機能を scaffold を使って導入していきましょう。
$ rails g scaffold Post text:text user:references上記のコマンドでPost機能の実装はだいぶ進みましたね。
ここから先はいろいろなファイルの中身に触れていくので、焦らずじっくりいきましょう。まずは、devise による「ユーザーがログインしているかどうかを判別する機能」をアプリケーション全体で機能させるために、application_controller.rb にauthenticate_user! メソッドをbefore_actionで追記します。
app/controllers/application_controller.rbclass ApplicationController < ActionController::Base before_action :authenticate_user! end次に、ユーザーを削除した際にそのユーザーが投稿したものが残ってしまうことがないように、PostモデルとUserモデルの関係性を記述します。
app/models/user.rbclass User < ApplicationRecord devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable has_many :posts, dependent: :destroy endapp/models/post.rbclass Post < ApplicationRecord belongs_to :user end(今回はUser(主)がいくつものPost(従)を持てる関係のため、Userモデルに has_many :posts、Postモデルに belongs_to :user としています。その上でUserが削除された際に、そのUserが投稿していたPostも全て削除されるように、「 has_many :posts, dependent: :destroy 」としています。)
これでモデルの関係性も構築できたので、以下のコマンドを実行してマイグレーションファイルをupしましょう。
$ rails db:migrate
■ ルーティングの設定からPost機能実装まで
さて、マイグレーションファイルも up しましたし、今度はサインアップを行うためのルーティングの整備だったり、投稿を行うための諸設定を整えていきましょう。
まずはconfig/routes.rbの中身を以下のように変更します。
config/routes.rbRails.application.routes.draw do root to: "posts#index" devise_for :users resources :posts end次に、scaffold で作成した諸々のファイルを整備していきましょう。手始めにposts_controller.rb内の post_params を以下のように書き換えます。
app/controllers/posts_controller.rbdef post_params params.require(:post).permit(:text).merge(user_id: current_user.id) end今度はviewファイルの編集です。application.html.erbを開いて、header 部分の実装、その header にログイン関係のリンクを実装しましょう。( devise による user_signed_in? でユーザーがログイン状態にあるかないかを判別しています。)
app/views/layouts/application.html.erb<body> <header> <div> <% if user_signed_in? %> <%= link_to 'ログアウト', destroy_user_session_path, method: :delete %> <% else %> <%= link_to 'サインアップ', new_user_registration_path %> | <%= link_to 'ログイン', new_user_session_path %> <% end %> </div> </header> <p class="message"><%= flash[:message] %><p> <p class="alert"><%= alert %></p> <%= yield %> </body>今のままだと header 部分も真っ白になってしまうので、ちょっと cssファイルで headerに色をつけましょう。(今回は安直にapplication.css の最下部に header の背景カラーを追加します。)
app/assets/stylesheets/application.cssheader { background-color: lightgray; }次に _form.html.erb に残っている下記の部分を削除します。
app/views/posts/_form.html.erb<!-- ここから以下の箇所までを削除 --> <div class="field"> <%= form.label :user_id %> <%= form.text_field :user_id %> </div> <!-- 以上の箇所からここまでを削除 -->続いて、誰が投稿したのかを分かりやすくするために、今回はEmailを表示させるようにしましょう。(本番のサービスではEmailではなく、name等を表示させるようにしてくださいね。)
app/views/posts/index.html.erb<table> <thead> <tr> <th>Text</th> <th>User_Email</th> <!-- 変更--> <th colspan="3"></th> </tr> </thead> <tbody> <% @posts.each do |post| %> <tr> <td><%= post.text %></td> <td><%= post.user.email %></td> <!-- 変更--> <td><%= link_to 'Show', post %></td> <td><%= link_to 'Edit', edit_post_path(post) %></td> <td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td> </tr> <% end %> </tbody> </table>app/views/posts/show.html.erb<p id="notice"><%= notice %></p> <p> <strong>Text:</strong> <%= @post.text %> </p> <p> <strong>User_Email:</strong> <!-- 変更--> <%= @post.user.email %> <!-- 変更--> </p> <%= link_to 'Edit', edit_post_path(@post) %> | <%= link_to 'Back', posts_path %>
■ credentials.ymel.encの編集から管理画面のコントローラー実装まで
ここまでの作業お疲れさまでした。
さて、本記事の肝心要の部分に入っていきます。
先程よりも手を動かす箇所が多いので、焦らずゆっくり進めていきましょう!まずは credentials の中身を変更するためにコマンドを入力しましょう。
$ EDITOR='code --wait' rails credentials:edit(私はVSCodeを利用しているため、上記でcredentialsの編集画面が表示されますが、他のエディタを利用されている方は以下の参考記事を元にcredentialsの編集画面を開きましょう。)
- 参考記事 -
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
参考記事
(4)Rails5.2のrails credentials:editを好きなエディタで編集する(macOS)
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
credentials の中身に今回の管理者用のメールアドレス(test@test.com)を、キー(access_user:)と共に追加します。追加後、credentials.yml.encファイルを閉じると変更内容が保存され、以降「 Rails.application.credentials[:access_user] 」で test@test.com を呼び出すことが可能になります。
(config/master.key の情報が外部に漏れなければ、他者が credentials.yml の中身を見ることはできません。仮にアプリケーションのコードがGitHub上に公開されてしまったとしても、master.key の情報が無ければ、管理者用として設定されているメールアドレスがなんであるかはコードを見ただけでは特定されることはありません。)
credentials.yml.enc# aws: # access_key_id: 123 # secret_access_key: 345 ..... <以下を追加> access_user: test@test.com .....次に管理画面へのルーティングを設定します。今回はUsersコントローラーを利用して、管理画面の表示とユーザーの削除を考えているので、以下のようにroutes.rbを設定します。
config/routes.rbRails.application.routes.draw do root to: "posts#index" devise_for :users resources :posts resources :users, only: [:index, :destroy] # 追加 endコマンド入力で Users コントローラーを作成します。
$ rails g controller users続いて、Users コントローラーの中身を記述していきましょう。
(今回は一般画面と管理画面の区別がわかりやすいようにlayoutを指定しています。後ほど、access_layoutのhtml作成と、cssを追記します。)app/controllers/users_controller.rbclass UsersController < ApplicationController before_action :access_user layout "access_layout" def index @users = User.all @posts = Post.includes(:user) end def destroy user = User.find(params[:id]) user.destroy flash[:message] = "ユーザーを削除しました" redirect_to users_path end private def access_user unless current_user.email == Rails.application.credentials[:access_user] flash[:message] = "アクセスをブロックしました" redirect_to root_path end end endaccess_user メソッドはログインしているユーザーのメールアドレスと、管理者用に設定したメールアドレス(Rails.application.credentials[:access_user])が一致しなかった場合、flash[:message]に"アクセスをブロックしました"という文字列を代入して、トップページヘリダイレクトさせます。
(本番のサービスではリダイレクトではなく、何もないURLにアクセスを試みた時と同様のエラーを返す仕組みにすれば、悪意あるユーザーに管理画面へのURLを知られずに済むかと思います。)
これで大まかな機能の実装は完了です。もう少しでこの記事の作業も終わりますので、あと一息頑張りましょう!
■ 管理画面の view ファイルの作成から css の設定まで
ここまでの作業お疲れさまです。本記事も残すところあと僅かです!一緒に頑張りましょう!
まずは、application.html.erb の header 部分に管理画面へのリンクを追加します。
app/views/layouts/application.html.erb<header> <div> <% if user_signed_in? %> <%= link_to 'ログアウト', destroy_user_session_path, method: :delete %> <% if current_user.email == Rails.application.credentials[:access_user] %> ||| <%= link_to '管理画面', users_path %> <% end %> <% else %> <%= link_to 'サインアップ', new_user_registration_path %> | <%= link_to 'ログイン', new_user_session_path %> <% end %> </div> </header>if current_user.email == Rails.application.credentials[:access_user] の記述で、ログインしているユーザーのメールアドレスとcredentials.ymelに設定したメールアドレスが一致していたら、'管理画面'のリンクが現れるようにしています。次に先程作成した管理画面のリンク先であるindex.html.erbを、app/views/usersファイル内に手動で作成して以下のように記載します。(*この時点でrails s を実行して管理画面にアクセスしても、access_layout.html.erbをまだ作成していないためエラーになります。)
app/views/users/index.html.erb<h1>管理画面</h1> <table>==== ユーザー一覧 ==== <thead> <tr> <th>ユーザーID</th> <th>メールアドレス</th> <th colspan="3"></th> </tr> </thead> <tbody> <% @users.each do |user| %> <tr> <td><%= user.id %></td> <td><%= user.email %></td> <td><%= link_to 'Destroy', user_path(user), method: :delete, data: { confirm: 'ユーザーを本当に削除しますか?' } %></td> </tr> <% end %> </tbody> </table> <br> <table>==== 投稿一覧 ==== <thead> <tr> <th>投稿ID</th> <th>投稿内容</th> <th>投稿者ID</th> <th>投稿者メールアドレス</th> <th colspan="3"></th> </tr> </thead> <tbody> <% @posts.each do |post| %> <tr> <td><%= post.id %></td> <td><%= post.text %></td> <td><%= post.user_id %></td> <td><%= post.user.email %></td> <td><%= link_to 'Destroy', post_path(post), method: :delete, data: { confirm: 'この投稿を本当に削除しますか?' } %></td> </tr> <% end %> </tbody> </table> <br> <%= link_to '一般トップページへ', root_path %>続いて、access_layout.html.erb を、 app/views/layouts ファイル内に手動で作成して以下のように記載します。
app/views/layouts/access_layouts.html.erb<!DOCTYPE html> <html> <head> <title>管理画面</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> </head> <body class='access'> <header> <div> <% if user_signed_in? %> <%= link_to 'ログアウト', destroy_user_session_path, method: :delete %> <% if current_user.email == Rails.application.credentials[:access_user] %> ||| <%= link_to '管理画面', users_path %> <% end %> <% else %> <%= link_to 'サインアップ', new_user_registration_path %> | <%= link_to 'ログイン', new_user_session_path %> <% end %> </div> </header> <p class="message"><%= flash[:message] %><p> <p class="alert"><%= alert %></p> <%= yield %> </body> </html>そして、管理画面のみブラックモードのような画面にして、一般画面との違いが分かりやすくしましょう。(今回は安直にapplication.cssの最下部に以下を追記します。)
app/assets/stylesheets/application.css.access { background-color: black; color: white; } a { color: lightgray; }
■ サーバーの起動と実装した部分の確認
作業お疲れさまでした。
これで管理者と一般ユーザーのアクセスできる部分を分けることができました。実際に rails s コマンドを実行してサーバーを立ち上げて確認してみてください。$ rails s
application.credentials[:access_user]に設定したメールアドレスでログインした場合と、そうでない場合でヘッダーに'管理画面'の表示の有無が確認できたでしょうか?
また、application.credentials[:access_user]に設定したメールアドレス以外でログインした場合、 http://localhost:3000/users にアクセスするとどうなりましたか?
[DEMO]
下の動画では、左側が管理者でログインした場合、右側はそれ以外でログインした場合になります。管理者にはヘッダーの部分に'管理画面'が表示されていますが、一般ユーザーの方には表示されていません。また、一般ユーザーのブラウザで http://localhost:3000/users にアクセスすると、「アクセスをブロックしました」というメッセージ表記と共にトップページが表示されていますね。
■ 本記事の最後に
本記事は以上になります。お疲れさまでした。
冒頭のはじめにで記載しました管理者からパートナーへのアクセス権の付与や、パートナーの限定的管理機能の実装につきましては、別の記事にて記載したいと思います。
本記事で作成したアプリケーションのコードは、以下のGitHub上から閲覧できますので適宜ご活用ください。
最後に
ここまで読んでいただき、ありがとうございました!!
- 投稿日:2021-03-22T17:19:32+09:00
Rails API 設定
[API 設定方法]
通常のrails newコマンドの末尾に--apiをつけることでAPIモードでアプリを作成することができる。
(APIに必要ない部分をデフォルトで作成しなくなる。)--apiをつけない場合
config/application.rbのApplicationクラス定義の冒頭に、次を追加します。
config.api_only = trueapp/controllers/application_controller.rbの以下のコードを置き換えます。
class ApplicationController < ActionController::Base end上を以下に変更します。
class ApplicationController < ActionController::API endrouting分割方法
rails6.1からroutes.rbのファイルを複数に分けることができるようになった。
- ファイル分割する際のディレクトリ構成
├─ routes.rb │ └─ routes/ #ここに分割したroutesファイルを格納 ├─ api.rb └─ admin.rb
- routes.rbの記載を変更
draw(:読み込みたいファイル名)
Rails.application.routes.draw do draw(:api) #別ファイルのルーティングを読み込む draw(:admmin) #別ファイルのルーティングを読み込む end
- routesディレクトリ&外部ファイルの作成
以下のディレクトリ構成になるようにroutesディレクトリと外部ファイルを作成します。
config ├─ routes.rb │ └─ routes/ #このディレクトリを作成 ├─ api.rb #外部ファイルを作成 └─ admin.rb #外部ファイルを作成
- 投稿日:2021-03-22T17:08:41+09:00
docker-compose Rails + Postgresql環境構築
作業ディレクトリと必要なファイルを作成
まず開発していくディレクトリとアプリケーションを構築するために必要なファイルを作成する
必要なファイル
Dockerfile
Gemfile
Gemfile.lock
entrypoint.sh
docker-compose.yml
$ mkdir myapp $ cd myapp $ touch {Dockerfile,Gemfile,Gemfile.lock,entrypoint.sh,docker-compose.yml} $ ls Dockerfile Gemfile.lock entrypoint.sh Gemfile docker-compose.ymlファイルの中身を記述してく
Rails6ではwebpackerが搭載されyarnのインストールが必要
DockerfileFROM ruby:2.6.6 RUN 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 RUN apt-get update -qq && apt-get install -y nodejs postgresql-client yarn 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.Gemfilesource 'https://rubygems.org' gem 'rails', '6.0.3'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.ymlversion: '3' services: db: image: postgres volumes: - ./tmp/db:/var/lib/postgresql/data environment: - POSTGRES_PASSWORD=password 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プロジェクトの構築
作成したファイルを利用してdocker-compose runを実行しアプリケーションを生成
$ docker-compose run web rails new . --force --no-deps --database=postgresqlそして
$ docker-compose build . . . Successfully built 0b14a3eedc73 Successfully tagged myapp_web:latestimageを構築
- 投稿日:2021-03-22T16:18:17+09:00
【Ruby on Rails6.0】データベースを指定してアプリ作成
前提
■あくまで個人の備忘録。見やすは非重視
■PostgreSQLが既にインストールされていること
※されていない場合は以下でインストールとPath設定を完了させる
PostgreSQL インストール方法Rubyインストール
★以下のサイトからWITH DEVKITの推奨版をダウンロード
※サイト内左側の一覧に「=>」となっているものが推奨★ダウンロードしたファイルで設定を進める
※途中コマンドプロンプトにて入力を求められた場合には、各々指定が無ければ「1,2,3」と入力★ダウンロードが完了したら、コマンドプロンプトを起動し、バージョンを確認し正常に確認出来たらインストールされている
# コマンドプロンプト $ ruby -v# 出力結果 ruby 2.7.2p137(2020-10-01 reversion 5445e04352) [x64-mingw32]※「$」は入力不要
Railsインストール
■以下のコードを実行し、Railsをインストールする
# コマンドプロンプト $ gem install rails■Railsがインストールされたかを確認するために、バージョンを確認
# コマンドプロンプト $ rails -v# 出力結果 Rails 6.1.3Yarnインストール
★以下のコードを実行し、Yarnをインストールする
# コマンドプロンプト $ npm install --global yarn★Yarnがインストールされたかを確認するためにバージョンを確認
# コマンドプロンプト $ yarn -v# 出力結果 1.22.10Node.jsインストール
■以下サイトでNode.jsをダウンロード・インストールを実行
■システム詳細設定内の環境変数(ユーザ環境変数)にPathを設定
デフォルトの場合の設定:C:\Program Files\Nodejs
■Node.jsがインストールされたかを確認するためにバージョンを確認
# コマンドプロンプト $ node -v# 出力結果 v14.16.0アプリの作成
★コマンドプロンプトで以下のコードを実行
# コマンドプロンプト $ rails new (アプリ名) -d postgresql★アプリケーション毎にGemバージョンを管理する場合は以下を実行
# コマンドプロンプト $ rails new (アプリケーション名) -d postgresql --skip-bundle★インストール完了後にアプリケーションディレクトリに移動し、以下のコードを実行
# コマンドプロンプト # 初回のみ以下 $ bundle install --path vendor/bundle # 2回目以降 $ bundle installデータベースの連携
■psql.exe が保存されたディレクトリをPatchに設定
デフォルトの場合の設定:C¥:Program Files¥PostgreSQL¥(バージョン)\bin
■作成したアプリケーションの以下のファイルを編集
ルート:(アプリケーション名)\config\database.yml#省略 default: &default adapter: postgresql encoding: unicode username: postgres #デフォルトの場合 password: postgres #デフォルトの場合 #省略Railsアプリの起動・表示
★cdコマンドでアプリケーションディレクトリに移動
★以下のコードを実行
# コマンドプロンプト $ rails s※「Use Ctrl-C to stop」の出力が表示されたらサーバー接続完了
★ブラウザで以下のURLにアクセスし、画像の表示になれば無事設定完了
localhost:3000★サーバーとの接続を解除する場合は「Use Ctrl-C to stop」と出力された状態のコマンドプロンプトで「Ctrl」+「C」を入力し停止
⇒コマンド入力待機に切り替わったら接続解除完了
- 投稿日:2021-03-22T15:21:45+09:00
[ Rails ] turbolinksの概要と一部使い方
RailsでECサイトを作成中に、一部ボタンが動作しないことがあり、turbolinksを一部無効化することで解決しました。
そもそもturbolinksとは何ぞや状態だったので、備忘録として残しておきます。turbolinksとは
ページ遷移をAjaxに置き換えることで、JavaScriptやCSSのパースを省略することで高速化するgemのこと。
Railsにデフォルトで入っているやつ。完全にturbolinksを無効化する方法
※ turbolinksを完全無効化すると、他の高速化するgemを入れたりする必要があるので、
私のような初心者は、特別なことがない限りおすすめしないです。1. gemを無効化する
Gemfile#コメントアウトをする #gem 'turbolinks'ターミナル$ bundle update2. application.jsを編集
application.js// 変更前 //= require turbolinks // 変更後 // require turbolinks3. application.html.slimを編集
application.html.slim/ 変更前 = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' = javascript_include_tag 'application', 'data-turbolinks-track': 'reload' / 変更後 = stylesheet_link_tag 'application', media: 'all' = javascript_include_tag 'application'一部を無効化する方法
1. JavaScriptを編集する方法
・.jsファイルの場合
hoge.js$(document).on('turbolinks:load', function() { // turbolinksを無効化したい処理を入れる });・.coffeeファイルの場合
hoge.coffee$(document).on 'turbolinks:load', -> # turbolinksを無効化したい処理2. リンクを編集する方法
・link_toに追加する場合
hoge.html.slim= link_to '', root_path, 'data-turbolinks': false'data-turbolinks': false をlink_toに追加すれば無効化できます。
・divの場合
hoge.html.slimdiv data-turbolinks='false' = link_to '', root_path
- 投稿日:2021-03-22T13:52:25+09:00
【Refile】attachment_image_tag の書き方
- 投稿日:2021-03-22T12:58:44+09:00
Refileの保存先をS3に変更する(Rails, AWS)
環境
- Ruby 2.6.3
- Rails 5.2.4
[IAM]ユーザー作成
IAMのダッシュボードでユーザーを選択し、ユーザーの追加をクリックします。
ユーザー名を入力AWSアクセスの種類を選択プログラムによるアクセスを選択肢、次へ既存のポリシーを直接アタッチを選択後S3で検索
AmazonS3FullAccessを選択し、次へ
ユーザー登録は完了させ、.csvダウンロードする。
access_keysecret_access_keyが書いてあるので忘れないように保管する。[S3]バケットポリシーの編集
S3に入ってバケットの選択し、アクセス許可のタブをクリック
バケットポリシーを編集するをクリックし、下のコード追加します。
AWSアカウントのidは右上の自分の名前をクリックし、マイアカウントの数字です。{ "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadGetObject", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::awsアカウントのid:user/IAMで作成したユーザー名"" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::バケット名/*" } ] }refile.rbを作成
$ touch config/initializers/refile.rbconfig/initializers/refile.rbrequire 'refile/s3' #if !Rails.env.production? # 開発環境でS3へアップロードできているか確認する方法 if Rails.env.production? # 本番環境の場合 aws = { access_key_id: ENV['S3_ACCESS_KEY_ID'], # アクセスキーID secret_access_key: ENV['S3_SECRET_ACCESS_KEY'], # シークレットアクセスキー region: 'ap-northeast-1', # リージョン bucket: 'S3バケット名', } Refile.cache = Refile::S3.new(prefix: 'cache', **aws) Refile.store = Refile::S3.new(prefix: 'store', **aws) end
Refile.cacheRefile.store残っていると本番環境で反映されなかったので
エラーになる方は消した方がいいです。.envAWS_ACCESS_KEY_ID="アクセスキー" AWS_SECRET_ACCESS_KEY="シークレットキー"Gemfilegem "refile-s3"
bundle installでgemを入れます。
本番環境にも同じように反映させたら完成です。参考になった記事です
https://qiita.com/matsubishi5/items/c2abdd7375a4c683392a
https://qiita.com/piyor/items/36d2c3c9b8fd638a71a0
- 投稿日:2021-03-22T12:47:45+09:00
Rails 検索機能 ransack
ransackを使って検索機能を実装する
gem 'ransack'ビューファイルに表示するフォームの作成
@pというのはコントローラーで作成するオブジェクトです。
urlについてはコントローラー、ルーティングに記述して、resultアクションを作成。<%= search_form_for @p, url: result_rooms_path do |f| %> <div class="search-select"> <div class="search-select__container"> <%= f.label '性別', class: "search-select__container__label" %> <%= f.collection_select :user_sex_id_eq, Sex.all, :id, :name, {disabled: 1, include_blank: '指定なし'}, {class: "search-select__container__list"} %> </div> <div class="search-select__container"> <%= f.label 'お部屋の場所', class: "search-select__container__label" %> <%= f.collection_select :place_id_eq, Place.all, :id, :name, {disabled: 1, include_blank: '指定なし'}, {class: "search-select__container__list"} %> </div> </div> <% end %>collection_selectの中身について
引数 値 役割 1. メソッド名 :place_id_eq カラム名、name属性やid属性を決める 2.オブジェクト Place.all アクティブハッシュを指定する 3.value :id 表示する際に参照するDBのカラム名 4.name :name 実際に表示されるカラム名 5.オプション include_blank: 何も選択していない時に表示される内容 disabled: 1はその値を無効にするオプションです。
controllerを記述するdef result @rooms = @p.result.includes(:user).limit(20).order(updated_at: "DESC") end privata def result_rooms @p = Room.joins(:user).ransack(params[:q]) endキー情報である[:q]によってRoomテーブルからデータを探してオブジェクトを生成する。
そしてresultアクション内で@roomsに検索結果を代入している。
.resultで取得することができる。またresult_roomsでDBからレコードを取得する際に、joinsでテーブル同士を内部結合して検索できるようにしています。
紐づいているユーザー情報からも検索できるようにしています。
そしてresult.html.erbを編集。
コントローラー内で記述した@roomsに対して繰り返し処理を行なって、ビューページに表示をしていきます。views/rooms/result.html.erb<% rooms.each do |room| %> <div class="rooms-item__card"> <%= link_to room_path(room.id), class: "link-cover" do %> <h4 class="rooms-item__card__title"><%= room.title %></h4> <p class="rooms-item__card__user"><%= room.user.name %></p> <div class="rooms-item__img"> <%= image_tag room.image %> </div> <% end %> </div> <% end %>以上がポートフォリオで作成したransackを用いた検索ページの実装でした。ポートフォリオはまた別記事で公開いたします。
ありがとうございました。
- 投稿日:2021-03-22T12:07:48+09:00
コントローラー 単体テスト実装
今回詰まった内容を備忘録のためと、知識定着させるためアウトプット!
現在ポートフォリオで簡単な画像付きの投稿サイトを作成中、コントローラーの単体テストを行っておりました。
indexアクションにリクエストするとレスポンスに投稿済みの画像が存在する上記テストだけがどうしてもうまくいかず、進まなかった状況です。
開発フレームワークは
railsを使用しており、
RSpecFactoryBot
は導入済みの状態です。エラー内容
TypeError: no implicit conversion of ActiveStorage::Attached::Many into String # ./spec/requests/posts_spec.rb:19:in `block (3 levels) in <top (required)>'ソースコード
posts_spec.rbequire 'rails_helper' describe PostsController, type: :request do before do @post = FactoryBot.create(:post) end describe 'GET #index' do it 'indexアクションにリクエストすると正常にレスポンスが返ってくる' do get posts_path expect(response.status).to eq 200 end it 'indexアクションにリクエストするとレスポンスに投稿済みのテキストが存在する' do get posts_path expect(response.body).to include(@post.name) end it 'indexアクションにリクエストするとレスポンスに投稿済みの画像が存在する' do get posts_path expect(response.body).to include("@post.images") end it 'indexアクションにリクエストするとレスポンスに投稿検索フォームが存在する' do get posts_path expect(response.body).to include('') end end end
posts.rbFactoryBot.define do factory :post do name { '投稿名' } post_text { '投稿文' } association :user after(:build) do |post| post.images.attach(io: File.open('public/test_image.png'), filename: 'test_image.png') end end end上記の記述で行っていました。
どうしても画像の確認だけができず、つまずいていたという状況でした。エラーログから考察するに、画像がstring(文字列型)になっているため確認が取れないよと認識する。
そのため
binding.pryを入力してターミナル上で情報の確認
response.body
@post
@post.images
@post.images.blobs上記全てをターミナル上で確認して、正常に画像がある事を把握する。
画像があるのに対して、string(文字列)になってしまっているエラーのためなぜかを考察する。
そこで、
include("@post.images")上記の記述の仕方が行けないのではないかと仮説を立てる。
画像情報を取得しているname属性の値を入れてみた。
include("post[images][]")上記に変更してみたが、同様のstring(文字列)のエラーが出ている。
それでエラーが出るのであれば、直接画像のimg属性のクラス名を指定するやり方で再度実行する
include("item-box-img")上記コードで出力を行う。
そうしたらテストが成功した。
エラーの原因で文字列になってしまっているというところに着目し、修正を加えて行ったのがエラー解読につながったとみている。
未だ一点だけ不明点があり、
なぜ画像を指定する際に、その画像のname属性ではなく、クラスを指定しなくては行けないのかという点が不明であった。同じ指定方法をしているのになぜなんだろうと思っている。
参考記事等も見つからず、もしご教授いただけるようでしたら、コメントいただけましたら助かります!
今回はコントローラー単体テストで画像確認のテストをする際におきたエラーでした。
同じようなエラーで迷われている方いましたら、是非ご参考にして頂けましたら幸いです!
宜しくお願いします!
- 投稿日:2021-03-22T11:07:59+09:00
テストコードその3
テストコードを効率よく記述するには?
アウトプット用として書いていきます。
FactoryBot
インスタンスをまとめることができるGemのこと。
他のファイルにインスタンスをまとめておいて呼び出すことで使うことができる。FactoryBotを導入する
前回のrspec-railsと同じようにGemfileに
gem 'factory_bot_rails'と記述する。
記述する場所もrspec-railsと同じようにする。
bundle installすれば導入完了。
ちなみに、rspecとFactoryBotは同時にインストールした方がファイルが自動生成されるのでより効率的である。
FactoryBotのファイルは以下のような記述になる。rbFactoryBot.define do factory :user do nickname {'test'} end endfactoryBotを使ってみる。
設定したインスタンスを生成するためにはbuildを使ってテストコードに記述する。
buildはnewメソッドと同じ意味を持つ。
コードは以下の通りuser=FactoryBot.build(:user)次にひとつひとつのテストに上記のコードを記述するのは非効率なのでbeforeを使ってインスタンス変数にする。
before do @user=FactoryBot.build(:user) endランダムな値を出したいときは。。。
FakerというGemを使う。
記述する場所はFactoryBotと同様である。
これを用いることでメールアドレスや名前などがランダムに生成される。
記述例は以下の通り。
Fakerの後に続くところは決まっている記述なので調べる必要がある。FactoryBot.define do factory :user do nickname {Faker::Name.initials(number: 2)} email {Faker::Internet.free_email} password {Faker::Internet.password(min_length: 6)} end end以上です。
- 投稿日:2021-03-22T10:50:23+09:00
devise
- 投稿日:2021-03-22T10:38:35+09:00
Bundlerについて
はじめに
初学者です。間違いあればご指摘いただきたいです。
参考
Bundler概要
Bundlerの使い方
Bundlerとは?Bundlerとは?
プロジェクト内で使うRubygemsを管理する仕組みのこと。
gemは手動で個別にインストールする事ができる。が、様々なgemを組み合わせて使っていくと「バージョンの組み合わせ」によっては上手くいかないなどの問題が出てくることがある。
複数人、複数環境で開発を行う場合、各々の環境で使うライブラリの名前やバージョンを合わせる必要がある。
上記2点の問題を解決できるのがBundler。
手動でgemをインストールするよりも、gem同士の互換性を保ってくれるBundlerでインストールする方が便利。Bundlerのインストール
まず初めに、Bundlerもgemの1つです。
つまり、インストールの必要があるってことですね。
- Bundlerは手動インストールします。
ターミナルgem install bundler
- 導入されたか確認します。バージョンが表示されるかを確認してください。
ターミナルbundler -vBundlerの使い方
- Gemfileを作る
ターミナルbundle init上記のコマンドでGemfileの雛形が作成されます。
- 使いたいgemをGemfileに記述する
- インストールしたいGemパッケージを記述後、bundle installを実行することで、自動的に調べて全部インストールしてくれます!
Bundlerのコマンド
- bundle init ・・・・Gemfileを生成する
- bundle install・・・Gemfileに書かれたGemパッケージをインストール
- bundle exec・・・・Bundlerでインストールされたgemパッケージを使用してコマンドの実行
- bundle list・・・・・インストール済みのgemパッケージの一覧を表示
- bundle update・・・インストール済みのgemパッケージのバージョンを更新
Gemパッケージの保存先
bundle installと実行すると、
rbenvを利用していた場合、/Users/ユーザー名/.rbenv/versions/バージョン名/lib/ruby/gems/...に保存されます。もしこの保存先を変更したい場合、
ターミナルbundle install --path <フォルダ名>と打つと、指定したフォルダの下に保存することが可能です。
ちなみに2回目以降は、保存先を記憶してくれているので
% bundle installと打つだけで大丈夫です。
- 投稿日:2021-03-22T02:28:57+09:00
formの値をコントローラに送る 基本
- 投稿日:2021-03-22T02:25:04+09:00
link_to form_tag form_for の違い
link_to
getのコントローラーを探しに行く
<%= link_to("移動", "/move") → get "move" => "users#move_form"
form_tag
postのコントローラーを探しに行く
<%= form_tag("/move") do %> → post "move" => "users#move"
form_for
<%= form_tag("/move") do %> <p>メールアドレス</p> <input name="email"> <p>パスワード</p> <input type="password" name="password"> <input type="submit" value="移動"> <%= end %>
- 投稿日:2021-03-22T00:38:34+09:00
【Rails】pluckメソッドのソースコードを読んでみた
アプリケーション作成時に使用した「pluck」メソッドについて、便利な機能だと思っていましたが、どのように処理をしているのか気になったのでRailsのソースコードを読んでみました。
pluckとは
公式ドキュメントでは以下のように記載されています。
pluckは、1つのモデルで使用されているテーブルからカラム (1つでも複数でも可) を取得するクエリを送信するのに使用できます。引数としてカラム名のリストを与えると、指定したカラムの値の配列を、対応するデータ型で返します。例えば、Productモデルがあったとして、nameカラムの中身を確認したい場合は、
Product.pluck(:name) => ["Ruby on Rails Tote", "Ruby on Rails Bag", "Ruby on Rails Baseball Jersey", "Ruby on Rails Jr. Spaghetti", "Ruby on Rails Ringer T-Shirt", "Ruby Baseball Jersey", "Apache Baseball Jersey", "Ruby on Rails Mug", "Ruby on Rails Stein"]といったようにProductモデル内のnameカラムを一覧表示することができます。
Product.pluck(:id,:name) => [[1, "Ruby on Rails Tote"], [2, "Ruby on Rails Bag"], [3, "Ruby on Rails Baseball Jersey"], [4, "Ruby on Rails Jr. Spaghetti"], [5, "Ruby on Rails Ringer T-Shirt"], [6, "Ruby Baseball Jersey"], [7, "Apache Baseball Jersey"], [8, "Ruby on Rails Mug"], [9, "Ruby on Rails Stein"]]このように第二引数を設定することも可能です。
pluckの処理内容と、第二引数を設定した場合の処理がどのように行われているか気になったので、ソースコードを見てみることにしました。
Railsのソースコード
rails/activesupport/lib/active_support/core_ext/enumerable.rbdef pluck(*keys) if keys.many? map { |element| keys.map { |key| element[key] } } else key = keys.first map { |element| element[key] } end end実際に読んでみる①
まず、引数が一つのケースで考えてみます。
[{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name) # => ["David", "Rafael", "Aaron"]def pluck(*keys) if keys.many? map { |element| keys.map { |key| element[key] } } else key = keys.first map { |element| element[key] } end end一行目
(*keys)に、:nameが配列として格納されます。pluck(*keys): *をつければ引数を複数個設定できる。(可変長引数) 引数は配列として受け取られる。二行目
keys.many? → 今回、keysは一つだけなのでスルーmany? → 条件を満たす要素が 2 つ以上ある場合に true。五行目
keysの配列で、最初の要素(:name)を、keyに格納六行目
[{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }]上記の配列をmapメソッドでそれぞれ、key に関連づけられた値を抽出。その後、配列として出力した結果、
=> ["David", "Rafael", "Aaron"]nameカラムの要素のみ表示できました。
実際に読んでみる②
次に、引数が2つ以上のケースで考えてみます。
[{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pluck(:id, :name) # => [[1, "David"], [2, "Rafael"]]def pluck(*keys) if keys.many? map { |element| keys.map { |key| element[key] } } else key = keys.first map { |element| element[key] } end end一行目
(*keys)に、:id, :name が配列として格納されます。二行目
keysが、2つ以上なのでそのまま進みます。三行目
[{ id: 1, name: "David" }, { id: 2, name: "Rafael" }]まず、上記の配列からmapメソッドで、keys → (:id, :name) に関連づけられた要素を抽出。
そこからさらに、mapメソッドを使って配列の要素それぞれに、上記の処理を行う。その後、配列として出力した結果、
=> [[1, "David"], [2, "Rafael"]]idカラムとnameカラムの要素を表示することができました。
終わりに
ソースコードのどこを読めばいいのかとか、おろそかにしてきた基礎文法の知識の足りなさが露呈したりと、たったこれを読むだけでもかなり苦戦しました。
ただ、今まで公式ドキュメント読んでも、「...?」だった内容が事細かに書いてある(当たり前)ので、ソースコードで確認することで、どういう仕組みか納得して進められるなと思った次第です。
これからも、誰かのソースコードを読むことは必須になってくるので、気になったメソッドとかがあったらソースコードを見てみる癖を付けておきたいなと思うのでした。







