- 投稿日:2020-12-23T23:47:57+09:00
rails heroku エラー録
久しぶりにHerokuにpushしようとしたらエラーが、、
... remote: -----> Preparing app for Rails asset pipeline remote: Running: rake assets:precompile remote: rake aborted! remote: ActiveSupport::MessageEncryptor::InvalidMessage: ActiveSupport::MessageEncryptor::InvalidMessage ... remote: remote: Caused by: remote: OpenSSL::Cipher::CipherError:
ActiveSupport::MessageEncryptor::InvalidMessage
これはrailsのmaster.keyが原因のエラーぽいHerokuに登録しなければいけないぽいので
heroku config:set RAILS_MASTER_KEY=`cat config/master.key` Setting RAILS_MASTER_KEY and restarting ⬢ tunagu-natto... done, v475 RAILS_MASTER_KEY: 72ddbs9f8c905e836e4e8dbf72a8b
- 投稿日:2020-12-23T23:47:11+09:00
FactoryBotで外部キーの値はどうやって作り出すんだ〜(泣
はじめに
先日投稿した、テストコードに関するエラーで少し進展したので、記録しておきます。
先日の投稿↓
「RSpecを使ってテストコードを書いているが、うまくいきません」検証結果
仮説2はおそらく関係がないことがわかりました。
ヘルパーメソッドを
number_fieldからtext_fieldに変えても、課題の解決には繋がりませんでした。依然として、うまく保存ができないため、仮説1の外部キーに関わる部分でエラーが発生していると考えられます。
モデルで外部キーであることをバリデーションしていることで、単にIDを入力するだけでは、主キーを見つけられないことが原因だと考えられます。最後に
引き続きテストコードがうまくいくように検証を続けて行きます。
- 投稿日:2020-12-23T23:33:04+09:00
[Ruby on Rails] kaminariの使い方
kaminariとは?
rubyのgemの一つで、ページネーションを作るためのものです。
kaminariのインストール
以下を
Gemfileに追加します。gem 'kaminari'ターミナルでインストールします。
$ bundle installコントローラーにページネーションのコードを追加
class PostsController < ApplicationController def index @posts = Post.all @posts = Post.page(params[:page]).per(15) end end
page(params[:page]).per(15)の部分でページあたりいくつ表示させるかを設定します。
ページネーションが表示されるのは、表示される数が設定した数より多い場合です。ビューファイルにページネーションのコードを追加
ビューでページネーションを表示させる場所に追加します。
<%= paginate @posts %>kaminariを日本語化する
kaminariの表示はデフォルトだと英語です。
日本語化する場合は、config/localesにkaminari_ja.ymlというファイルを作成すると管理しやすいです。
kaminari_ja.ymlに以下を追記します。ja: views: pagination: first: "« 最初" last: "最後 »" previous: "‹ 前" next: "次 ›" truncate: "..." helpers: page_entries_info: one_page: display_entries: zero: "" one: "<strong>1-1</strong>/1件中" other: "<strong>1-%{count}</strong>/%{count}件中" more_pages: display_entries: "<strong>%{first}-%{last}</strong>/%{total}件中"
- 投稿日:2020-12-23T22:32:05+09:00
Rails の credentials.yml.enc と master.key の関係性について(undefined method `[]' for nil:NilClass (NoMethodError))
職場で運用している Rails で作成した、顧客と収益アプリの公開用 clone を作成する際に、題名のところでハマったのでメモ用として残しておきます。
経緯
- GitHub のプライベートリポジトリからローカルにソースコードを clone
- プライバシー情報を削除後、
.gitファイルを削除して、アプリ名(folder 名)を_v2へと変更git initして、リモートリポジトリへプッシュ- CircleCi と連携させて、master に merge されたタイミングで自動テストを組む
- RDS を本番環境の db にしたいので、ローカルで
credentials.ymlに、RDS の情報を打ち込む設定を行う(このとき、credentials:editコマンドを一度使用して、なぜか一度 credential ファイルを削除、credeitials:editコマンドで再作成という謎の手順を踏んでいます)- ECR にコンテナデプロイして、ECS のタスクを実行しようとしたところ、ECR のコンテナが起動していない
- 開発用の Dockerfile を push していたため、
rails sコマンドを起動しておらず追記- 一度、開発環境で動作確認しようと思い、
docker buildすると、サーバーが起動しないエラー発生(undefined method `[]' for nil:NilClass (NoMethodError))ここまでが経緯です。
AWS は一度お試しアプリで、本番環境として自動デプロイを組んだことがあるという程度で、サービスに関してよく理解しないまま進めていました。
何が問題だったのか
問題は、普通に 5 番目の項目ですね。笑
少し詳しくみると、
- credential.yml.enc は、master.key を使用して暗号化、復号される
git push時に、master.key はプッシュされない(.gitignore に記載されているため)つまり、clone してきた時点で master.key は無かった。 そして、一回目の
credentials:editコマンド時に master.key が作成された。しかも、一度 credentials.yml ファイルを削除して、再度
credentials:editコマンドを行っていたので、master.key との整合性が取れていない credentials.yml が作成されていた。そのため暗号化も復号もできておらず、一度作成していた RDS の設定も消えていた。という感じですかね?多分
どう解決したか
この場合は、
- 一度、master.key と credentials.yml を削除
credentials.editコマンドで 2 つのファイルを再作成という工程でいけました!
結構ありがちなエラーみたいで調べたらたくさん情報が出てきたけど、いい勉強になった。
同じようなケースの方は私の屍を超えていってください!!
- 投稿日:2020-12-23T22:07:14+09:00
【rails】railsとjsを用いて「いいね機能」を実装してみた
今回はrailsとjsでいいね機能を実装していきたいと思います
** また最後におまけでユーザーがいいねした投稿を表示できるような機能も実装していきます**
jsを読み込んだりする説明は割愛!
参考にさせていただいた記事
https://techtechmedia.com/favorite-function-rails/
https://qiita.com/hayabusa3703/items/2b916e652a1dc85bb6e3完成予想図
下準備
ユーザーはたくさんの投稿にいいねをして、投稿もたくさんのユーザーにいいねされるので
likesテーブルを中間テーブルにした、ユーザと投稿の多対多のテーブル構造
rails g model likeマイグレーションファイル
class CreateLikes < ActiveRecord::Migration[5.0] def change create_table :likes do |t| t.integer :user_id t.integer :drink_id t.timestamps end end endrails g controller likesアソシエーション
like.rb
class Like < ApplicationRecord belongs_to :user belongs_to :drink, counter_cache: :likes_count end・counter_cahce: :likes_countはリレーションされているlikeの数の値をリレーション先のlikes_countというカラムの値に入れますよっていう意味です。なのでlikes_countカラムをstoriesテーブルに追加しましょう。(rails g migration AddLikes_countToStories likes_count:integerをターミナルで実行すればオッケーです。)
この文章の参照元drink.rb
class Drink < ApplicationRecord has_many :likes has_many :liking_users, through: :likes, source: :user endliking_usersモデルは無いので、likesテーブルを中間テーブルにして、userモデルとアソシエーションを汲みますよーってことをrailsに伝えてます
has_manyはbelongs_toはアソシエーションを組むのが本質ではなくて、メソッドを作るメソッド。
つまり,@drink.liking_userとかやったら、その投稿にいいねしたユーザー一覧を取得できるメソッドができるし、アソシエーションも組める
user.rb
has_many :likes has_many :like_drinks, through: :likes, source: :drinkこれも、user.like_drinksとかやったら、そのユーザーがいいねした投稿一覧が取得できる
これは、インスタ、Twitterによくある、そのユーザーがいいねした投稿を表示する時に便利has_manyはbelongs_toはアソシエーションを組むのが本質ではなくて、メソッドを作るメソッド。
これを覚えて帰りましょう。
いいねボタンの記述
drinks/index.html.erb
こちらは投稿一覧のページになります
<%if @drinks%> <% @drinks.each do |drink|%> <li class='list'> <%= link_to drink_path(drink.id) do %> <%= link_to user_path(drink.user.id) do%> <div class="user-info-timeline"> <%=image_tag drink.user.image.variant(resize: '60x60'),class: "user-img-timeline" if drink.user.image.attached?%> <div class="username-timeline"> <%= drink.user.nickname %> </div> </div> <% end %> <div class='item-img-content'> <%= image_tag drink.image , class: "item-img" if drink.image.attached? %> <%# if drink.trade%> <%# end %> </div> <div class='item-info'> <h3 class='item-name'> <%= drink.name %> </h3> <div class='item-price'> <span><%= drink.price %>円<br>(税込み)</span> <div class='star-btn'> <%# image_tag "star.png", class:"star-icon" %> <span class='star-count'>0</span> </div> </div> <div class='item-explain'> <%= drink.explain%> </div> <div class='item-tag'> <% drink.tags.each do |tag| %> #<%=tag.tag_name%> <%end%> </div> <%= render "likes/like",drink: drink%> </div> <% end %> </li> <%end%><%= render "likes/like",drink: drink%>に注目して欲しいです!
まずは可読性を高めるために
画像のいいねボタンを部分テンプレートで切り出しています、そして、,drink: drinkの部分ですが、
<% @drinks.each do |drink|%>のeach文内のブロック変数を、likes/likeにも適用するために変数を受け渡しています。
ブロック変数とは(分かる人は飛ばして)
ブロック変数とは、each文やらtimes文,form_withとか、そのメソッド内だけで使える変数です。
つまり、eachだったらeachから endまでの範囲無で使える変数@drinksにはいろんな情報が、配列として入っていますが、|drink|
とすることで、配列の中の一つ一つの情報がdrinkに入っていって、@drinksにある配列の数だけ表示しますlikes/_like.html.erb
パーシャル(部分テンプレート)であることを分かりやすくするために慣習的にファイル名を_likeとしてます。
ただ<%= render "likes/like",drink: drink%>
で呼び出す時はアンダーバーはいりません
<div class="like" id="like-link-<%= drink.id %>"> <% if current_user.likes.find_by(drink_id: drink.id) %> <%= link_to unlike_path(drink.id), method: :delete, remote: true do %> <div class = "iine__button">❤️<%= drink.likes.count %></div> <% end %> <% else %> <%= link_to like_path(drink.id), method: :post, remote: true do %> <div class = "iine__button">♡️<%= drink.likes.count %></div> <% end %> <% end %> </div>id="like-link-<%= drink.id %>"
がミソ。
jsで非同期で画面を切り替えたいので、idを取得できるように、投稿ごとにidを区別するために
このように記述しましょう。<%= link_to unlike_path(drink.id), method: :delete, remote: true do %>, remote: true
と記述することにより、
リンクを押した時にajaxが発火するので非同期で通信が行われます。
いいねボタンを押したらいいねがすでについてれば、unlike_pathそうじゃなければlike_pathに飛びます
それぞれのpathをまだ定義してないので、このままじゃルーティングエラーになってしまうので
routes.rb
post 'like/:drink_id' ,to: 'likes#like', as: 'like' delete 'like/:drink_id',to: 'likes#unlike', as: 'unlike'と記述しましょう
as: 'like' とすることにより本来ならlikes_like_path(drink.id)とパス指定をしなきゃいけないのですが、
like_path(drink.id)でlikes#likeにpostリクエストを送ることができますこれで、リンクを踏んでリクエストを送ることができたので、次はコントローラーをみていきましょう
likes_controller
class LikesController < ApplicationController include SessionsHelper before_action :set_variables def like like = current_user.likes.new(drink_id: @drink.id) #redirect_to drinks_path # jsを用いるので画面遷移は行わない #binding.pry like.save end def unlike like = current_user.likes.find_by(drink_id: @drink.id).destroy #binding.pry end private def set_variables @drink = Drink.find(params[:drink_id]) @id_name = "#like-link-#{@drink.id}" end endremote: trueのリンクからlike,unlikeアクションが呼び出されるので、
デフォルトの遷移先はilke.js.erb,unlike.js.erbとそれぞれなります。「⚠︎ @id_name = "#like-link-#{@drink.id}"
とControllerにViewの処理を書くのは、MVCパターン的にあまりよろしくないと思いますね。」とご指摘をいただいたので、あまりよく無いですが、機能的には問題無いので一旦次いきます。
likes/like.js.erb
$("<%= @id_name %>").html('<%= escape_javascript(render("likes/like", drink: @drink )) %>');/likes/unlike.js.erb
$("<%= @id_name %>").html('<%= escape_javascript(render("likes/like", drink: @drink )) %>');likes/_like.html.erbにまた戻ります
この時にまた
drink: @drink
と書いて_like.html.erbに変数を受け渡してあげましょうこの@drinkは
likes_controllerの
private def set_variables @drink = Drink.find(params[:drink_id]) @id_name = "#like-link-#{@drink.id}" endの@drinkです。
以上で実装終了です。お疲れ様でした。
おまけ、ユーザーがいいねした投稿を表紙
users/show.html.erb
<%= link_to "#{@user.nickname}がいいねした投稿",user_likes_path(@user.id)%>こんな感じのリンクを作成
@userhはusers#showで@user = User.find(params[:id])
とかよくある感じで定義してますuser_like_pathはまだ定義してないので
routes.rb
get 'user/likes/:id', to: 'users#likes',as: 'user_likes' resources :users do member do get :following,:followers # memberメソッドを使うと # ユーザーidが含まれてるURlを扱うようになる end endresources :userとかみんなやると思うので、resourcesの上に get 'user/likes/:id', to: 'users#likes',as: 'user_likes'
を書きましょう
これで、 リンクを踏んだらusers#likesにGETリクエストを飛ばすことができます
users_controller
def likes @user = User.find(params[:id]) @drinks = @user.like_drinks.paginate(page: params[:page],per_page: 10).order("created_at DESC") endこんな感じで実装しましょう
.paginate(page: params[:page],per_page: 10)
はページネーション をまだ取り入れてなければ書かなくて大丈夫です。
.like_drinksメソッドは
has_many :like_drinks, through: :likes, source: :drinkとuser.rbで書いたので、ユーザーがいいねした投稿一覧を取得できます。
デフォルトで、users/likes.html.erbにリダイレクトされるので、そのビューも用意しましょう
users/likes.html.erb
<div class="user-profile"> <h2 class="user-profile-name"><%= current_user.nickname %></h2> <h2><%= image_tag @user.image.variant(resize: '100x100'),class: 'user-img' if @user.image.attached? %></h2> <div class="user-like-post"> <%= link_to "#{@user.nickname}がいいねした投稿",user_likes_path(@user.id)%> </div> <div class="user-edit"> <% if current_user?(@user) %> <%= link_to "プロフィールを編集",edit_user_path(@user)%> <% end %> </div> <% unless current_user?(@user) %> <div id="follow_form"> <% if current_user.following?(@user) %> <%= render 'unfollow' %> <% else %> <%= render 'follow' %> <% end %> </div> <% end %> </div> <% @user ||= current_user %> <div class="stats"> <a href="<%= following_user_path(@user) %>"> <strong id="following" class="stat"> <%= @user.following.count %> </strong> following </a> <a href="<%= followers_user_path(@user) %>"> <strong id="followers" class="stat"> <%= @user.followers.count %> </strong> followers </a> </div> <div class='main'> <%# 商品一覧 %> <div class='item-contents'> <h2 class='title'><%= @user.nickname%>の投稿</h2> <%= will_paginate @drinks%> <ul class='item-lists'> <%# 商品のインスタンス変数になにか入っている場合、中身のすべてを展開できるようにしましょう %> <%if @drinks%> <% @drinks.each do |drink|%> <li class='list'> <%= link_to drink_path(drink.id) do %> <div class='item-img-content'> <%= image_tag drink.image , class: "item-img" if drink.image.attached? %> <%# if drink.trade%> <%# end %> </div> <div class='item-info'> <h3 class='item-name'> <%= drink.name %> </h3> <div class='item-price'> <span><%= drink.price %>円<br>(税込み)</span> <div class='star-btn'> <%# image_tag "star.png", class:"star-icon" %> <span class='star-count'>0</span> </div> </div> <div class="item-explain"> <%= drink.explain%> </div> </div> <% end %> </li> <%end%> </ul> <%= will_paginate @drinks%> </div> <%end%> </div>自分はこんな感じ
これで以上です。お疲れ様でした。
今までのコードのまとめ
- 投稿日:2020-12-23T21:41:41+09:00
[メモ] ?で終わるメソッド
勉強用のメモ代わりとして記事にさせていただきます。
?で終わるメソッド
Rubyのメソッド名は?で終わらせることができる。?で終わるメソッドは慣習として真偽値を返すメソッドになっている。
# 空文字列ならtrue、そうでもなければfalse ''.empty? #=> true 'abc'.empty? #=> false # 引数の文字列が含まれていればtrue、そうでもなければfalse 'movie'.include?('mo') #=> true 'movie'.include?('at') #=> false # 奇数ならtrue、そうでもなければfalse 3.odd? #=> true 4.odd? #=> false?で終わるメソッドは自分で定義することができる。
# 2の倍数ならtrue、それ以外はfalseを返す def multiple_of_two?(n) n % 2 == 0 end multiple_of_two(1) #=> false multiple_of_two(2) #=> true multiple_of_two(3) #=> falseまとめ
真偽値を返す目的のメソッドであれば、?で終わらせるようにした方が良い。
- 投稿日:2020-12-23T20:06:50+09:00
Railsと別で書いていたscssをRailsに入れようとしたら、SassC::SyntaxError in Users::Sessions#newが出た件について
目次
- はじめに
- 実行環境
- 理由
- 解決方法
- まとめ
はじめに
今回は別で書いていたscssをrailsに入れようとしたら
background-color: $color-basic;
のところで
Error: Undefined variable: "$color-basic".
というエラーが出た。実行環境
この記事は以下の動作環境で動作確認しています。
* ruby (2.7.1)
* rails (6.0.3)理由
* application.scss(css)内のデフォルトでいる
*= require_tree .が、app/assets以下の全てのcssファイルを読み込んでいる
ので、
読み込む順番がずれて、
$colorを指定したmiximファイルが先に読み込まれていなかったから。
*が前に書いてあって、コメントアウトされている様に見えるけれど
ナ●シカの巨神兵の様に奴らは生きている...!!
解決方法
今回はstyle.scssに
style.scss@import "./ホゲホゲ/mixin"; @import "./ホゲホゲ/plugin"; @import "./ホゲホゲ/reset"; (などなど続く)の様な@importの集団を書いて、これを読み込ませたかったので、
1 application.scssに
(application.cssならscssに変更)2 同ファイルの*= require_tree .の行を削除
3 末尾に↓の様に@importしてstyle.scss(などの@importがたくさん書いてあるファイル)を読み込む
application.scss/* * This is a manifest file that'll be compiled into application.css, which will include all the files * listed below. * * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's * vendor/assets/stylesheets directory can be referenced here using a relative path. * * You're free to add application-wide styles to this file and they'll appear at the bottom of the * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS * files in this directory. Styles in this file should be added after the last require_* statement. * It is generally better to create a new file per style scope. * *= require_self //このファイルが最初に読み込むの意味。 */ @import "./css/style.scss"; // ここにimport(適用)したいscssを入れる。今回はstylesheet/cssフォルダ内にimportしたいscssを入れたのだけれど、ファイル構造や名前に合わせていただければ!こんな感じで解決した。
まとめ
application.scss(css)の中身は
*の後ろも生きているので注意が必要!
- 投稿日:2020-12-23T19:58:24+09:00
間違ったマイグレーションファイルを削除する方法
オンラインスクールの課題に取り組んでいる時に、間違って、余計なマイグレーションを行ってしまいました。
せっかく上手く動作していたのに、そのマイグレーションをきっかけにエラーが頻発。パニック。
rollbackを行おうとしたのですが、上手くできなかったため、今回は削除することにしました。まずはマイグレーションの状態を調べる
rails db:migrate:statusで現在のマイグレーションの状態を調べます。
その結果、このように返ってきました。Status Migration ID Migration Name -------------------------------------------------- up 20201222113451 Devise create users up 20201223005506 Create items up 20201223093320 Add nickname to users down 20201223095940 Add devise to users一番下のファイルが余計に追加してしまったデータベースです。downになってますね。
マイグレーションを削除!
rm -rf db/migrate/20201223095940_add_devise_to_users.rbそして、
rails db:migrateを行い、再びrails db:migrate:statusを実行。きれいに削除されました
Status Migration ID Migration Name -------------------------------------------------- up 20201222113451 Devise create users up 20201223005506 Create items up 20201223093320 Add nickname to usersきれいに最後のマイグレーションが削除され、無事に動作確認をすることができました。
まとめ
今回と問題になったパターンは違うと思いますが、rollbackを使って、マイグレーション問題を解決した方法を書きました。
今回は削除して対応してみました。
まだ上手く頭の中でマイグレーションについて理解できていませんが、少しずつ深めていきたいと思います。
先人の経験に感謝です!参考
- 投稿日:2020-12-23T19:12:30+09:00
【Rails】フォームのオートフォーカスによる画面エラー
Railsで個人アプリを開発しているときに発生したエラーです。
備忘録としてエラーの発見から解消までを記します。事象
スマートフォン(OS:iOS、ブラウザ:Google Chrome,Safari)でサインアップページにアクセスすると、ページのレイアウトが一瞬だけ表示された後、「このページは開けません。」というエラーが発生する。
ただし、該当URLを直打ちでアクセスするとページが正常に表示される。(これについては最終的に謎のまま終わりました・・・)
調査
他に同様のエラーが出るページは無いか探したところ、プロフィール編集ページでも発生しました。
サインアップページとプロフィール編集ページの共通点は、ユーザー情報を入力するフォームがあることでした。
サインアップページ
プロフィール編集ページ
原因
1画面内にautofocus: trueのフォームが複数存在すると、スマートフォンで閲覧した際にエラーが発生するようです。
そのため、autofocus: trueを一番最初の入力フォームにのみ残し、残りのフォームから消したところエラーは解消されました。
PCで閲覧する際にはエラーが出ないので見落としていました・・・
フォームをコピペで増やしていくのもいいですが、この辺りをしっかりメンテナンスしないといけないですね・・・。
- 投稿日:2020-12-23T19:05:33+09:00
lib/配下のファイルをリロードするたびに再読み込みする
めも
TL;DR
config/application.rb... config.eager_load_paths += ["#{Rails.root}/lib"] ...参考記事: https://stackoverflow.com/questions/3282655/ruby-on-rails-3-reload-lib-directory-for-each-request
requireは不要になるので削除。
開発環境でのみonにする
開発時にしか行わないことなので、本番で毎回読み込まないようにするには以下のように書く。
config/application.rb... config.eager_load_paths += ["#{Rails.root}/lib"] if Rails.env.development? ...呼び出し側require './lib/invoice_pdf' unless Rails.env.development?
- 投稿日:2020-12-23T18:57:02+09:00
【Rails】paramsってなんだ?
はじめに
こんにちは、23日目のカレンダーを担当する@sleepy_catです。
今現在メンターをしていますがこの質問かなり多いなと感じ、また、Railsを学び始めた頃にちょくちょく見かけて理解するのが大変だったparamsについての記事を書いていきます。
この記事を読んで欲しい方
- モデル.find(params[:id])ってとりあえずshowアクションに書いてるけどよくわからんって方
- formから送られてきたデータがよくわかんないけど直接DBに保存されると思ってる方
環境
$ rails -v Rails 5.2.4.3 $ ruby -v ruby 2.6.2p47 (2019-03-13 revision 67232) [x86_64-linux]Rails5系です。現在6系が最新ですが、バージョンそこまで関係ない話だと思います。
paramsとは
クライアントからURLやフォームで送信された値(パラメータ)を取得するメソッドです。
これでわかりましたって方は多分元からこの記事を読んでないはずなので詳しく見ていきましょう。パラメータの送り方について知る
ここでいうパラメータとはユーザ側のアクションによってページ遷移の時に一緒に送られるデータ(リクエスト情報)のことをいいます。主に送り方は3種類あります。
注)このパラメータについて知るにはHTTPメソッドやformについての知識も必要ですがそれも書くとめんどくさいかなり長くなってしまうため割愛させていただきます。クエリパラメータ
URLパラメータとかクエリ文字列とか正しい呼び方がわからない...
遷移先がGETメソッドの時のデータの送り方。データの送り方としてはシンプルでURLの末に送りたいデータを載せて送るやり方です。
例を出すなら
https://hogehoge/hugahuga/index?like=dog
このURLの?以降がクエリパラメータです。今回はlikeという名前のデータを送っていますね(データの中身はdog)。一つしか送れないかというとそんなことはなくいくつも送れます。よく見る場面としては検索機能ではこのクエリを用いてデータがやり取りされることが多いです。実際にこのqiitaの検索機能を使って検索結果のページに飛んだ後、URLを確認してみましょう。URLにクエリパラメータがあるのが確認できると思います。
もう一つよく使われる場面としてはWebサイトのアクセス解析をするために付けられることがあります。一番イメージしやすいのが個人ブログに貼ってあるamazonとかへのリンクだと思います(俗にいうアフィリエイト)。あのリンクはそのブログ経由で商品が購入された時にブログ主にも収益が入ると言った物ですが、じゃあどのサイトからきたのか、というのを示すためにクエリがついていることがあります。
ルートパラメータ
先ほどのクエリがURLの末にデータを載せるやり方ならこちらはURLの中にパラメータを入れ込むやり方です(URLの一部をパラメータと見なす、の方が適切かもしれませんが)。
例として以下のルーティングがあるとします。
config/routes.rbRails.application.routes.draw do resources :users endPrefix Verb URI Pattern Controller#Action users GET /users(.:format) users#index POST /users(.:format) users#create new_user GET /users/new(.:format) users#new edit_user GET /users/:id/edit(.:format) users#edit user GET /users/:id(.:format) users#show <=この行を主に考えます PATCH /users/:id(.:format) users#update PUT /users/:id(.:format) users#update DELETE /users/:id(.:format) users#destroyここで一部ルーティングのURL(URI Pattern)に少しおかしな物が紛れているかと思います。"/:id"といった部分です。まさしくこの部分がパラメータとなる部分です。このようにURLの文字列内にコロンがついた部分は文字として扱われず一種の変数として扱われます。
(前提条件 Railsが動く順番として
URLが入力される => ルーティングで一致するcontroller/actionが実行)
例えば/users/1というURLのページを開こうとするとこれに一致するルーティングは/users/:id(.:format)だとRailsは判断します。"id"という名前のデータ(中身は1)が渡されページ遷移が行われるといったイメージです。おまけ
Prefix Verb URI Pattern Controller#Action item GET /qiita.com/:user_name/items/:item_id(.:format) items#showこんなパスがあるとして
https://qiita.com/sleepy_cat/items/c8eecfc5c486b0f7f2b8このサイトを開きたいと思います。ここで得られるパラメータは何があるでしょうか
答え
①user_nameという名前のデータ、中身はsleepy_cat
②item_idというデータ、中身はc8eecfc5c486b0f7f2b8ポストデータ
遷移先がPOSTの時のデータの送り方。ログインの時などにフォームにメールアドレスやパスワードを入力して画面遷移など一番イメージしやすいと思います。通常ユーザ側が送られたデータを確認することはできないので(クエリなどはURL確認すると一発でわかってしまいますよね)セキュリティ上今までのものと比べ一番ましです。
paramsとは(再び
さて、データの送り方がいくつかあることはわかった。じゃあ受け取り方は?とここまで読んでいただいた方は思っている頃だと思います。それこそがparamsメソッドです。Railsではこの三つのデータを1つにまとめて
params[:パラメータ名]といった形で受け取れるようになっています。ではこんなルーティングがあり
Prefix Verb URI Pattern Controller#Action user GET /users/:id(.:format) users#show
/users/4とURLが指定され、コントローラでapp/controllers/users_controller.rbdef show @user = User.find(params[:id]) endと記述されていたら、
@userにはどんなプロセスで、どんな値が入っているのか、今ならわかるはずです。
①まずURLパラメータとして、このページに"id"という名前のデータが送られます。
②送られた"id"というデータをparams[:id]が受け取ります。
③受け取ったデータの中身は"4"なので@user = User.find(4)となる。
④Userモデルからfindメソッドでidが4のデータを持ってきて、@userに入力されます。確かめてみよう
paramsで受け取れるデータはどこで受け取ればいいのか。確認方法としてはデバッグ用gemで見たりもいいですが、ターミナルを確認してみるのもいいでしょう。
こちら一部変更してますが簡単に作ったアプリケーションでupdateアクションを行った時のターミナルの一部です。
Started POST "/users/2" for 999.999.999.99 at 2020-12-23 09:25:51 +0000 Cannot render console from 999.999.999.99! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255 Processing by UsersController#update as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"ABw1gqVMw8Jhogehogehugahuga", "user"=>{"name"=>"sleepy_cat", "text"=>"i love dog"}, "commit"=>"Update User", "id"=>"2"} . . .注目していただきたいのが"parameters:"から始まる記述の部分です。{"データの名前" => "データの中身","データの名前" => "データの中身"...}となっています。
例えばここでparams[:id]とすると得られるデータは"2"です。またparametersはハッシュのデータもあり、"user"=>{"name"=>"sleepy_cat", "text"=>"i love dog"}この部分は入れ子のようになっているため取り出す際はparams[:user][:name]とすると"sleepy_cat"が得られます。まとめ
ちなみにparamsメソッドはcontrollerとviewで扱うことができます。
Railsの場合、formだろうとクエリだろうと①ページ遷移②parametersに情報集まる③コントローラなどで使う、モデルに振り分ける(ストロングパラメータなどがここに密接に関わってくるのでよかったら更に調べてみてください)等をするといった手順さえ頭の中に描けていればよりRailsの記述の理解が進むかもしれません。
この記事を読んでparamsと少しは仲良くなれそうだと思っていただけたら幸いです。
- 投稿日:2020-12-23T18:48:09+09:00
ransack使用 検索機能実装
はじめに
※すでにアプリケーションがある定で書いてます。
rails用の検索機能を実装する為のgemになります。
検索キーワードを元に紐付いたデータを取得
逆にキーワードが無い場合は全て取得する。手順
Gemfileに
ransackを記述してbundle installGemfilegem 'ransack'ターミナルbundle install次に
コントローラーにransackを機能を利用する処理を書きます。app/controllers/users_controller.rbclass UsersController < ApplicationController def index @q = User.ransack(params[:q]) @users = @q.result #resultメソッドで結果を返します end end次に
ビューファイルに検索フォームを書きます。
ransackを使用した検索フォームはsearch_form_forというヘルパーメソッド を使います。app/views/users/index.html.erb<%= search_form_for @q do |f| %> <div class="d-flex"> <div class="form-group flex-grow-1"> #検索窓 <%= f.search_field :name_cont, placeholder: "〇〇を探す", class: "form-control" %> </div> <div> #検索 <%= f.submit "検索", class: "btn btn-primary ml-1" %> </div> </div> <% end %>今回は「部分一致検索」が目的の為
カラム名_contにしています。
「一致検索」の場合は,カラム名_eqとします。検索機能完成
※Qiiteに動画のアップロード初めてでしたが、上手く行きました!
この記事には関係ありませんが参考になりました!
https://qiita.com/bohebohechan/items/f8bf6d4bbe0f14497a7b終わりに
ざっくりとした内容になりましたが、
結論画期的なgemを作って下さった技術者に感謝です!
- 投稿日:2020-12-23T18:06:02+09:00
購入機能の実装
購入機能の実装
課題で唯一難しかったので記録用として保存しておきます。
FormオブジェクトとPay.jpを使った機能ですが詰まったところだけ抜粋して記述。購入するためコントローラの記述
Payjp::Charge.createに商品の価格やトークンを渡せば購入できます
class OrdersController < ApplicationController before_action :authenticate_user! before_action :item_find def index if user_signed_in? && current_user.id == @item.user_id || @item.order.present? redirect_to root_path end @item_order = ItemOrder.new end def create @item_order = ItemOrder.new(item_order_params) if @item_order.valid? pay_item @item_order.save redirect_to root_path else render :index end end private def item_order_params params.require(:item_order).permit( :postal_code, :prefecture_id, :city, :block, :building, :telephone_number ).merge(user_id: current_user.id, item_id: params[:item_id], token: params[:token]) end def item_find @item = Item.find(params[:item_id]) end def pay_item Payjp.api_key = ENV["PAYJP_SECRET_KEY"] Payjp::Charge.create( amount: @item.price, card: item_order_params[:token], currency: 'jpy' ) end end購入のビューファイル
@item_orderの変数を定義して受け取りができるように記述
<%= render "shared/second-header"%> <div class='transaction-contents'> <div class='transaction-main'> <h1 class='transaction-title-text'> 購入内容の確認 </h1> <%# 購入内容の表示 %> <div class='buy-item-info'> <%= image_tag @item.image, class: 'buy-item-img' %> <div class='buy-item-right-content'> <h2 class='buy-item-text'> <%= @item.name %> </h2> <div class='buy-item-price'> <p class='item-price-text'>¥<%= @item.price %></p> <p class='item-price-sub-text'><%= @item.charge.name %></p> </div> </div> </div> <%# /購入内容の表示 %> <%# 支払額の表示 %> <div class='item-payment'> <h1 class='item-payment-title'> 支払金額 </h1> <p class='item-payment-price'> ¥<%= @item.price %> </p> </div> <%# /支払額の表示 %> <%= form_with(model:@item_order, id: 'charge-form', class: 'transaction-form-wrap',local: true) do |f| %> <%= render 'shared/error_messages', model: f.object %> <%# カード情報の入力 %> <div class='credit-card-form'> <h1 class='info-input-haedline'> クレジットカード情報入力 </h1> <div class="form-group"> <div class='form-text-wrap'> <label class="form-text">カード情報</label> <span class="indispensable">必須</span> </div> <%= f.text_field :number, class:"input-default", id:"card-number", placeholder:"カード番号(半角英数字)", maxlength:"16" %> <div class='available-card'> <%= image_tag 'card-visa.gif', class: 'card-logo'%> <%= image_tag 'card-mastercard.gif', class: 'card-logo'%> <%= image_tag 'card-jcb.gif', class: 'card-logo'%> <%= image_tag 'card-amex.gif', class: 'card-logo'%> </div> </div> <div class="form-group"> <div class='form-text-wrap'> <label class="form-text">有効期限</label> <span class="indispensable">必須</span> </div> <div class='input-expiration-date-wrap'> <%= f.text_area :exp_month, class:"input-expiration-date", id:"card-exp-month", placeholder:"例)3" %> <p>月</p> <%= f.text_area :exp_year, class:"input-expiration-date", id:"card-exp-year", placeholder:"例)23" %> <p>年</p> </div> </div> <div class="form-group"> <div class='form-text-wrap'> <label class="form-text">セキュリティコード</label> <span class="indispensable">必須</span> </div> <%= f.text_field :cvc, class:"input-default", id:"card-cvc", placeholder:"カード背面4桁もしくは3桁の番号", maxlength:"4" %> </div> </div> <%# /カード情報の入力 %> <%# 配送先の入力 %> <div class='shipping-address-form'> <h1 class='info-input-haedline'> 配送先入力 </h1> <div class="form-group"> <div class='form-text-wrap'> <label class="form-text">郵便番号</label> <span class="indispensable">必須</span> </div> <%= f.text_field :postal_code, class:"input-default", id:"postal-code", placeholder:"例)123-4567", maxlength:"8" %> </div> <div class="form-group"> <div class='form-text-wrap'> <label class="form-text">都道府県</label> <span class="indispensable">必須</span> </div> <%= f.collection_select(:prefecture_id, Prefecture.all, :id, :name, {}, {class:"select-box", id:"prefecture"}) %> </div> <div class="form-group"> <div class='form-text-wrap'> <label class="form-text">市区町村</label> <span class="indispensable">必須</span> </div> <%= f.text_field :city, class:"input-default", id:"city", placeholder:"例)横浜市緑区"%> </div> <div class="form-group"> <div class='form-text-wrap'> <label class="form-text">番地</label> <span class="indispensable">必須</span> </div> <%= f.text_field :block, class:"input-default", id:"addresses", placeholder:"例)青山1-1-1"%> </div> <div class="form-group"> <div class='form-text-wrap'> <label class="form-text">建物名</label> <span class="form-any">任意</span> </div> <%= f.text_field :building, class:"input-default", id:"building", placeholder:"例)柳ビル103"%> </div> <div class="form-group"> <div class='form-text-wrap'> <label class="form-text">電話番号</label> <span class="indispensable">必須</span> </div> <%= f.text_field :telephone_number, class:"input-default", id:"phone-number", placeholder:"例)09012345678",maxlength:"11"%> </div> </div> <%# /配送先の入力 %> <div class='buy-btn'> <%= f.submit "購入" ,class:"buy-red-btn" %> </div> <% end %> </div> </div> <%= render "shared/second-footer"%>モデルの記述
class OrderAddress include ActiveModel::Model attr_accessor :postal_code, :prefecture_id, :city, :address_num, :building_name, :phone, :item.id, :params[:token], :current_user.id with_options presence: true do validates :postal_code, format: {with: /\A[0-9]{3}-[0-9]{4}\z/, message: "is invalid. Include hyphen(-)"} validates :city, format: { with: /\A[ぁ-んァ-ン一-龥]/, message: "is invalid. Input full-width characters."} validates :address_num validates :phone, format: {with: /\A\d{10}\z|\A\d{11}\z/ , message: "is invalid."} validates :token end validates :prefecture_id, numericality: { other_than: 1 } def save Order.create(item:id) Address.create(postal_code: postal_code, address_num: address_num, building_name: building_name, phone: pOrder.create(user: current_user.id, item: id) Address.create(postal_code: postal_code, prefecture_id: prefecture_id, city: city, address_num: address_num, building_name: building_name, phone: phone)hone) end endクレジット機能の記述
const pay = () => { Payjp.setPublicKey(process.env.PAYJP_PUBLIC_KEY); const form = document.getElementById("charge-form"); form.addEventListener("submit",(e) => { e.preventDefault(); const formResult = document.getElementById("charge-form"); const formData = new FormData(formResult); const card = { number: formData.get("item_order[number]"), exp_month: formData.get("item_order[exp_month]"), exp_year: `20${formData.get("item_order[exp_year]")}`, cvc: formData.get("item_order[cvc]"), }; Payjp.createToken(card, (status, response) => { if (status == 200 ) { const token = response.id; const renderDom = document.getElementById("charge-form"); const tokenObj = `<input value=${token} name='token' type="hidden">`; renderDom.insertAdjacentHTML("beforeend", tokenObj); } document.getElementById("card-number").removeAttribute("name"); document.getElementById("card-exp-month").removeAttribute("name"); document.getElementById("card-exp-year").removeAttribute("name"); document.getElementById("card-cvc").removeAttribute("name"); document.getElementById("charge-form").submit(); }); }); }; window.addEventListener("load", pay);
- 投稿日:2020-12-23T17:32:46+09:00
「OpenSSH keys only supported if ED25519 is available」のエラーの解決方法
- 投稿日:2020-12-23T17:13:43+09:00
[Rails]本番環境のデータベースをリセットする方法(Capistrano版)
はじめに
前提
・Railsを使用してアプリケーションを開発
・Capistranoでの自動デプロイを実装している
・AWSのEC2にてサーバーを構築している
・RDSでMySQLを使用している背景
私は開発環境では、rails db:migrate:resetにていつもデータベースを作り直していましたが、本番環境ではどのようにすればいいのかという疑問から実装しました。
本番環境のデータベースをリセットする
まずはターミナルを用いてEC2で自分のアプリケーションフォルダの階層まで進む。
Capistranoでの実装をしているのでミスをしないように基本的にはcurrentディレクトリで作業するようにする。terminal[ec2-user@ip-222-22-2-222 アプリ名]cd currentcurrentRAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bundle exec rails db:dropこれでデータベースが消去することができました。
データベース再度作成する
今回はRDSにMySQLを導入している前提でお話していきます。
まず引き続きターミナルは同じディレクトリでmysqlに接続します。
mysql -u (マスタユーザ名) -p -h (エンドポイント)
「-u」はユーザ名、「-p」はパスワードの入力、「-h」は接続先の情報を表すオプションです。
なお、「エンドポイント」は、RDSメニューで確認し、入力してください。
「パスワード」は、「マスターパスワード情報」で設定したパスワードを入力します。terminalmysql -u root -p -h rds-mysql-server.xxx.ap-northeast-1.rds.amazonaws.comこのコマンドを打つとpasswordの入力が求められるので入力すると無事mysqlに接続が完了しました。
削除したアプリケーション名と同じ名前をつけデータベースを再度作成します。
terminalmysql> create database アプリケーション名;再度本番環境でmigrateを実行します。
terminalbundle exec rails db:migrate RAILS_ENV=productionこれでデータベースのリセットは終了です。
あとは本番環境でcapistranoのコマンドを叩いて終了ですterminalbundle exec cap production deployお読みいただきありがとうございました
- 投稿日:2020-12-23T17:13:00+09:00
datetimeを使って、本日の注文件数を表示したい。
まずは「$ rails c」でdatetimeの動きを見てみる。
irb#現在時間の取得 [1] pry(main)> dt=DateTime.now => Wed, 23 Dec 2020 05:34:58 +0000 #parseで日付情報だけに加工 [2] pry(main)> today=Date.parse(dt.strftime("%Y/%m/%d %H:%M:%S")) => Wed, 23 Dec 2020 #ある日付を定義 [3] pry(main)> dt2 = DateTime.new(2020,12,23,5,6,7) => Wed, 23 Dec 2020 05:06:07 +0000 #parseで日付情報だけに加工 [4] pry(main)> the_day=Date.parse(dt2.strftime("%Y/%m/%d %H:%M:%S")) => Wed, 23 Dec 2020 #today == the_day [5] pry(main)> the_day == today => true本日の注文を表示させたい時
状況設定
ECサイトの管理者top画面で本日の注文件数を表示させたい。
注文に関するモデル:Orderorders_controllerdef top dt=DateTime.now #まずは、今日の日付を取得。こんな感じ(=> Wed, 23 Dec 2020 05:34:58 +0000) today=Date.parse(dt.strftime("%Y/%m/%d %H:%M:%S")) #日付だけ取り出す orders=Order.all #とりあえず、注文情報全て引っ張ってくる。 @sum=0 #合計件数用。 ※別に初期化しているわけではないことに注意 #@sum = @sum + 1 とした時 「@sumって何?」というエラーが出る。 orders.each do |x| #理系ですので、xと定義させていただきます。 dt2=x.created_at the_day=Date.parse(dt2.strftime("%Y/%m/%d %H:%M:%S")) if today == the_day @sum = @sum + 1 end end end
- 投稿日:2020-12-23T15:50:02+09:00
anyenvでrbenvとnodenvを管理する
はじめに
anyenvを導入した理由はrubyの管理をrbenvからanyenv経由でrbenvをインストールする形式に変えたかったからです。ついでにNode.jsのバージョン管理もnodebrewからnodenvに切り替えました。こうすることで、.zshrc(bashを使う人は.bash_profile)にanyenvのパスを通すだけで済むのでファイルをきれいに保つことができます。anyenv経由でnodenvをインストール
Node.jsをいったんアンインストールする
こちらの記事を参考にさせていただきました。また、
rm -rf .npm-globalでグローバルインストールしたパッケージ等も削除しました。グローバルインストールをしない理由ということでこちらの記事も参考にさせていただきました。anyenvを導入
brewでインストールしていきます。
$ brew install anyenv $ echo 'eval "$(anyenv init -)"' >> ~/.zshrc $ exec $SHELL -l $ anyenv install nodenv $ exec $SHELL -l
~/.zshrcの部分は使っているシェルに応じて変更してください。これだけで完了です!プラグインの導入
anyenv-update
これはnodenvを含めた
~envをまとめてアップデートできるanyenv updateとういコマンドを提供してくれます。$ mkdir -p $(anyenv root)/plugins $ git clone https://github.com/znz/anyenv-update.git $(anyenv root)/plugins/anyenv-update
$anyenv rootの場所はホームディレクトリ直下です。$ anyenv root /Users/shuntagami/.anyenvnodenv-default-packages
anyenv プラグインのanyenv-update と、npmインストール時にデフォルトでいっしょにインストールしておくパッケージを指定できるnodenvプラグインです。
$ mkdir -p $(anyenv root)/plugins $ git clone https://github.com/znz/anyenv-update.git $(anyenv root)/plugins/anyenv-update $ mkdir -p "$(nodenv root)"/plugins $ git clone https://github.com/nodenv/nodenv-default-packages.git "$(nodenv root)/plugins/nodenv-default-packages" $ touch $(nodenv root)/default-packages
default-packagesの中身にインストールしたいパッケージを指定しますdefault-packagesyarn typescript ts-node typesyncnodenvでNode.jsをインストール
$ nodenv install -l $ nodenv install 15.4.0 $ nodenv global 15.4.0最新の15.4.0をインストールしました。これで
node -vと打ってインストールしたバージョンが入っていれば成功です!anyenv経由でrbenvをインストール
rbenvの詳細はこちらの記事でまとめました。
nodenvの導入時と同様、いったんrbenvをアンインストールする必要があります。rbenvをアンインストールする
こちらの記事を参考にさせていただきました。
再びrbenvをインストール
$ anyenv install rbenv $ rbenv install 2.6.5 $ rbenv global 2.6.5バージョンは適宜変えてください。以上で完了です!
補足 railsコマンドがみつからないと言われた時
私はコマンドも消してしまったので再インストールしました。
$ gem install bundler $ gem install rails --version='6.0.0'
- 投稿日:2020-12-23T15:50:02+09:00
anyenvに移行しました!(anyenvでrbenvとnodenvを管理する)
はじめに
anyenvを導入した理由はrubyの管理をrbenvからanyenv経由でrbenvをインストールする形式に変えたかったからです。ついでにNode.jsのバージョン管理もnodebrewからnodenvに切り替えました。こうすることで、.zshrc(bashを使う人は.bash_profile)にanyenvのパスを通すだけで済むのでファイルをきれいに保つことができます。anyenv経由でnodenvをインストール
Node.jsをいったんアンインストールする
こちらの記事を参考にさせていただきました。また、
rm -rf .npm-globalでグローバルインストールしたパッケージ等も削除しました。グローバルインストールをしない理由ということでこちらの記事も参考にさせていただきました。anyenvを導入
brewでインストールしていきます。
$ brew install anyenv $ echo 'eval "$(anyenv init -)"' >> ~/.zshrc $ exec $SHELL -l $ anyenv install nodenv $ exec $SHELL -l
~/.zshrcの部分は使っているシェルに応じて変更してください。これだけで完了です!プラグインの導入
anyenv-update
これはnodenvを含めた
~envをまとめてアップデートできるanyenv updateというコマンドを提供してくれます。$ mkdir -p $(anyenv root)/plugins $ git clone https://github.com/znz/anyenv-update.git $(anyenv root)/plugins/anyenv-update
$anyenv rootの場所はホームディレクトリ直下です。$ anyenv root /Users/shuntagami/.anyenv以下が
anyenv updateコマンドを実行したときの私の例です。$ anyenv update Skipping 'anyenv'; not git repo Updating 'anyenv/anyenv-update'... Updating 'nodenv'... Updating 'nodenv/node-build'... Updating 'nodenv/nodenv-default-packages'... Updating 'nodenv/nodenv-vars'... Updating 'rbenv'... Updating 'rbenv/ruby-build'... Updating 'tfenv'... Updating 'anyenv manifest directory'...nodenv-default-packages
anyenv プラグインのanyenv-update と、npmインストール時にデフォルトでいっしょにインストールしておくパッケージを指定できるnodenvプラグインです。
$ mkdir -p $(anyenv root)/plugins $ git clone https://github.com/znz/anyenv-update.git $(anyenv root)/plugins/anyenv-update $ mkdir -p "$(nodenv root)"/plugins $ git clone https://github.com/nodenv/nodenv-default-packages.git "$(nodenv root)/plugins/nodenv-default-packages" $ touch $(nodenv root)/default-packages
default-packagesの中身にインストールしたいパッケージを指定しますdefault-packagesyarn typescript ts-node typesyncnodenvでNode.jsをインストール
$ nodenv install -l $ nodenv install 15.4.0 $ nodenv global 15.4.0最新の15.4.0をインストールしました。これで
node -vと打ってインストールしたバージョンが入っていれば成功です!anyenv経由でrbenvをインストール
rbenvの詳細はこちらの記事でまとめました。
nodenvの導入時と同様、いったんrbenvをアンインストールする必要があります。rbenvをアンインストールする
こちらの記事を参考にさせていただきました。
再びrbenvをインストール
$ anyenv install rbenv $ rbenv install 2.6.5 $ rbenv global 2.6.5バージョンは適宜変えてください。以上で完了です!
補足 railsコマンドがみつからないと言われた時
私はrailsコマンドも消してしまったので再インストールしました。
$ gem install bundler $ gem install rails --version='6.0.0'
- 投稿日:2020-12-23T13:36:29+09:00
Webの仕組みとHTTPについて
ブラウザとサーバー
ブラウザは今表示されてる画面
サーバーは色んなデータを保存してる大きなPCのようなもの
サーバーからファイルをダウンロードすることでブラウザに表示される
ファイルの中にはHTML、CSS、JSなどの情報が入ってる図で表すとこんな感じ
(ブラウザ) ←←←←←← (サーバー)
ファイル
(HTML,CSS,JS)HTTP
HTTPとはブラウザとサーバーのやりとりの方法
基本はリクエストとレスポンスリクエスト
→→→→→→
(ブラウザ) (サーバー)
←←←←←←
レスポンスリクエストで欲しい情報をサーバーに投げてサーバーがその情報を返してくれる
このリクエストとレスポンスのやりとりのルールを作るのがサーバーサイド言語HTTPの基本メソッド4つ
1.GET データの取得
Webページを表示するときに使用このページ見たい
→→→→→→
(ブラウザ) (サーバー)
←←←←←←
ページの情報2.POST データの送信
フォームなどでデータを保存するに使用データ保存して
→→→→→→
(ブラウザ) (サーバー)
←←←←←←
保存したよ3.PUT データの更新
既存のデータを書き換えるときに使用データ変更して
→→→→→→
(ブラウザ) (サーバー)
←←←←←←
変更したよ4.DELETE データの削除
既存データを消すときに使用データ消して
→→→→→→
(ブラウザ) (サーバー)
←←←←←←
消したよTwitterで例えると
ツイートを表示 GET
ツイートの新規投稿 POST
ツイートの更新 PUT (Twitterはできなかったはず)
ツイート削除 DELETEIPアドレスとドメイン
IPアドレスとはサーバー内でデータに割り振られている住所みたいなもので数字で管理されている
ドメインとは「~~.com」の部分
IPアドレスだと分かりにくいのでDNSというシステムがIPアドレスとドメインを紐付けている最後にWebサイト(Qiita)が表示されるまで
qiita.comのIPアドレス教えて
→→→→→→
(ブラウザ) (DNS)
←←←←←←
IPアドレスを返すDNSから取得したIPアドレスにGETリクエスト
→→→→→→
(ブラウザ) (サーバー)
←←←←←←
HTML、CSS、JSを返すこんな感じです
- 投稿日:2020-12-23T12:46:16+09:00
Rails チュートリアル 第4章 備忘録
第4章の備忘録
環境
Rails 6.0.3
Ruby 2.6.3目次
1 配列・メソッド
2 ブロック
3 ハッシュ
4 シンボル
5 CSSの読み込みを解読1 配列・メソッド
1.1 splitメソッド
文字列を配列に変換することが可能
# デフォルトは空白で区切る >> "foo bar baz".split => ["foo", "bar", "baz"] # 区切る文字を指定することが出来る >> "fooxbarxbaz".split('x') => ["foo", "bar", "baz"]1.2 インデックスに−1を使ってみる
配列のインデックスに
-1を指定すると、配列の最後の要素を取得することが出来る。>> a = [42, 8, 17] => [42, 8, 17] >> a.last => 17 >> a[a.length - 1] => 17 >> a[-1] => 171.3 empty?メソッド
空かどうか調べることが出来る
>> a = [42, 8, 17] => [42, 8, 17] >> a.empty? => false1.4 include?メソッド
指定した値が含まれているか調べることが出来る
>> a = [42, 8, 17] => [42, 8, 17] >> a.include?(42) => true1.5 sortメソッド
配列を昇順(小さい順)に並べ替える
>> a = [42, 8, 17] => [42, 8, 17] >> a.sort => [8, 17, 42]1.6 reverseメソッド
逆順に変更する
>> a = [42, 8, 17] => [42, 8, 17] >> a.reverse => [17, 8, 42]1.7 shuffleメソッド
ランダムな並びに変更
>> a = [42, 8, 17] => [42, 8, 17] >> a.shuffle => [8, 42, 17]1.8 各メソッドに
!を付けるメソッドを使用した値自体も変更させる
>> a = [42, 8, 17] => [42, 8, 17] >> a.sort => [8, 17, 42] >> a => [42, 8, 17] # a自体は変更されていない >> a.sort! => [8, 17, 42] >> a => [8, 17, 42] # a自体も変更される1.9 push( < )メソッド
配列の最後に要素を追加する
>> a.push(6) => [42, 8, 17, 6] >> a << 7 => [8, 42, 17, 6, 7]1.10 joinメソッド
splitメソッドの逆。配列を文字列に変換
>> a = [42, 8, 17, 6, 7, "foo", "bar"] => [42, 8, 17, 6, 7, "foo", "bar"] >> a.join => "4281767foobar" # 連結 >> a.join(',') => "42,8,17,6,7,foo,bar" # 間にカンマを挟んで連結1.11 to_aメソッド
配列に変換する
0..9 : 9を含む>> (0..9).to_a => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]2 ブロック
>> (1..5).each do |i| ?> puts 2*i >> end 2 4 6 8 10 => 10上のコードのように do~endで囲むとブロックになる
ブロック内が複数行になる場合はこちらの方が主流らしい。3 ハッシュ
ハッシュは配列と違って、
・ インデックスに整数値以外が使える(そのハッシュのインデックスをキーと呼び、それに対応するものが値)
・ ハッシュ内の要素の並び順が保証されない4 シンボル
Railsでは文字列よりシンボルが使われる。
文字列との違いはクォートで囲まず、コロンが前におかれる。
ハッシュではシンボルをキーとして使うことが一般的。
また、=>はハッシュロケットと呼ばれ、下のコードのように書き換えが可能。{ :name => "Test Name" } { name: "Test Name" }5 CSSの読み込みを解読
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>このコードを理解するためには、
・ Rubyでは丸カッコを使用しなくても構わない
・ ハッシュがメソッド呼び出しの最後の引数の場合、波カッコ省略可能
を把握することが必要。よって、<%= stylesheet_link_tag ( 'application', { media: 'all', 'data-turbolinks-track': 'reload' } ) %>となり、引数は2つであることが判明する。
最初の要素はメディアタイプを指定、
次の要素はturbolinks機能をオンに設定している。turbolinks : ページ遷移を高速化するライブラリ。Rails4から追加
- 投稿日:2020-12-23T11:24:49+09:00
Rails:find,find_by,whereについて簡単にまとめた
最初に
カレンダー企画2020の23日目
プログラミングの勉強を始めて3ヵ月程経ったので学んだことのメモをアウトプットとして記事に残します。
これからプログラミングの世界に入る人の手助けになれたら嬉しい限りです。
間違っていたり、言葉が違っていたり、誤解されるような言葉があったら教えてください^^
言葉を長々と読みづらかったら申し訳ありません。少しずつなれてがんばります。find,find_by,whereについて
個人的に訳わからず調べて自分なりに解釈した内容です。
他にも細かく載っている記事はたくさんあると思うのでここでは大枠、捉え方ぐらいに思って貰えればいいかと^^;(詳しく書いてもどっかの受け売りでコピペになるのでね^^;)find,find_by,whereこれらはDB(データベース)から必要な情報だけを取り出す為に必要な理解です。
WEBアプリケーションを作成するなら絶対どれかは使う。これだけ覚える
(検索というのは私なりの解釈です。ご了承ください)
メソッド 検索範囲 取得するデータ find id 1つ find_by 指定したカラム 最初の1つ where 指定したカラム すべて find
これだけ覚える
↓
id(主キー)を指定して、見つけた1レコードを取得する。見つけられないと
ActiveRecord::RecordNotFoundというエラーが出る。# インスタンス変数 = モデル名.find(主キー) @post = Post.find(params[:id])こんな感じで記述をします。
idに部分が1や2や3,,,nが入ってそれに関連しているものを取得してくる。
1だったら=> post.find(1)となってpostのid:1のデータを取得する。find_by
これだけ覚える
↓
findの役割に+αでid以外のカラムも指定できるfindは指定できる(検索できる)カラムがid限定でした。
find_byは指定できる(検索できる)カラムがid以外もOKになる。検索結果とは同じ見つかった1レコードを取得してきます。
文字とかも指定できるが、1番最初に見つけたものだけが適応される。#モデル名.find_by(任意のカラム名: 格納されている値) @post = Post.find_by(title: "Qiita")Postのtitleカラム内で「Qiita」と格納されているものを1つ取得する。
idで見つけるならfindを使う
それ以外ならfind_byを使うwhere
これだけ覚える
↓
find_byの役割に+αで取得するレコードが複数になる。whereはfind_by同様に指定できる(検索できる)カラムがid以外もOK
検索結果が1つではなく該当するものすべてになる。
#モデル名.where(任意のカラム名: 格納されている値) @post = Post.where(title: "Qiita")find_byではtitleに「Qiita」とあるもの1つでしたが、
whereではtitleに「Qiita」とあるものすべてを取得します。最後に
解釈の仕方が間違っていたらごめんなさい。
DBからデータを取得するので個人的には図書館で検索する機械とか漫喫にある本の検索機をイメージしましたね。
そうしたら理解できた気がしたので載せました^^
- 投稿日:2020-12-23T11:15:08+09:00
プログラミングを始めて3ヶ月半の未経験が「エンジニアチェッカー」を作ってインフルエンサーを撲滅してしまった話
インフルエンサー見なくなったと思いませんか?
エンジニア界隈をあんなにも盛り上げてくれたインフルエンサー。
最近、ちょっと元気ないですよね。実はこれ、「エンジニアチェッカー」というサービスの影響なんです。
多くの未経験が目を覚ましてしまった
エンジニアチェッカーの基本機能は「エンジニアの皮を被ったインフルエンサー」を検知することです。
まるで優秀なエンジニアであるかのように装って未経験向けに発信してるインフルエンサー、いますよね。
そういった人たちに「インフルエンサー」というレッテルを貼り直してあげるのがこのサービスの仕事です。ありがたいことに、2020年7月のリリースからわずか3日で10000人以上もの方々に使っていただくことができました。
その中にはインフルエンサーをエンジニアだと勘違いしていた未経験もいたでしょう。
情報発信を頑張っているインフルエンサー見習いの未経験もいたでしょう。
もしかしたらインフルエンサーご本人もいたかもしれません。彼らの多くはエンジニアチェッカーを使うことによって改心しました。
インフルエンサーを信じる未経験は消え、インフルエンサーを目指す未経験も消え、そして最後にはインフルエンサーも消えていきました。使用技術
という盛大な前置き(釣り)を経て、エンジニアチェッカーで使用した技術について書かせていただこうと思います。タイトルにもある通りプログラミングを始めて数ヶ月の自分が使った技術ですし決してレベルの高いものではありませんが、外部APIを多く使用しており、それら(札束の力)に頼ることで技術力が低くても提供するサービスの内容をある程度充実させられたと言う点で、特にこれから個人サービス・ポートフォリオを作る駆け出しエンジニアの方に多少なりとも参考になることを願って書きます。
言語・FW
Ruby 2.6.4
Ruby on Rails 5.2.4.3触ったことのある言語がこれしかなかったのでこれで書きました。モデルもDBもないアプリなのでRailsである必要は無かったです。あとCSSも生で書いてます。
外部API
Twitter API
診断対象アカウントのツイート・名前・プロフィール・フォロー・フォロワー等を取得するためにTwitterが提供しているAPIを使いました。実際にはtwitterというgemを使用してAPIを叩いています。エンドポイントごとにリクエスト制限があるため注意です。例えば「フォロワーのリストを取得する」というエンドポイントは、15分に15回までしかリクエストを送れません。
参考:Rate limits — Twitter Developers全くの0からコンテンツを用意しなくてもいいため、Twitterの情報をAPIで持ってきてアレコレ加工するというサービス・ポートフォリオは作りやすいし使ってもらいやすいのではないかなと思います。
Amazon Rekognition
Amazon Rekognition(高精度の画像・動画分析サービス)| AWS
画像解析をしてくれるAWSのサービスです。人間の顔写真に対して推定年齢や性別の解析(顔解析)や、何の生物や物体が写っているかという解析(ラベル解析)を行ってくれます。
リリース当時、容姿端麗な女性をアイコンにして駆け出しエンジニアを装い、フォロワーを集める、スクールの勧誘をしたり情報商材を売りつける、といった手法がにわかに流行っていたのでそれを検知するために使用しました。また「猫エンジニア」や「筋肉エンジニア」の判定にも一部使用しています。画像解析の精度としてはほとんど満足のいくものでした。顔解析について、実物の人間の顔写真に対しては概ね正しく年齢や性別を読み取ってくれますが、二次元アイコンに対してはその多くについて性別をFemale(女性)と認識してしまいます(イラストを解析することを想定していないため、当然といえば当然のことです)。またラベル解析についてはキツネを猫と認識してしまうなどがありましたが、逆にイラストで描かれた猫についても「これは猫である」と認識してくれていたことが多かったと思います。
Amazon Comprehend
Amazon Comprehend(テキストのインサイトや関係性を検出)| AWS
文章をいろいろ解析してくれるAWSのサービスです。今回は感情分析の機能のみを使いました。
Neutral・Positive・Negative・Mixedの4種類の感情のどれに近いかをそれぞれ%表示で分析してくれます。感情分析の用途としては「インフルエンサーの誤判定を防ぐ」ためのものです。
「インフルエンサー的なツイート」「インフルエンサーに関連するツイート」の多さで診断結果が変わってきますが、Comprehendを導入する以前は「インフルエンサーを批判するツイート」に対して上記のインフルエンサー関連ツイートだと評価してしまうケースが多発し、アンチインフルエンサー的なアカウントをインフルエンサーだと診断してしまう、診断サービスとしてあるまじき事態が発生していました。そこでComprehendを導入し、インフルエンサーに対して感情的にPositive(肯定的)なツイートのみをインフルツイートとして計上することで、インフルエンサーの誤判定が圧倒的に減り、かなり実態と近い診断を下せるようになりました。
Comprehendの使用には従量制で課金されるので、一時期は感情分析の野良gemも試してみましたが、やはり分析の精度にかなり差異があり、結果的にはComprehendを選択しました。
インフラ
Heroku(hobbyプラン)
無料プランだとサブドメイン以外で独自ドメインが設定できなかったので月7$払ってhobbyプランにしています。
終わりに
リリースが半年近く前ということで完全に賞味期限切れの話題だと思いますがRUNTEQのアドベントカレンダーに参加させてもらうということで書かせていただきました。
私が卒業したプログラミングスクールのRUNTEQ
https://runteq.jp/インフルエンサーを撲滅してしまったので、今はコラビットという会社で不動産の闇を暴いています!
https://github.com/collabit-inc/job-offer-engineer
- 投稿日:2020-12-23T10:00:22+09:00
Homebrew + rbenv + ruby-build の関係性(後編)実際にrubyとRailsの導入もできます!
前回の記事ではbrewでインストールしたプログラムが
/usr/local/Cellerディレクトリなどに入りシンボリンクを作成することでパスが通ること、各ディレクトリ構成について説明しました。今回は実際にrbenvとruby-buildをインストールして、それぞれのコマンドで何をしているのかを説明していきます。rbenv, ruby-buildのインストール
まずはbrewを最新の状態にしておきます。
% brew update次に
rbenvとruby-buildのインストールです。ruby-buildはrbenvのプラグインの1つです。rbenv installというRubyのバージョンをインストールするコマンドを提供しています。rbenvをインストールする際に、セットでインストールします。% brew install rbenv ruby-buildRBENV_ROOT とは
次のコマンドの説明に必要なのでこの用語の説明をします。RBENV_ROOT というのは rbenv の shims (後述) と versions (Ruby のインストール先) がある場所(パス)を指し示すための環境変数です。 デフォルトではホームディレクトリに直下になっており、以下のように確認できます。
% rbenv root /Users/shuntagami/.rbenvrbenv initの実体
話を戻します。rbenv のインストール手順によると以下のコマンドを実行するようにあります。
% echo 'eval "$(rbenv init -)"' >> ~/.zshrc #(`~/.zshrc`の部分は使っているシェルに応じて変えてください。)これは何を行うのでしょうか? 答えは書いてあるとおり、
shimsとautocompletionを有効化します。shimsには何が入っているのか確認してみましょう。% cd .rbenv % ls shims version versions % cd shims % ls bundle bundler erb gem irb rake rdoc ri ruby testrb,,,bundleやらrakeやらrailsを使ったことのある人ならおなじみのコマンドが入っています。つまり、
shimsを有効化することにより、$RBENV_ROOT/shimsをPATHに入れ,これらのコマンドがどこからでも使えるようになるということです。最後にシェルの設定ファイルの変更を以下のコマンドで読み込みましょう。source ~/.zshrc #(`~/.zshrc`の部分は使っているシェルに応じて変えてください。)rbenvでrubyをインストールする
ここまでで
rbenvのインストールが完了したのでrubyをインストールしていきます。インストール可能なバージョンは以下のように確認しましょう。% rbenv install --list特に理由がなければ最新のバージョンをインストールしましょう。
% rbenv install 2.7.2インストールしたバージョンを使うために以下のコマンドを実行します。
% rbenv global 2.7.2最後に
rbenvを読み込み、変更を反映させます。新しいバージョンの Ruby を入れたときや、実行ファイルを提供する gem を入れたあとには実行するようにしましょう。% rbenv rehashRailsを用意する
rubyの導入が終わり、せっかくなので
Railsの導入手順も説明していきます。bundlerのインストール
bundlerとは、gemのバージョンやgemの依存関係を管理してくれるgemです。bundlerを使うことで、複数人での開発やgemのバージョンが上がってもエラーを起こさずに開発できます。
% gem install bundlerbundler自体もgemなのでインストールが完了すると
1 gem installedと表示されるはずです。Railsのインストール
% gem install rails --version='6.0.0'バージョンを指定してインストールします。完了したら先ほど説明した
rbenv rehashコマンドを実行しましょう。参考
rbenv + ruby-build はどうやって動いているのか
https://takatoshiono.hatenablog.com/entry/2015/01/09/012040rbenv公式
https://github.com/rbenv/rbenv#basic-github-checkoutまとめ
rubyとRailsのインストール手順とそれぞれのコマンドの意味を見ていきました。あとはデータベース,yarn,Node.jsをインストールすればRailsを動かすことができるようになります
- 投稿日:2020-12-23T09:17:43+09:00
Railsの賞味期限を延ばす方法をまとめてみる
はじめに
年末になりアドベントカレンダーが盛り上がってますね。Railsのエントリーも賑わっています。
以下のエントリーに触発されて、大規模な開発になっても少しでもうまく開発が進む方法まとめてみようと思いました。
https://okuramasafumi.hatenablog.jp/entry/2020/12/16/224401
https://blog.unasuke.com/2020/i-have-to-learn-those-things-in-the-future/考え方
この記事では、DDDやアーキテクチャについて議論は取り扱わず、具体的なRubyのコーディング方法を中心にまとめていきます。
まず、原則的になぜRailsが大規模に向かないのか?開発が進むにつれしんどくなっていく理由について考えてみます。大規模開発に向かない理由:
- クラスやオブジェクトの参照箇所が正確に把握できない。このため、リファクタリングはもちろん機能追加などがやり辛く、開発のスピード・品質が悪くなっていく。こんな経験ありませんか?
- Gemのソースコードを追っていたけど、メソッドの定義がどこかわからなくなってしまう
- ネストが深すぎて処理内容がよくわからなくなるRubyのようなスクリプト型言語とコンパイル型言語の大きな違いの1つに動的な関数呼び出しがあり、これが規模が大きくなるにつれ開発を難しくする要因の大きない理由になっています。これを解決する手段として、DDDなどの手法を採用することも多いと思います。
参照箇所がなるべく明示的になるコーディングをする
参照箇所が明示的にわかるようにするには、大まかにいうと "メタプロを避ける" ということが言えます。
具体的には、
- 動的なメソッド定義を避ける=
-#respond_to?を使って処理を変えるコードは避ける
-#sendを使わない
- 静的な処理を動的に処理しない
(例: viewでActiveRecordのattributeを.eachを使って表示を作る )という感じです。
メタプロではありませんが、Railsの標準機能でも避けた方が良い機能もあります。
- Concernなどのモジュールのinclude/mixinは避ける 別クラスに移譲するべき
- ActiveRecordの
before_*/after_*を避ける サービスパターン、コマンドパターンなどで別クラスからメソッドをコールするコーディングルールを定める
より実践的な運用を考えると、ここまで紹介してきたようなポイントを、コーディングルールとして定めてチームで共有しておくと負債の増加が防げて望ましい状況ができます。
また、これらのことが守られているかはレビューでチェックする必要が出てきますが、レビュアーの負担が増えるため、 querly などのツールで検出することが理想的です。
これがあれば新規メンバー加入時も、チームの負担を少なく品質を守り、また新規メンバーもなるべく自力で馴染んでいくことができます。雑感
まとめてみるということで雑記帳のようになりましたが、そのうち統合的に再編集したい気持ちもあります。
ぜひ、よくわからないこと(避けるべき理由や対処法)や他にも気をつけた方が良いポイントなどコメントもらえたら嬉しいです
- 投稿日:2020-12-23T07:26:53+09:00
Payjp v2 ざっくり実装
最近Payjpのv2なるものがリリースされたらしく、Payjp側もセキュリティの向上のためv2の使用を推奨しているらしいです。
少し前に質問があり、気になったので実装してみました。忘れないようにメモとして記事作りました。
細かい説明は省きます。リファレンス見れば誰でも簡単に実装できます。v1との違いは?
v1ではトークン化APIのみを提供しており、カード情報入力フォームは加盟店側で用意する必要がありました。 しかしより安全なクレジットカード商取引のために、最新のPCI-DSSでは、カード情報入力フォームを決済代行業者側で用意することが求められています。 で、 payjp.js v2では、これらのフォームを弊社ドメインのiframe内で用意し、かつ独自スタイルの適用・イベント監視などv1で実現できた機能を提供いたします。 加えて、カード番号入力時の自動フォーマットやレスポンシブデザインなど、ニーズの高かった機能をデフォルトで提供致します。との事です。Payjp側で用意された入力フォームを使えるので、わざわざ作らなくて良い感じらしいですね。
ところでPCI-DSSってセキュリティの基準か何かの基準??
金融業界出身の方いたら、教えて欲しいです。ざっくりと実装
- application.html.hamlにv2のcdnを記載 %head %script{src: "https://js.pay.jp/v2/pay.js", type: "text/javascript"} .....payjp.jsコード
$(function(){ if(document.location.pathname !== "/cards/new") return false; // カード登録ページじゃい時は処理を実行しない const payjp = Payjp('pk_test_7370ce03239ee60f10ca694c') //公開鍵を読み込む。 // Payjp.setPublicKey('pk_...................')としなくて良いらしい const elements = payjp.elements(); // payjpのインスタンス生成 const cardElement = elements.create('card', {style: {base: {color: 'black'}}}) // ここでformを生成してる。createの第一引数には、「card」「cardNumber」「cardExpiry」「cardCvc」とかのタイプを選んで作れる。 // cardだとカード番号、有効期限、cvcの3つをまとめて横並びにしたフォームを生成する // フォームを分けたい人は「cardNumber」「cardExpiry」「cardCvc」を引数にして作ると良いです。 cardElement.mount('#card-element'); // 任意のセレクタ(#card-element)に対してiframe(入力フォームを付与する) const submit_btn = $("#info_submit") // いつものリファクタ submit_btn.click(function(e) { e.preventDefault(); // submitしないように止める payjp.createToken(cardElement).then(function(response) { if (response.error) { // Payjp側からの返ってくるオブジェクトがerrorオブジェクトを持ってた場合 // = 通信に失敗したとき alert(response.error.message) // どの情報に対して不備があるのか教えてくれる。 // 下記に記載しているが該当箇所のエラーを知らせてくれる regist_card.prop('disabled', false); // いつものやつ return ; } else { alert("カード登録が完了しました") $("#card_token").append( `<input type="hidden" name="payjp_token" value=${response.id}> <input type="hidden" name="card_token" value=${response.card.id}>` // これもいつものやつ ); cardElement.clear() // 入力情報を消す $('#card_form')[0].submit() } }) }); });ビュー
.mypage.horizontal-padding-15 = render 'shared/side_bar' .mypage-main .block.horizontal-padding-25 .block__menu 支払い方法 .block.horizontal-padding-25 #card-element -# ↑これ追加しただけ。この#card-elemntがマウントされるセレクタ(名前は何でも良い) #card-icons = image_tag 'icon_visa.png' = image_tag 'icon_master.jpg' = image_tag 'icon_saison.png' = image_tag 'icon_jcb.png' = image_tag 'icon_american.svg' = image_tag 'icon_diners.png' = image_tag 'icon_discover.png' = form_with model: @card, id: "card_form" do |f| #card_token = f.submit "次へ進む", class:"button back-red font-white", id: "info_submit"実際のカード情報入力ページ
入力に不備があると該当箇所に対してアラートもしっかりと出る(V1もできる)
使ってみた所感
好きな方を使いましょう!
あんまり変わらないです!
- 投稿日:2020-12-23T01:18:00+09:00
Railsでバリデーション設定でハマった話
こんばんは
アロハな男、やすのりです!今日はポートフォリオ作成中にモデルのバリデーションでハマった話をしていきたいと思います!!
もしかしたら明日は我が身かも...?
結論
Userモデルのパスワードへのバリデーションは
on: :createを使おう!
ハマった時の状況
え、いやどういうこと...?
となってしまうと思うので、順を追って説明していきます。まずポートフォリオではユーザーが会員登録された場合は、専用のマイページがあったり口コミ投稿ができたりする機能をRailsのGemである
deviseで作成していました。そんな機能の中で、マイページで行える『自身のユーザー情報変更機能ページ』で事件が起こりました...
何があったのか?
ユーザー情報の変更ページではユーザー名やアイコン画像等を変更することができるページなんですが、
deviseを使用していると通常は変更の際に毎回パスワードの入力が必要になります。ただ、『少しの変更で毎回パスワードを入力するのは面倒だなぁ...』という人のために、パスワードを入力しなくても良い様にするメソッドを
deviseは用意してくれています。registrations_controller.rbprotected def update_resource(resource, params) resource.update_without_password(params) end最初はこのメソッドはコメントアウトされているので、コメントアウトを外すことでユーザー情報更新の際でもパスワードを入力しなくてもよくなるはずでした。
しかし実際に変更内容を入力して
更新ボタンを押してみると...『あれ...え、なんで!?パスワードの入力を求められたぞ...!?』
もちろん、この状況でパスワードと確認用パスワードを入力して更新ボタンを押すとユーザー情報が更新されはするんですけど...俺が欲しかったのはこんなよくわかんない機能じゃな〜い!!
ということで、いろいろ調べてみると原因が判明しました。
原因
察しのいい方はもうお気づきかもしれませんが...
そう、今回の事象の原因はUserモデルで設定したパスワードのバリデーションのせいだったんです!!どういうことかと言うと、今回パスワードのバリデーションとして
presence: true(カラムが空だと登録されないオプション)を設定していたんですが、この
カラムが空だと登録できないという部分が効いてしまっていたんです...!!
つまり、Userモデル『お、ユーザー情報を更新するぞ〜』
↓
Userモデル『deviseのコントローラーでパスワードがいらない設定もできてるな〜』
↓
Userモデル『あれ、でもモデルのバリデーションでパスワードが必要だな...』
↓
Userモデル『はい、パスワードも入力してくださ〜い』と言う流れになっていた様です...なんという...
解決策
原因がわかればあとは簡単です。
パスワードに適用されていたバリデーションをユーザー登録の時だけかかる様に設定しなおせば良いだけです。そこで冒頭でお見せした、
on: :create(コントローラーのcreateアクションの時のみ動作する様にするオプション)が必要になります!
今回の私のコードで書くと
user.rbwith_options presence: true do # ユーザー新規登録時のみバリデーションを適用する。 with_options on: :create do validates :password validates :password_confirmation end end※いろいろ他にもバリデーションを記述はしていますが、パスワードだけを抜き出しています。
さぁ、これで無事にユーザー情報が更新される様になりました!
めでたしめでたし最後に
ユーザー機能もパスワードのバリデーションも比較的多くのアプリで必要になってくる機能だと思いますので、もし同じ様なことが会った際は参考にしてみてください!
この件に関するご指摘・アドバイスはどんどんいただきたいと思っていますので、コメントお待ちしています!!
- 投稿日:2020-12-23T01:18:00+09:00
Railsのバリデーション設定でハマった話
こんばんは
アロハな男、やすのりです!今日はポートフォリオ作成中にモデルのバリデーションでハマった話をしていきたいと思います!!
もしかしたら明日は我が身かも...?
結論
Userモデルのパスワードへのバリデーションは
on: :createを使おう!
ハマった時の状況
え、いやどういうこと...?
となってしまうと思うので、順を追って説明していきます。まずポートフォリオではユーザーが会員登録された場合は、専用のマイページがあったり口コミ投稿ができたりする機能をRailsのGemである
deviseで作成していました。そんな機能の中で、マイページで行える『自身のユーザー情報変更機能ページ』で事件が起こりました...
何があったのか?
ユーザー情報の変更ページではユーザー名やアイコン画像等を変更することができるページなんですが、
deviseを使用していると通常は変更の際に毎回パスワードの入力が必要になります。ただ、『少しの変更で毎回パスワードを入力するのは面倒だなぁ...』という人のために、パスワードを入力しなくても良い様にするメソッドを
deviseは用意してくれています。registrations_controller.rbprotected def update_resource(resource, params) resource.update_without_password(params) end最初はこのメソッドはコメントアウトされているので、コメントアウトを外すことでユーザー情報更新の際でもパスワードを入力しなくてもよくなるはずでした。
しかし実際に変更内容を入力して
更新ボタンを押してみると...『あれ...え、なんで!?パスワードの入力を求められたぞ...!?』
もちろん、この状況でパスワードと確認用パスワードを入力して更新ボタンを押すとユーザー情報が更新されはするんですけど...俺が欲しかったのはこんなよくわかんない機能じゃな〜い!!
ということで、いろいろ調べてみると原因が判明しました。
原因
察しのいい方はもうお気づきかもしれませんが...
そう、今回の事象の原因はUserモデルで設定したパスワードのバリデーションのせいだったんです!!どういうことかと言うと、今回パスワードのバリデーションとして
presence: true(カラムが空だと登録されないオプション)を設定していたんですが、この
カラムが空だと登録できないという部分が効いてしまっていたんです...!!
つまり、Userモデル『お、ユーザー情報を更新するぞ〜』
↓
Userモデル『deviseのコントローラーでパスワードがいらない設定もできてるな〜』
↓
Userモデル『あれ、でもモデルのバリデーションでパスワードが必要だな...』
↓
Userモデル『はい、パスワードも入力してくださ〜い』と言う流れになっていた様です...なんという...
解決策
原因がわかればあとは簡単です。
パスワードに適用されていたバリデーションをユーザー登録の時だけかかる様に設定しなおせば良いだけです。そこで冒頭でお見せした、
on: :create(コントローラーのcreateアクションの時のみ動作する様にするオプション)が必要になります!
今回の私のコードで書くと
user.rbwith_options presence: true do # ユーザー新規登録時のみバリデーションを適用する。 with_options on: :create do validates :password validates :password_confirmation end end※いろいろ他にもバリデーションを記述はしていますが、パスワードだけを抜き出しています。
さぁ、これで無事にユーザー情報が更新される様になりました!
めでたしめでたし最後に
ユーザー機能もパスワードのバリデーションも比較的多くのアプリで必要になってくる機能だと思いますので、もし同じ様なことが会った際は参考にしてみてください!
この件に関するご指摘・アドバイスはどんどんいただきたいと思っていますので、コメントお待ちしています!!
- 投稿日:2020-12-23T00:35:52+09:00
[Ruby]作成されてから〇〇以上経ったレコードのみ取得・選択する方法
- 投稿日:2020-12-23T00:16:44+09:00
【Rails】 LIKEで複数の値で検索する方法
- 投稿日:2020-12-23T00:16:05+09:00
Homebrew + rbenv + ruby-build の関係性(前編)
はじめに
最近rubyの管理を
rbenvからanyenv経由でrbenvをインストールする形式に変えようと思っていました。というのも、.zshrc(bashを使う人は.bash_profile)にanyenvのパスを通すだけで済むのでファイルをきれいに保てるというのが1番の理由です。その移行方法について調べている際に「rbenvをよくわかってなかったなあ」と感じたので記事を書くことにしました。また、今回の記事は「homebrewでインストールしたとき」を想定しています。brewでインストールしたものはどこにある?
まず私はこんな基本的なこともわたしは理解していませんでした。homebrewでインストールしたものは
/usr/local/Cellerに入るようになっています。「/usr/local/Cellerにパスを通したことなんてない!」と思ったのですが、homebrew の仕組みにしたがって、適切なバージョンの実行可能ファイルに/usr/local/binからのシンボリックリンク(ショートカット)が作成されるみたいです。つまり、/usr/local/binへのパスが通っていればhomebrewでインストールしたコマンドは使えるようになります。以下のような感じです。$ ll /usr/local/bin/{rbenv,ruby-build} lrwxr-xr-x 1 shuntagami admin 31B 8 3 15:26 /usr/local/bin/rbenv -> ../Cellar/rbenv/1.1.2/bin/rbenv lrwxr-xr-x 1 shuntagami admin 44B 12 20 08:13 /usr/local/bin/ruby-build -> ../Cellar/ruby-build/20201210/bin/ruby-buildちなみに、
PATHは環境変数$PATHに設定されており、echo $PATHで確認できます。以下は私の例です。$ echo $PATH /Users/shuntagami/.anyenv/envs/nodenv/shims:/Users/shuntagami/.anyenv/envs/nodenv/bin:/Users/shuntagami/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbinパスは
:で区切られるので見やすくしてあげます。$ echo $PATH /Users/shuntagami/.anyenv/envs/nodenv/shims /Users/shuntagami/.anyenv/envs/nodenv/bin /Users/shuntagami/bin /usr/local/bin /usr/bin /bin /usr/sbin /sbin
/usr/local/binへのパスが通っていますね!補足で、$PATHに同じパスが通っていたらtypeset -U path PATHで解消できます。binがいっぱいあるけどどういう意味?
先ほどの環境変数
$PATHには/usr/,/binなどがありましたがそれらの違いについて説明します。そもそもbinとはBinary codeのことで実行可能プログラム置き場ということです。 コマンドも実態はプログラムなので権限や用途に合わせてわけて保存されます。/bin
シングルユーザモードでも利用できるコマンドを置きます。逆の言い方をすると、「/usr/bin」や「/usr/local/bin」に置かれているコマンドなどはシングルユーザモードで利用できないということになります。シングルユーザモードは、基本的にOSが壊れて正常に起動できないなど非常時に利用するものですので、「/bin」にはごく基本的かつ非常時に利用するコマンドが置かれることになります。
/sbin
ここにはシステム管理用のコマンドが保存されます。多くのシステム管理用のコマンドはrootユーザーで(管理者になってから)実行されます。
/usr/bin
/usr/binには「シングルユーザモードで利用しない」かつ「RPMやdebなどのパッケージ管理システムによって、システムに管理されるコマンドやプログラム」が置かれます。非常時に利用するものではないが、システムを構成する重要なコマンドやプログラムはここに置かれることになります。また、ここには1000以上のコマンドがあるので
ls -l /usr/bin | lessコマンドを使うと確認しやすいです。/usr/sbin
/binと/usr/binの違いと同様。
/usr/local/bin
/usr/local/binは自分でインストールしたコマンドや自作のコマンドを置くのに使います。
まとめ
brewでインストールしたプログラムが/usr/local/Cellerディレクトリなどに入りシンボリンクを作成することでパスが通ること、各ディレクトリ構成について説明しました。後編では実際にrbenvとruby-buildをインストールして詳細を解説していきます!
参考
「/bin」「/usr/bin」「/usr/local/bin」ディレクトリの使い分け
https://linuc.org/study/knowledge/544/Linux標準教科書
https://linuc.org/textbooks/linux/








