- 投稿日:2020-12-27T23:48:37+09:00
Ruby on Rails でnewコマンドにてアプリを作成するとbundler: failed to load command: spring (/Users/ユーザー名/アプリを作成するディレクトリ名/アプリ名/vendor/bundle/ruby/2.6.0/bin/spring)と出た話
こんばんは。Miyayanと申します。今回初めてQiitaにて記事をあげます。
ゆえに拙い部分もあるかと存じますが、どうぞよろしくお願いいたします。目次
- 環境
- 参考記事
- 概要
- 仮説
- 試したこと
- 解決方法
- まとめ
環境
OS : macOS Big Sur ver.11.1
Ruby : 2.6.5p114
Rails : 6.0.0
bundler : 2.1.4, default: 1.17.2
gem : 3.0.3参考記事
・【Rails6】rails new で bundler: failed to load command: spring が出た。問題はbundler2.1.4かRuby2.7にあるようだが.....
・bundler: failed to load command: spring が出た。。
・「gem update --system」と「gem update」の違い
概要
railsにてnewコマンドを用い、アプリケーションの作成を試みました。
rails _6.0.0_ new アプリ名 -d mysqlすると、下記文面が赤色で表示されるではないですか!
bundler: failed to load command: spring (/Users/ユーザー名/アプリを作成したいディレクトリ/アプリ名/vendor/bundle/ruby/2.6.0/bin/spring)どうもエラーのようでエラーっぽくないと言いますか、正直プログラミング初学者の私からしたらイマイチ何が起きているのかもパッとしない状況・・・。
しかし赤文字ってだけで何かムズムズしてしまう。
どうにかしてこの警告のような文面が出ることなくアプリケーションを作成できないものだろうか・・・。仮説
文面から見るにSpringというものがうまくいってないように感じます。
しかしながら、インストールされているGemを見ると、Installing spring 2.1.1と緑色で表示があり、Springは入っている。正直この警告は無視しても良さそうな感じがします。
参考記事を見てみると、バージョンが2.1.4となっているbundlerが悪さをしているのかと書かれております。では、bundlerをいじってみましょうか。
試したこと
まずbundlerのバージョンを確かめてみます。
% gem list bundler *** LOCAL GEMS *** bundler (2.1.4, default: 1.17.2)参考記事の方々と同じ2.1.4です。
これをアンインストールし、バージョンを再度確認。% gem uninstall bundler Successfully uninstalled bundler-2.1.4 % gem list bundler *** LOCAL GEMS *** bundler (default: 1.17.2)そしてさらに、最新バージョンのbundlerを入れてみます。
% gem install bundlerここで再度bundlerのバージョンを確かめてみましょう。
% gem list bundler *** LOCAL GEMS *** bundler (2.2.3, default: 1.17.2)bundlerが2.2.3にアップグレードされました。
これでnewコマンドでアプリを作成してみましょう!!!bundler: failed to load command: spring (/Users/ユーザー名/アプリを作成したいディレクトリ/アプリ名/vendor/bundle/ruby/2.6.0/bin/spring)出るんかい!!!
どうもbundlerではなさそう。あるいは2.2.3でもSpringの警告文は出るのかもしれない。gemそのもののバージョン・・・?
解決方法
こちらは私の場合、解決した方法です。あくまでご参考程度にしていただけると幸いです。
gemのバージョンを確認してみる。
% gem -v 3.0.3gemのアップデートを試みる。
% gem update --system再度gemのバージョンを確認する。
% gem -v 3.2.3アップデートが完了したようです。
流石にこれで解決するのかなーと半信半疑でしたが、ここで一旦bundlerのバージョンも確認してみます。% gem list bundler *** LOCAL GEMS *** bundler (default: 2.2.3)ん?ちょいと表記が違いますね。
先程はbundler (2.2.3, default: 1.17.2)こういう表示だったのが、gem自体のアップデートを行なったことによりbundlerのdefaultがカチッと最新バージョンになったようです。
ここでrails newコマンドで再度アプリを作成すると、
無事警告が出ることなく作成完了しました!!!まとめ
結論、なぜ解決したのかパッとしませんが、
①bundlerのdefaultバージョンが1.17.2より現行最新である2.2.3へと切り替わったことで解決した。
②gemのバージョンが3.0.3から3.2.3になったことで解決した。以上2パターンかなぁと感じております。
あくまで私の環境下での解決方法ではありましたが、同様に
bundler: failed to load command: spring
が出た方のご参考になれば幸いです。ご覧いただきありがとうございました!
- 投稿日:2020-12-27T23:39:19+09:00
FactoryBot、外部キーバリデーションで弾かれたときの解決方法
はじめに
以前から、FaxtoryBotを使って、Rspecのテストがエラーでなかなか進めませんでした。今回、解決出来たので紹介します。
↓以前の投稿
FactoryBotで外部キーの値はどうやって作り出すんだ〜(泣設計
userテーブルはroomテーブルとアソシエーションしていて、ユーザー登録をする際に、room_idを入力する必要があるような状況です。
ユーザー登録のテストコード一部
user_spec.rbRSpec.describe User, type: :model do describe 'ユーザー登録' do before do @user = FactoryBot.build(:user) end it '全ての項目が入力されていれば、登録できること' do expect(@user).to be_valid end end end
@user = FactoryBot.build(:user)
の部分でいつもエラーが出てしまっていた。FactoryBotの一部
roomモデル
rooms.rbFactoryBot.define do factory :room do Faker::Config.locale = :ja name { Faker::Name.first_name } end enduserモデル
users.rbFactoryBot.define do factory :user do Faker::Config.locale = :ja room { FactoryBot.create(:room) } #元々のエラーの原因はここ email { Faker::Internet.free_email } nickname { Faker::Name.last_name } password = Faker::Internet.password(min_length: 6) password { password } password_confirmation { password } end endRspecのエラーだった原因
ずばり、この部分です。
room { FactoryBot.create(:room) }(修正後) room_id { 1 }(修正前)外部キーにしていた
room_id
を無理やり、「1」という値を入れて、FacroryBotとして生成させようとしていました。しかし、これでは、バリデーションのエラーが出てしまっていました。エラーを解釈すると、「外部キーが見当たらない」みたいな感じです。解決方法
- 外部キーのカラムには
FactoryBotの中に、FactoryBotを打ち込む!!- 細かい点ではあるが、
_id
は記述しない。最後に
これで、やっとテストコードを進めていくことができます。久しぶりに、がっつり知識が増えました!
- 投稿日:2020-12-27T23:39:16+09:00
Railsチュートリアル 14章 FactoryBotでRelationshipのテストデータの作成
はじめに
Railsチュートリアルをrspecに対応させながら取り組んでいたところ、14.2.3のリスト14.28のユーザのRelationshipテストデータをFactoryBotで作ろうとしたときにハマってしまったので、備忘録として投稿します。
環境
- ruby 2.7.2
- rails 6.0.3
- factory_bot_rails 6.1.0
- rspec-rails 4.0.1
やりたいこと
①下記ようにrelationshipのテストデータを作成するfixtureをFactoryBotで定義する。
②userのテストデータも同時にFactoryBotの定義内で作成する。test/fixtures/relationships.yml(リスト14.28)one: follower: michael followed: lana two: follower: michael followed: malory three: follower: lana followed: michael four: follower: archer followed: michael解決方法
試してみて、採用した解決方法を記載します。
その1 Relationshipのテストデータを作成するFactoryを定義(①のみ解決)
一番素直な方法です。follower_idとfollowed_idを持つRelationshipクラスのファクトリーを作成します。ただ、この方法でassociationをうまく設定することができなかったので、userのテストデータを別途作成しました。
spec/factories/relationships.rbfactory :relationship, class: Relationship do follower_id { follower.id } followed_id { followed.id } endspec/models/relationship_spec.rbRSpec.describe Relationship, type: :model do let(:follower) { create(:user) } let(:followed) { create(:user) } let(:relationship) { create(:relationship, follower: follower, followed: followed) } it { expect(relationship).to be_valid } endその2 Relationshipを持つuserのテストデータを作成するFactoryBotを定義(①②の両方解決?)
2つめの方法は、Relationshipを持つuserのテストデータを作成する方法です。userのテストデータはすべてのテストでRelationshipを持っている必要はないので、traitで必要に応じて設定できるようにしています。この方法だと、userとrelationshipのテストデータをそれぞれ作成しなくても良くなりました。しかし、この方法はあくまでuserのテストデータを作成する方法で、relationshipを呼び出すにはuserを通す必要があるので、relationshipのテストには向いていなさそうです。
spec/factories/users.rbfactory :user do . . . trait :has_followed do after(:create) do |user| followed = create(:user) user.follow(followed) end end endspec/models/relationship_spec.rbRSpec.describe Relationship, type: :model do let(:user) { create(:user, :has_followed) } it { expect(user.actve_relationships).to be_valid } end終わりに
結局①②を完全に達成する解決方法を見つけられなかったので、relationshipのテストはその1の方法で、relationshipを持つuserのテストはその2で書くことにしました。
参考文献
- 投稿日:2020-12-27T22:29:29+09:00
【Ruby】便利なやつだよ 〜before_action編〜
コントローラー内の記述でかぶっているものについてまとめてくれる、そんな素晴らしいコマンド「before_action」編です。
class ItemsController < ApplicationController def index @items = Item.order('created_at DESC') end def new @item = Item.new end def create @item = Item.new(item_params) if @item.save redirect_to root_path else render :new end end def show @item = Item.find(params[:id]) end def edit @item = Item.find(params[:id]) redirect_to root_path unless current_user.id == @item.user_id end def update @item = Item.find(params[:id]) @item.update(item_params) if @item.save redirect_to root_path else render :edit end end endアクション内でかぶっている記述がありますね。
上から順番にshow
edit
update
以上3つの「@item = Item.new(item_params)」という記述です。これをbefore_actionを使ってまとめてみます。
class ItemsController < ApplicationController before_action :find_item ⬅️❶まずこれを記述して 〜略〜 def show @item = Item.find(params[:id]) ⬅️❷これを消してく end def edit @item = Item.find(params[:id]) ⬅️❷これを消してく redirect_to root_path unless current_user.id == @item.user_id end def update @item = Item.find(params[:id]) ⬅️❷これを消してく @item.update(item_params) if @item.save redirect_to root_path else render :edit end end private ⬅️❸privateメソッドにして def find_item ⬅️❹find_itemという名前のメソッドを定義して、中身はかぶっている記述をIN @item = Item.find(params[:id]) endそしてページ更新!
はい!エラーになりました!笑
定義したfind_itemメソッドは、かぶっていて記述を削ったアクションにだけ必要になっている。
つまりshow、edit、updateの3つにだけ適用したい。
そんな時はonlyアクションでしたね。しぼっちゃいましょう。class ItemsController < ApplicationController before_action :find_item, only: [:show, :edit, :update] ⬅️❶ここに追加 〜略〜 def show end def edit redirect_to root_path unless current_user.id == @item.user_id end def update @item.update(item_params) if @item.save redirect_to root_path else render :edit end end private def find_ite @item = Item.find(params[:id]) endだいぶスッキリしました。
ずっと同じファイルで記述しているとこういうことが起きやすいのかなと思いました。
コードが増えてきたら一度整理&確認してみることが大事ですね。
今日も良い経験になりました。
- 投稿日:2020-12-27T22:29:29+09:00
【Ruby】便利なやつだよ〜before_action編〜
コントローラー内の記述でかぶっているものについてまとめてくれる、そんな素晴らしいコマンド「before_action」編です。
class ItemsController < ApplicationController def index @items = Item.order('created_at DESC') end def new @item = Item.new end def create @item = Item.new(item_params) if @item.save redirect_to root_path else render :new end end def show @item = Item.find(params[:id]) end def edit @item = Item.find(params[:id]) redirect_to root_path unless current_user.id == @item.user_id end def update @item = Item.find(params[:id]) @item.update(item_params) if @item.save redirect_to root_path else render :edit end end endアクション内でかぶっている記述がありますね。
上から順番にshow
edit
update
以上3つの「@item = Item.new(item_params)」という記述です。これをbefore_actionを使ってまとめてみます。
class ItemsController < ApplicationController before_action :find_item ⬅️❶まずこれを記述して 〜略〜 def show @item = Item.find(params[:id]) ⬅️❷これを消してく end def edit @item = Item.find(params[:id]) ⬅️❷これを消してく redirect_to root_path unless current_user.id == @item.user_id end def update @item = Item.find(params[:id]) ⬅️❷これを消してく @item.update(item_params) if @item.save redirect_to root_path else render :edit end end private ⬅️❸privateメソッドにして def find_item ⬅️❹find_itemという名前のメソッドを定義して、中身はかぶっている記述をIN @item = Item.find(params[:id]) endそしてページ更新!
はい!エラーになりました!笑
定義したfind_itemメソッドは、かぶっていて記述を削ったアクションにだけ必要になっている。
つまりshow、edit、updateの3つにだけ適用したい。
そんな時はonlyアクションでしたね。しぼっちゃいましょう。class ItemsController < ApplicationController before_action :find_item, only: [:show, :edit, :update] ⬅️❶ここに追加 〜略〜 def show end def edit redirect_to root_path unless current_user.id == @item.user_id end def update @item.update(item_params) if @item.save redirect_to root_path else render :edit end end private def find_ite @item = Item.find(params[:id]) endだいぶスッキリしました。
ずっと同じファイルで記述しているとこういうことが起きやすいのかなと思いました。
コードが増えてきたら一度整理&確認してみることが大事ですね。
今日も良い経験になりました。
- 投稿日:2020-12-27T22:26:33+09:00
ファイル生成を抑えた最低限のRails
はじめに
新しくRailsでアプリを作ろうとした際に、余計なファイルが生成されてしまうのが気になったので、今回は自分に必要な最低限のファイル生成でrails newをする方法、設定を書きます。
Rails newのオプション
rails newにオプションをつけることで、指定した関連のファイルを生成しないでアプリを作ってくれます。
以下によく使いそうなオプションをいくつか上げていきます。中にはファイル生成以外の物も含まれています。使用データベースの指定
rails new sample_app --database=mysql--database=(任意のDB)で最初から指定したDBでアプリを作ってくれます。指定しない場合はsqliteになるはずです。勿論DBは後から変更することはできますが、少々面倒なので使用DBが決まっている場合は先に指定してしまいましょう。
minitestの除外
rails new sample_app --skip-testrails標準搭載のminitestを生成しなくなります。Rspecを使用する際には確実に使うオプションです。skipオプションは他にもあります。
turbolinksの除外
rails new sample_app --skip-turbolinksページ遷移をAjaxに置き換え、JavaScriptやCSSのパースを省略して高速化させるturbolinksを取り込まなくなります。turbolinksはreadyが発火しないなどの問題もありますので、除外する方もいるみたいです。
.gitignoreの除外
rails new sample_app --skip-gitデフォルトのgitignoreを生成しなくなります。予めpushしないファイルを決めてgitignoreを用意している場合に使います。
APIモード
rails new sample_app --apiアプリをAPIとして作成する際の小さな構成で作ってくれます。MVCのVがなくなった感じです。デフォルトのgemもかなり削減されます。詳しくは最後に参考記事を載せますので、そちらをご参照ください。
Rails new後の設定
rails generateを使用することで簡単にコントローラーやモデルを作成できますが、同時に要らないhelperやtestが生成されてしまうことがあります。そういった場合はconfigのapplication.rbにgenerateコマンドの設定を記述します。
config/application.rbmodule Sample class Application < Rails::Application config.generators do |g| g.stylesheets false #stylesheetsが自動生成されなくなる g.helper false #helperが自動生成されなくなる g.test_framework false #test及びfixtureが生成されなくなる end end endこれはあくまで一例ですが、こういった設定をすることでファイル量をかなり減らすことができます。
終わりに
簡単なオプションを付け加えるだけでしたが、快適な開発を進める上でかなり役立ちました。
参考にさせていただいた記事
- 投稿日:2020-12-27T20:43:18+09:00
クッキーとセッションの仕組み
概要
クッキーとセッションについて学習したので自分用メモとしてアウトプットしていきます。
はじめに
ショッピングサイトでログイン情報を入力しなくてもログインできたり、(自分が削除しない限り)カートに入れた商品がしばらくカートに入ったままになったりしますよね。これは、セッションとクッキーの仕組みがあるため実現できています。
セッション(session)
- Webサービスに情報を一時的に保持してくれる仕組み
- アクセスの開始から終了までの一連の通信
- Railsでは
session
というオブジェクトにハッシュのような形で格納されるクッキー(cookie)
- ブラウザが持っているデータを保存できる領域
- セッション情報(ID)を保存する場所
- 有効期限がある
CookieStore
- Railsでセッションを利用する際のデフォルトの保存先
- セッション情報は暗号化してブラウザのCookieに保存される
- ハッシュ形式でセッションを保存する
まとめ
- セッションとはアクセスのはじめから終わりまでの一連の通信
- クッキーとはセッションなどユーザーのデータ(ID)を保存するブラウザの領域
- SessionとはRailsでセッションを利用する際のオブジェクト
- CookieStoreとはRailsでセッションを利用する際のデフォルトの保存先
参考文献
- 投稿日:2020-12-27T20:05:57+09:00
deviseを用いたユーザー認証機能の作成
アプリケーションに"devise"を読み込ませる
Gemfile: gem 'devise' #追加terminal$ bundle installdeviseコマンドでモデル、ビュー、コントローラを作成
terminal$ rails g devise:install $ rails g devise User name:string #モデルの作成 $ rails db:migrate $ rails g devise:views users #ビューの作成 $ rails g devise:controllers users #コントローラの作成
rails g devise "model名"
で作成したモデルには初期値ではnameカラムが存在しない為、上記のようにカラムを同時に作成するか、migrationファイルに記述してテーブルに反映させる。・作成されたモデル
app/models/user.rbclass User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable endデフォルトの機能
- database_authenticatable(パスワードの正確性を検証)
- registerable(ユーザー登録や編集、削除)
- recoverable(パスワードをリセット)
- rememberable(ログイン情報を保存)
- validatable(emailのフォーマットなどのバリデーション)
ルーティングの変更
config/routes.rb...編集 devise_for :users # devise機能の使用の際にURLにusersを含むことの宣言 ↓ devise_for :users, controllers: { sessions: 'users/sessions', registrations: 'users/registrations' }ビューページの編集
新規登録画面に名前の入力フォームを追加
app/views/users/registrations/new.html.erb... +の部分を追加 + <div class="field"> + <%= f.label :name %><br /> + <%= f.text_field :name, autofocus: true, autocomplete: "name" %> + </div> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> :ログイン画面の入力フォームを
name
に変更
これによりemailでのログイン認証へと変更させるapp/views/users/sessions/new.html.erb...編集 : <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> ↓ <div class="field"> <%= f.label :name %><br /> <%= f.text_field :name, autofocus: true, autocomplete: "name" %> </div> :コントローラの編集
app/controllers/application_controller.rb...追加 before_action :configure_permitted_parameters,if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up,keys:[:name]) enddevise利用の機能(ユーザ登録、ログイン認証など)が使われる場合、その前に
configure_permitted_parameters
が実行
devise_parameter_sanitizer.permit(:sign_up,keys[:name])
= ユーザ登録(sign_up)の際のユーザ名(name)のデータ操作を許可
Strong Parameters
と同様の機能
・private = 自分のコントローラ内のみで参照
・protected = 呼び出された他のコントローラからも参照可能ログアウト機能の実装
app/views/layouts/application.html.erb...+部分の追加 <body> + <% 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 %> :以上
記載内容に間違い等ございましたらご指摘頂けると幸いです。
ご連絡お待ちしております。
- 投稿日:2020-12-27T20:01:24+09:00
hidden_field_tagの使い方
はじめに
Railsアプリ作成時に
hidden_field_tag
を使ったので、その時の内容のメモ書きになります。
検索機能を使った時にパラメータが飛ばなかったのでhidden_field_tag
を使用し対応した時の内容になります^^使用方法
hidden_field
とhidden_field_tag
は用途は似ているが使い方が違う。
hidden_field
はform_for
やform_with
の中で使用するに対し、
hidden_field_tag
は一つだけで使用でき単体でパラメーターを渡したいとき
に使用する。
form_for
内でも使用はできます。作業内容
このように検索窓のソースがあります。
app/views/texts/index.html.erb<%= search_form_for @eq do |f| %> <div class="d-flex"> <div class="form-group flex-grow-1"> <%= f.search_field :title_cont, placeholder: "教材を探す", class: "form-control" %> </div> <div> <%= f.submit "検索", class: "btn btn-primary ml-1" %> </div> </div> <% end %>viewの表示はこのようにコントローラーで指示をしています。
app/controllers/texts_controller.rbdef index if params[:genre].nil? @eq = Text.where(genre: ["Ruby on Rails", "Git","Basic","Ruby"]).ransack(params[:q]) else @eq = Text.where(genre: params[:genre]).ransack(params[:q]) end @texts = @eq.result.order(:id) endそこで
indexアクションに記述してある
if params[:genre].nil?
はパラメータが空ならture
で以下実行するという記述です。一部ページのパスに
genre:
を埋め込んでいます。<%= link_to " Ruby/Rails教材", texts_path, class: "dropdown-item" %> <%= link_to "動画教材", movies_path, class: "dropdown-item" %> <%= link_to "PHP教材", texts_path(genre: "PHP"), class: "dropdown-item" %> <%= link_to "プログラミング勉強会", movies_path(genre: "Live"), class: "dropdown-item" %> <%= link_to "質問集", questions_path, class: "dropdown-item" %> . . . .表示するページ事に
[:genre]
を付けて色分けしています。
なのでリンクからの表示なら問題は無いのです。が、
今回は
検索して表示
が目的なので、このままだと
キーワード検索してもgenreのparams
に値が無いのでtrue
で表示されます。app/views/texts/index.html.erb<%= f.search_field :title_cont, placeholder: "教材を探す", class: "form-control" %>↑今のままだと検索かけたとしてもユーザーが記入した文字列しか飛ばしていません。
ターミナル部分一致検索→"p"→検索 Parameters: {"q"=>{"title_cont"=>"p"}, "commit"=>"検索"} User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 3], ["LIMIT", 1]] From: /Users/ikedakeigo/Desktop/gyakuten_clone_group27/app/controllers/texts_controller.rb:4 TextsController#index: 2: def index 3: binding.pry => 4: if params[:genre].nil? 5: @eq = Text.where(genre: ["Ruby on Rails", "Git","Basic","Ruby"]).ransack(params[:q]) 6: else 7: @eq = Text.where(genre: params[:genre]).ransack(params[:q]) 8: end 9: @texts = @eq.result.order(:id) 10: end [1] pry(#<TextsController>)> params[:genre] => nil ⇦:genreに値が入っていない。そこで
hiddenfield_tag
の出番です!
:genreを単体で送り込みましょう。app/views/texts/index.html.erb<%= search_form_for @eq do |f| %> <div class="d-flex"> <div class="form-group flex-grow-1"> <%= f.search_field :title_cont, placeholder: "教材を探す", class: "form-control" %> </div> <div> <%= hidden_field_tag(:genre, "Php")%> ⇦追加 <%= f.submit "検索", class: "btn btn-primary ml-1" %> </div> </div> <% end %>このように記述すると検索キーワードと:genreを飛ばすことができます!
が、
このままだと常に中身がPhp
でfalse
が返され特定の物しか検索できない形になります。そこで条件分岐を付けて上げて柔軟に対応するようにします。
app/views/texts/index.html.erb<%= search_form_for @eq do |f| %> <div class="d-flex"> <div class="form-group flex-grow-1"> <%= f.search_field :title_cont, placeholder: "教材を探す", class: "form-control" %> </div> <div> <%= hidden_field_tag(:genre, params[:genre]) if params[:genre].present? %> ⇦追加 <%= f.submit "検索", class: "btn btn-primary ml-1" %> </div> </div> <% end %>
present?
メソッドは「〜が存在するとき」
の条件分岐表示しているページによって
:genre
に値を付けているので、
それで判断させています。これでページ事のキーワード検索ができました!^^
おわりに
コード書いていると極々普通なことかもしれませんが、
悩んでいたことが、上手くできると
「ん?いや、普通に考えたらわかるやん!」っておわりに気づくことがあります^^笑なんでも諦めないことですね!^^
- 投稿日:2020-12-27T19:06:59+09:00
form_withのlocalとflashメッセージ
ちょっと困ったこと
Railsでよくあるflashメッセージを出そうと頑張っていたが、flash.nowだけ出せない。。。
例えば、以下のようにSessionControllerで、ユーザログインを行うようなコードを書く。
def create @user = User.find_by(login_id: params[:session][:login_id]) if @user && @user.authenticate(params[:session][:password]) log_in(@user) redirect_to @user, success: 'ログインしました' else flash.now[:danger] = 'ログインに失敗しました。' render :new end endログイン成功したとき、すなわち、redirect_toした後の「ログインしました」は出るんだけど、ログイン失敗した時、すなわち「ログインに失敗しました」が全く表示されないという問題が発生しました。
問題点
結論から言うと、form_withに対してlocal: trueをつけていなかったからでした。
そのため、以下のようにlocal: trueをつけたらうまくいきました。= form_with scope: :session, url: login_path, local: true do |f| = f.label :login_id, 'ログインID' = f.text_field :login_id, { class: 'form-control' } = f.label :password, 'パスワード' = f.password_field :password, { class: 'form-control' } = f.submit 'ログイン', class: 'btn btn-primary'なぜlocal: trueが必要か
話がそれますが、form_withにはlocalオプションなるものがあることは知っていました。form_withを使うにあたって、色々調べながら実装していったわけで、参考にする情報は大体local: trueがついていました。
ただ、別にlocal: trueなくても、普通にログインセッション張れるし、つけなくてもいいんじゃね?ということに気がついたので、local: trueは外していました。しかしながら、今回こういう壁にぶち当たった以上、このlocal: trueって何ですか、というところを放置するのはよくないと思ったので、もう少し深堀してみます。
そもそもform_withにおけるlocalオプションって何?
とりあえずRailsドキュメントを見ましょう。https://railsdoc.com/page/form_with
すると「local:リモート送信の無効」と書いています。これだけでは何のことだかさっぱりです。もう少し詳しく見たかったので、こちらをあたりました。https://techracho.bpsinc.jp/hachi8833/2020_03_09/39502#6
すると「local: trueを指定するとフォームのリモート + unobtrusive XHR送信が無効になります(デフォルトのフォームではリモート + unobtrusive XHRが有効になります)」という記載があります。これだけ見るとはてなマークばかりですが「unobtrusive XHR送信」というのはAjax通信のことです。というわけで、form_withにおけるlocalオプションは「当該箇所のform_withはAjax通信を無効(true)にするか、有効(false)にするか」ということになります。
Ajax通信と今回のflashメッセージ問題考察
さて、ここからは完全に憶測になるので、誤った記載となると思います。参考にする場合はほどほどでお願いします。ちなみに、Ajaxについての詳しい記載は本筋とは少し違うので、省略します。詳細を知りたい方は、本記事最後の参考をどうぞ。
考察
元のコードでうまくいかなかった理由
- form_withでlocalを指定しない場合、デフォルトでlocal: falseが設定される、すなわち、Ajax通信有効となっている。
- 今回私が書いたコードもそうなっている。
- これにより、ログインセッションを作成する処理は非同期通信で行われている。
- 非同期通信のため、クライアント側からサーバ側にログインセッションを生成しに行ってもそれがうまくいったかどうかはサーバ側から、クライアント側に返ってこない
- 例えば、HTTPステータス200とか404とかの情報が返ってこない。
- 今回のケースで言うと「ログイン失敗した」という情報がサーバ側から返ってこないため「flash.now[:danger]」は実行されない。
ところで冒頭に書きましたが「local: trueがない状態で、サーバ側からログインセッション生成しに行った結果が返ってこないのに、なぜ「ログインしました」のメッセージが出て、ログイン後の画面に遷移するのか」という次の疑問が出てきます。
これは、renderメソッドとredirect_toメソッドの違い、というところにあるかと思っています。ざっくりいうと、renderはHTTPリクエストをサーバに送らず、redirect_toはHTTPリクエストをサーバに送ります、というところですね。
今回のケースではログイン処理後にredirect_toを実行している、すなわちサーバからリクエストを送っています。redirect_toメソッドはリクエストに応じたHTMLをクライアントに返すので、クライアント側で画面遷移が発生します。
local: trueでうまくいった理由
上記の裏返しなんですが、local: trueにして、Ajax通信を無効、すなわち同期通信をすることによって、サーバからログインできたかどうかの結果がちゃんと返ってきます。それを検知して、flashメッセージが出せるようになるわけです。
参考記事
MDN
https://developer.mozilla.org/ja/docs/Web/Guide/AJAX/Getting_StartedMDNよりわかりやすいQiitaの記事
https://qiita.com/hisamura333/items/e3ea6ae549eb09b7efb9renderとredirect_to
https://qiita.com/january108/items/54143581ab1f03deefa1
- 投稿日:2020-12-27T19:03:54+09:00
resources & resource
resources
Ruby on Railsでルーティングを行う際に必ずと行っていいほど頻出である
resources
。
resources
はモデルに対してアプリケーションにおける基本メソッド7つを自動的にルーティングしてくれます。例えば
User
モデルに対してresources
を使ってルーティングを記載した場合config/routes.rbRails.application.routes.draw do resources :users end
$ rails routes
でルーティングを表示させると以下のようになります。$ rails routes Prefix 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 DELETE /users/:id(.:format) users#destroyこのようにして、たった1行記載するだけで、簡単にルーティイングをしてくれます。
resourcesが使われるのは基本的にモデルに複数のリソースがある時です。
例えば、User
モデルにはアプリケーションのユーザのモデルがたくさん登録されると思います。
他にも、ユーザの投稿モデルであるPost
モデルも、アプリケーション内に複数の投稿が存在するので、resources
を使用することができます。resource
では、複数リソースに対してではなく単数のリソースにルーティングする場合はどうでしょうか?
単数のリソースとはつまり、アプリケーション内のページにおいて、ログインユーザだけが使用するリソースです。
例えば、Instagramの設定にあるプロフィールページは自分だけが使用できますよね?
他の人はあなたのプロフィール設定ページににアクセスすることはできません。(できたらアカウントが乗っ取られています笑)そのような単一リソースに対してルーティングを設定する際は
resources
ではなく、単数形resource
を使います。
例えば、プロフィール画面をルーティングするとしましょう。config/routes.rbRails.application.routes.draw do resources :users # 追記 resource :profile end$ rails routes Prefix Verb URI Pattern Controller#Action new_profile GET /profile/new(.:format) profiles#new edit_profile GET /profile/edit(.:format) profiles#edit profile GET /profile(.:format) profiles#show PATCH /profile(.:format) profiles#update DELETE /profile(.:format) profiles#destroy POST /profile(.:format) profiles#create
resources
と何かが違いますね、、。①indexアクションがない
なぜ?、と思うかもしれませんが、これはよくよく考えてみると簡単です。
上述したように、
resource
を使用する場合、単一リソースが使用対象をなることを説明しました。
しかし、index
アクションはモデルのリソース全てを表示することを意図しています。
結果、単一リソースであるプロフィール画面を扱う際に複数を表示するindex
アクションは不要となるわけです。②:idがない
4つのアクション(edit、show、update、destroy
)から:idという部分が消えています。実はこれも
index
アクションがない理由と同じになります。
resources
において4つのアクションに:id
が必要だった理由は、複数あるリソースの中からどのリソースかを指定するためです。
例えば、自分の投稿を編集する場合、どのidの投稿かを指定しないと、どの投稿を編集していいのかがわかりません。投稿の詳細閲覧、投稿の更新、投稿の削除も同様に、どの投稿であるかを指定しないといけません。しかし、プロフィール設定画面はどうでしょうか。
単一リソースであるプロフィールは、指定せずとも一つしかないのだからわかるという仕組みです。
ですので、idを指定する必要がそもそもないという理由で:id
が消えています。
- 投稿日:2020-12-27T17:34:20+09:00
Rails チュートリアル 第8章 備忘録
第8章の備忘録です。
環境
Rails 6.0.3
Ruby 2.6.3目次
1 セッションとcookies
2 フラッシュメッセージ表示
3 ヘルパーメソッドを作成して利用するまでの流れ
4 jqueryとbootstrapの導入方法
5 signupした後に再度ログインさせない1 セッションとcookies
日頃通信する時に利用されているHTTPはステートレスなプロトコルである。
そのステートレスとは、
ブラウザ側が、〇〇のページを表示してください(リクエスト)→サーバー側が、〇〇のページです!(レスポンス)のやりとりをトランザクションというのだが、一度そのやりとりを終えるとすっかり忘れてしまうのである。つまり、会員サイトでログインした後に、この商品の購入ページを表示してくださいとリクエストを送ると、以前のログインしたやりとりを忘れてしまっているので、あなたは誰ですか?となってしまう。
それを防ぐために、ユーザーのIDを保持しておくための設定がセッションである。
そして、そのセッションを実装するために使われるのが、cookiesである。cookiesはブラウザに保存することができる小さなでキストデータである。ここにログインしたらユーザーのIDを保管、ログアウトしたらcookiesに保管したものを削除することで、ログインの機能を作っているのである。
2 フラッシュメッセージ表示
第7章で実装した、新規登録時に表示されるフラッシュメッセージは、ActiveRecordオブジェクトに関連づけられていたものだが、セッション時にはActiveRecordを使用していないので、別の方法で作成する必要がある。
app/controllers/sessions_controller.rbclass SessionsController < ApplicationController def new end def create user = User.find_by(email: params[:session][:email].downcase) if user && user.authenticate(params[:session][:password]) # ユーザーログイン後にユーザー情報のページにリダイレクトする else flash.now[:danger] = 'Invalid email/password combination' render 'new' end end . . end実装の流れとしては、
表示したいタイミングで、flashメソッドを使用。application.html.erb
でCSS含めレイアウトしてあるので、この1行で自動的に表示される。また、flashメソッドだけだと、再レンダリングしても消えない小さなバグが発生するため、flashメッセージを表示した後に、リクエストが発生したら表示を消す機能を含んだ、
flash.now
メソッドを使用する3 ヘルパーメソッドを作成して利用するまでの流れ
ここまで来ると、各Controller毎に、ログインしているかどうかでの条件分岐が多発してくる。毎度毎度のコードを簡潔にメソッドとしてまとめておくと、コードが簡略化されるため、自身でメソッドを作成し使用するまでの流れをまとめる。
application_controller.rb
に、ヘルパーモジュールを読み込む(今回はsessions_helper.rb
)app/controllers/application_controller.rbclass ApplicationController < ActionController::Base include SessionsHelper end
- 自作メソッドをhelperファイルに作成(今回はlog_inメソッド)
app/helpers/sessions_helper.rbmodule SessionHelper def log_in(user) session[:user_id] = user.id end end
- Controllerファイルで使用
appp/controllers/sessions_controller.rb. . def create . . log_in user . end .こうすることで、実際にメソッドを使用することができる。
今回はlog_inメソッドの中身も1行であるが、今後複数行のメソッドを作ることも想定し同じ動作を繰り返すのであれば、このようにすることで、メソッド名を設定することで可読性も上がり、DRYであることに繋がる。4 jqueryとbootstrapの導入方法
Rails6から設定方法が変わった?かもしれないらしいので、今回はRails6での設定方法をまとめる。
- yarnでインストール
$ yarn add jquery@3.4.1 bootstrap@3.4.1
- WebpackにjQueryの設定を追加
config/webpack/environment.jsconst { environment } = require('@rails/webpacker') const webpack = require('webpack') environment.plugins.prepend('Provide', new webpack.ProvidePlugin({ $: 'jquery/src/jquery', jQuery: 'jquery/src/jquery' }) ) module.exports = environment
- 必要なJSファイルをrequire / import
app/javascript/packs/application.js. . require("jquery") import "bootstrap"5 signupした後に再度ログインさせない
signupの機能を作った後に、login機能を作るとうっかり忘れがちになりそう?なのだが、実際にsignupすると、ログイン状態にならない。
実際の動きは、
redirect_to @user
で/users/◯
のshowビューが表示されているのだが、セッションにユーザーIDを保存していないので、セッションを用いて作成したcurrent_user
やlogged_in
メソッドが使えない、もしくはfalseを返す。こうならないためにも、signup時の
create
アクションでユーザーが保存されたら、log_in @user
を忘れない。わざわざ書くまでのことではないのかもしれないが、ユーザー登録自体がめんどくさいと思ってしまう自分だったら、仮に新規登録した後に、ログイン画面で再度入力しなければならなくなった場合、そっとそのアプリを閉じると思う。。笑
ちょっとしたユーザービリティも考えて一応メモ。
- 投稿日:2020-12-27T17:17:06+09:00
Ruby on Rails ✕ Docker 開発中のアプリにDocker導入(MySQL)
はじめに
はじめてのDocker導入だと、何から手を付けたら良いのかわからない、ということがよくありますが、まさに自分がそれでした...
本記事では開発途中・完成したRailsアプリケーション(DB: MySQL)にDockerを導入する方法・流れを解説していきます。
参考までに自分は6時間位かけてローカルに導入できました。その苦労を忘れないようにしっかりアウトプットしていこうと思います(笑)
間違っていたら指摘してくださると幸いです!Dockerの導入
1)Dockerのインストール
まずMacにDockerのアプリをインストールしてください
それに関しては以下の記事がわかりやすいです!
DockerをMacにインストールするインストールできたらターミナルで以下コマンドを実行しましょう!
ターミナル~ % docker run -d -p 80:80 docker/getting-started2)インストールの確認
ターミナル~ % docker -v以下のように出力されたらインストール成功です。
Docker version 20.10.0, build 7287ab3
ターミナル~ % docker-compose -vこちらも同じように
docker-compose version 1.27.4, build 40524192
と出力されたら成功です。3)開発中・完成済みのアプリでDockerファイルの作成
次にDockerを導入するためにDockerファイルを作成し、設定を記述していきます。
テキストエディタでも可能ですが、自分の場合はターミナルから入力して方がエラーもなくスムーズだったため、そちらの方法を記載していきます。①Dockerfileの作成
まずアプリのルートディレクトリにDockerfileを作成して、記述していきます。
ルートディレクトリというのは以下の図のようにアプリ直下のディレクトリを表します。dock_app ----|-- app |-- bin |-- config |-- db ・・・・・・ ・・・・・・ |-- Gemfile |-- Gemfile.lock |-- package.json |-- Rakefile |-- README.md |-- Dockerfile ←「Dockerfile] |-- docker-compose.yml ←[docker-compose.yml]手順としては以下の順に進んでいきます。
ターミナル① ~ % cd Dockerを導入したいアプリのパス ② アプリ名 % vi Dockerfile #ファイルを開いたら「i」でインサートモードにして以下記述 FROM ruby:2.6.5 #アプリのRubyバージョン RUN apt-get update -qq && \ apt-get install -y build-essential \ libpq-dev \ nodejs RUN mkdir /アプリ名 WORKDIR /アプリ名 ADD ./Gemfile /アプリ名/Gemfile ADD ./Gemfile.lock /アプリ名/Gemfile.lock RUN gem install bundler #bundlerをインストールしないとエラーが出る RUN bundle install ADD . /アプリ名 #記述ができたら「escキー」を押して「:wq」で保存②docker-compose.ymlファイルの作成
ターミナル① アプリ名 % vi docker-compose.yml ② docker-compose.ymlに以下記述 #「i」と入力しインサートモードで記述 version: '3' services: db: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: 'password' # このままpasswordとしても問題なく動く ports: - "4306:3306" #DockerコンテナとSequelpro接続の為に必要な設定 web: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/アプリ名 ports: - "3000:3000" depends_on: - db #記述が終了したら「escキー」を押して「:wq」で保存4)config/database.ymlファイルの編集
(テキストエディタ)default: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: password # passwordの設定がなければ、このままで良い socket: /tmp/mysql.sock host: db development: <<: *default database: アプリ名_development追加されたのは
password: password
とhost: db
の2つのみ。5)docker-compose buildでコンテナ作成
ターミナルアプリ名 ~ % docker-compose build上記コマンドを実行してコンテナを作成しましょう。※時間がかかることがあります
以下のように出力されれば成功です。
ターミナルRemoving intermediate container dac250609513 ---> f0ba8d685e44 Step 9/9 : ADD . /tumlog ---> f50cb7681119 Successfully built f50cb7681119 Successfully tagged tumlog_web:latestちなみに初心者の方だとコマンド実行中に赤字で
debconf: delaying package configuration, since apt-utils is not installed
と表示されますが、自分の調べた範囲では特に気にするようなこともない?出力のようです。6)コンテナ上でDB作成・migrationの実行
コンテナが作成できたらコンテナ上でDBを作成していきます。
ターミナルアプリ名 % docker-compose run web bundle exec rake db:createRails6だとこのコマンドを実行すると
======================================== Your Yarn packages are out of date! Please run `yarn install --check-files` to update. ======================================== To disable this check, please change `check_yarn_integrity` to `false` in your webpacker config file (config/webpacker.yml).このように出力されることがあります。
このように出力されたら、エラー分通りconfig/webpacker.ymlファイル
の記述を以下のように編集しましょう。webpacker.yml# Verifies that correct packages and versions are installed by inspecting package.json, yarn.lock, and node_modules check_yarn_integrity: true # check_yarn_integrity: true を falseに変えましょう → check_yarn_integrity: falseこれでエラーは解決できると思うので、記述を変更したら、もう1度DB作成のコマンドを実行しましょう。
ターミナルCreated database 'アプリ名_development' Created database 'アプリ名_test' #上記のようにcreatingがcreated...doneとなったら成功続いてmigrationを実行しましょう。
ターミナルアプリ名 % docker-compose run web bundle exec rake db:migrate == 20201222010929 Createテーブル名: migrating ==================================== -- create_table(:テーブル名) -> 0.0095s == 20201222010929 Createテーブル名: migrated (0.0096s) =========================== # 上記のようにrails db:migrateを実行したときのようにマイグレーションが実行されれば成功です7)コンテナの起動
最後にコンテナを起動して無事、アプリがブラウザで表示されるか確認しましょう。
コンテナの起動コマンドを実行しましょう。
ターミナルアプリ名 % docker-compose up # 起動していれば以下の様の出力が出る db_1 | 2020-12-27T06:45:52.494912Z 0 [Note] Event Scheduler: Loaded 0 events db_1 | 2020-12-27T06:45:52.497330Z 0 [Note] InnoDB: Buffer pool(s) load completed at 201227 6:45:52 db_1 | 2020-12-27T06:45:52.497669Z 0 [Note] mysqld: ready for connections. db_1 | Version: '5.7.32' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL) web_1 | => Booting Puma web_1 | => Rails 6.0.3.4 application starting in development web_1 | => Run `rails server --help` for more startup options web_1 | Puma starting in single mode... web_1 | * Version 3.12.6 (ruby 2.6.5-p114), codename: Llamas in Pajamas web_1 | * Min threads: 5, max threads: 5 web_1 | * Environment: development web_1 | * Listening on tcp://0.0.0.0:3000 web_1 | Use Ctrl-C to stopコマンドを実行し、サーバーが起動したらローカル環境にアクセスしてみましょう
http://localhost:3000/
無事に表示・挙動が確認できれば開発環境にDockerを導入できたということになります。自分はこれだけで6時間くらいかかったので、ぜひ皆さんは本記事を活用して、さくさく進めていってください!!
本記文献
①『さわって学ぶクラウドインフラ docker基礎からのコンテナ構築』
② 既存のrails6のアプリにMySQLでDockerを導入する。
③ Ruby on Rails 「途中まで作ったアプリにDockerを導入したい」に挑戦してみる(MySQL / Sequel Pro)
- 投稿日:2020-12-27T16:26:37+09:00
scopeの中にjoins等は書いて構わないと思う
主観もりもりです。賛否両論あると思いますが、いろんな意見もらえると嬉しいです。
背景
こんなコードを見かけた。
class Hoge scope :with_active_fuga, -> { merge(Fuga.active) }これだとscope単体で動かない。joins(:fuga)等を付けてあげないといけない。
でも、このjoins(:fuga)等は,
joins(:fuga).with_active_fuga
のように処理の中に付ける方がいいの?- それともscope外の呼び出し元にjoins(:fuga)等を付ける方がいいの?
と疑問に思ったので立ち止まって考えるに至った。
scopeに書いて構わないと判断した理由
- joins等を外出しすると使う人にjoinの種類を委ねるからパフォーマンスや動作的にscope設計者の意図しない使われ方をされるリスクがある。
- joins等を外出し前提で作ると、単純に動かないコードをそのまま残すことになってまずい。
joins(:fuga).joins(:fuga)
のように、scopeの組み合わせで同じ内容が被ってもSQLに影響が出ない。- includes、preload、eager_loadと共存することができるので、同時にキャッシュも行いたい場合も問題ない。
- 内部結合と外部結合どっちを使うか選びたいとかあるかもしれないけど、これはテーブルへの関連がない場合を含めるかどうかみたいな判断になって処理の役割が変わるから、それぞれのscopeを作成した方がよいと判断できる。
ちなみに
joins等が発生する絞り込みはscopeを使わないでクラスの中に処理を作るって人たちもいるから必ずしも「絞り込み = scope」とは限らない。
- 投稿日:2020-12-27T15:50:25+09:00
RailsチュートリアルでRuby3.0.0をインストールしたらbundle updateとbundle installができなかったときの解決法
あいさつ
知っている人はこんにちは!知らない人ははじめまして!
独学でプログラミングを極める変態中学生のAtieです!
今回は約3日間格闘し続けたエラーの解決法がわかったのでここに記録を残します
これでやっとRailsチュートリアルを進めることができます結論から言うと...
Rubyの最新版(3.0.0)をインストールしてしまって依存関係が解決できずに動かなかった!
ということのせいで動きませんでした
なのでRailsチュートリアルと同じバージョンのRuby2.6.3をインストールしてGlobalに2.6.3を設定することで動きました!開発環境
Ruby 3.0.0
Rails 6.0.3.4
Gemfile.lock は削除済み
Gemfileの内容(名前は「Gemfile」ですがRubyのコードで記載されていてわかりやすいようにわざと.rbの拡張子をつけています本番環境では.rbはついていません以下Gemfileを表示するときは.rbを拡張子としてつけています)Gemfile.rbsource 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } gem 'rails', '6.0.3' gem 'puma', '4.3.6' gem 'sass-rails', '5.1.0' gem 'webpacker', '4.0.7' gem 'turbolinks', '5.2.0' gem 'jbuilder', '2.9.1' gem 'bootsnap', '1.4.5', require: false group :development, :test do gem 'sqlite3', '1.4.1' gem 'byebug', '11.0.1', platforms: [:mri, :mingw, :x64_mingw] end group :development do gem 'web-console', '4.0.1' gem 'listen', '3.1.5' gem 'spring', '2.1.0' gem 'spring-watcher-listen', '2.0.1' end group :test do gem 'capybara', '3.28.0' gem 'selenium-webdriver', '3.142.4' gem 'webdrivers', '4.1.2' end # Windows ではタイムゾーン情報用の tzinfo-data gem を含める必要があります gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]エラーの内容
まずはbundle installを行うと以下のようなエラーが出てきました
$ bundle install Fetching gem metadata from https://rubygems.org/............ Fetching gem metadata from https://rubygems.org/. You have requested: listen = 3.1.5 The bundle currently has listen locked at 3.3.3. Try running `bundle update listen` If you are updating multiple gems in your Gemfile at once, try passing them all to `bundle update`エラーの内容は「バージョンがロックされているからbundle updateでアップデートしてね!」という内容です
$ bundle update Fetching gem metadata from https://rubygems.org/............ Fetching gem metadata from https://rubygems.org/. Resolving dependencies... Bundler found conflicting requirements for the Ruby version: In Gemfile: Ruby armv7l-linux-eabihf capybara (= 3.28.0) armv7l-linux-eabihf was resolved to 3.28.0, which depends on Ruby (>= 2.4.0) armv7l-linux-eabihf listen (= 3.1.5) armv7l-linux-eabihf was resolved to 3.1.5, which depends on Ruby (>= 2.2.3, ~> 2.2) puma (= 4.3.6) armv7l-linux-eabihf was resolved to 4.3.6, which depends on Ruby (>= 2.2) armv7l-linux-eabihf selenium-webdriver (= 3.142.4) armv7l-linux-eabihf was resolved to 3.142.4, which depends on Ruby (>= 2.3) armv7l-linux-eabihf内容は「競合が発生しているよ!」という内容です
ググってみると依存関係がどうのこうのだと...
あれ?ちょっと待てよRubyのバージョンってRailsチュートリアルのバージョンと一緒なのか?
という疑問が頭の中をよぎりました
そのときにぴーんと来ました!
なのでまずはRailsチュートリアルのRubyのバージョンを調べました
Railsチュートリアルの初期の状態のGemfileは以下のようになっていましたGemfile.rbsource 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '2.6.3' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '~> 6.0.3' # Use sqlite3 as the database for Active Record gem 'sqlite3', '~> 1.4' # Use Puma as the app server gem 'puma', '~> 3.11' # Use SCSS for stylesheets gem 'sass-rails', '~> 5' # Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker gem 'webpacker', '~> 4.0' # Turbolinks makes navigating your web application faster. # Read more: https://github.com/turbolinks/turbolinks gem 'turbolinks', '~> 5' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder gem 'jbuilder', '~> 2.7' # Use Redis adapter to run Action Cable in production # gem 'redis', '~> 4.0' # Use Active Model has_secure_password # gem 'bcrypt', '~> 3.1.7' # Use Active Storage variant # gem 'image_processing', '~> 1.2' # Reduces boot times through caching; required in config/boot.rb gem 'bootsnap', '>= 1.4.2', require: false group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a # debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] end group :development do # Access an interactive console on exception pages or by calling 'console' # anywhere in the code. gem 'web-console', '>= 3.3.0' gem 'listen', '>= 3.0.5', '< 3.2' # Spring speeds up development by keeping your application running in the # background. Read more: https://github.com/rails/spring gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' end group :test do # Adds support for Capybara system testing and selenium driver gem 'capybara', '>= 2.15' gem 'selenium-webdriver' # Easy installation and use of web drivers to run system tests with browsers gem 'webdrivers' end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]Railsチュートリアルのバージョンが2.6.3で自分の環境が3.0.0...
違いすぎるだろ!!それじゃ動くわけねぇよ!(3.0.0に至ってはメジャーアップデートでそこそこ大幅に改良されてたし... 詳しくはここへ)
そうですバージョンが大幅に違いました
あるあるです
特にLinuxを使っているとプログラムなどを動かそうとしてもライブラリなどのバージョンどうのこうのの依存関係のせいで動かないのがよくあります(自分が使っているFedoraなどは特にそう)はぁはぁはぁ...疲れた...やっと動く...(フラグじゃないよ\(^o^)/)
ということで動きました!
最後に
今回はかなり解決に時間がかかったエラーでした
今回のことを経験することができそのおかげで一回りはプログラマーとして成長できたと思います
エラーの原因を探したり解決するのもプログラマーの必須スキルであったりします
そして今回は依存関係などのバージョンの大切さを非常に学ぶことができました
もしこの記事が皆さんのエラー解決に少しでも役に立てたら光栄です
最後まで読んでいただきありがとうございました
ではまた次回の記事で!
AtieのTwitter
- 投稿日:2020-12-27T14:11:07+09:00
FactoryBotでの外部参照キーの記述方法
はじめに
Railsでテストコードを記述していたところ、必要事項を全て埋めても、外部参照したカラムの記述に関するエラーが出たので、FactoryBotでの外部参照キーの記述方法についてまとめました。
前提条件
下記のER図のようなUserモデルとArticleモデルにおいて、Articleモデルのuser_idが外部参照している場合を考えます。また、下記のようにUserのFactoryBotは定義済みとします。
user.rb# UserのFactoryBot FactoryBot.define do factory :user do nickname {Faker::Name.name} email {Faker::Internet.email} password {Faker::Internet.password} password_confirmation {password} last_name {"投稿"} first_name {"太郎"} end end実行するテストコード
article_spec.rb# Articleで実行するテストコード require 'rails_helper' describe Article do before do @article = FactoryBot.build(:article) end describe '記事新規投稿' do context '新規投稿がうまくいく時' do it '必要事項が全て存在すれば登録できる' do expect(@article).to be_valid end end context '新規投稿がうまくいかない時' do it 'titleが空だと登録できない' do @article.title = "" @article.valid? expect(@article.errors.full_messages).to include("Title can't be blank") end end end end上記のように、Articleモデルの単体テスト実行の場合を考えます。今回は、簡単のために、正常系として必要事項が全て記述されたとき、異常系としてtitleカラムが空の場合のみを考えます。
エラーになったコード
article.rb# ArticleのFactoryBot FactoryBot.define do factory :article do title {"あいうえお"} prefecture_id {Faker::Number.within(range: 1..10)} distance {Faker::Number.within(range: 10..500)} content {"あいうえおかきくけこ"} user_id {1} end end最初は、上記のarticle.rbでArticleのFactoryBotを定義し、article_spec.rbのテストを実行しましたが、it '必要事項が全て存在すれば登録できる'の部分で'User must exist'のエラーが生じました。これにより、article_rbのuser_id {1} という記述だけでは、外部参照出来ていないことがわかります。
解決策1
article_spec.rb# ArticleのFactoryBot FactoryBot.define do factory :article do title {"あいうえお"} prefecture_id {Faker::Number.within(range: 2..48)} distance {Faker::Number.within(range: 10..500)} content {"あいうえおかきくけこ"} user {FactoryBot.create(:user)} end enduser_id {1} としていた部分をUserのFactoryBotで生成したインスタンスに変更しました。これにより、articlesテーブルで外部参照可能になり、無事article_spec.rbのテストコードが正しく実行されました。
解決策2
article_spec.rb# ArticleのFactoryBot FactoryBot.define do factory :article do title {"あいうえお"} prefecture_id {Faker::Number.within(range: 2..48)} distance {Faker::Number.within(range: 10..500)} content {"あいうえおかきくけこ"} association :user end end次に、user_id {1} としていた部分をassociation :userという記述に変更しました。この記述でも、article_spec.rbのテストコードが正しく実行されました。
まとめ
FactoryBotで外部参照キーを記述する際は、user_id {1} などのように直接数字を記述するだけでは正しく外部参照できず、解決策①②のような記述が必要なことを学びました。
- 投稿日:2020-12-27T13:35:33+09:00
[Rails]ActionMailerでメール送信機能を作る(完全版)
はじめに
ある案件にお問い合わせメール送信機能の実装がありました。
自分的には、初めて自分で実装するので備忘録として、また、ひとつの記事だけではなかなか実装出来なかったので、この記事を見るだけで実装完了出来ると他の人にも役立つと思い書きます。実装手順
1.使用するモデルの作成
# 任意のモデル名、必要カラムを設定する $ rails g model inquiry name:string text:string $ rails db:migrate2.Action Mailerの作成
メール送信するために必要なApplicationMailerを継承するクラスは、generateコマンドから作成出来る。
$ rails g mailer inquiry3.Gmailで送信するための設定
Railsからメール送信出来るようにするには、2つやることがあります。
①パスワードの二段階認証の設定
②アプリパスワードの設定
↑はこちらから設定出来ます。
設定出来たら、下記を記述してください。config/enviroments/development.rb# trueだと、メールが送信されない時にエラーメッセージが表示される config.action_mailer.raise_delivery_errors = true # メイラーのテンプレートでフラグメントキャッシュを有効にするべきかどうかを指定する config.action_mailer.perform_caching = false # 配信方法を指定する config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { address: 'smtp.gmail.com', port: 587, domain: 'gmail.com', user_name: '<gmailのメールアドレス>', password: 'アプリパスワード', authentication: 'plain', enable_starttls_auto: true }4.メールの宛先や件名を指定する
app/mailer/inquiry_mailer.rbdef send_mail(inquiry) @inquiry = inquiry mail( from: 'from@example.com', # 送信元メールアドレス to: 'to@example.com', # 送信先メールアドレス subject: 'お問い合わせメール' # 件名 ) end※デフォルト値を設定する場合は、application_mailer.rbに記述する。
(この場合、app/mailer/inquiry_mailer.rbのfrom: 〇〇の記述は必要なし。)app/mailer/application_mailer.rbclass ApplicationMailer < ActionMailer::Base default from: 'from@example.com' layout 'mailer' end5.メール本文のレイアウトを作成
メール本文のレイアウトを作成するためは命名規則にしたがってerbファイルを作成します。
(app/views/メイラー名_mailer/メイラークラスのメソッド名.text.erb)app/views/inquiry_mailer/send_mail.text.erb================================== <%= @inquiry.name %> 様 から問い合わせがありました。 ================================== <お問い合わせ内容> <%= @inquiry.text %>6.メールをプレビューで確認
ActionMailer::Previewを継承したクラスは、generateコマンドで生成したInquiryMailerPreviewクラスが存在するので、そちらに下記を記述して確認する。
spec/mailers/previews/inquiry_preview.rb# Preview all emails at http://localhost:3000/rails/mailers/inquiry class InquiryPreview < ActionMailer::Preview def inquiry inquiry = Inquiry.new(name: "三原 蓮之介", text: "問い合わせメッセージ") InquiryMailer.send_mail(inquiry) end private def inquiry_params params.require(:inquiry).permit(:name, :text) end end確認方法は、サーバーを起動し、http://localhost:3000/rails/mailers/inquiry に接続。
※接続先はファイルの一番上に書いてあります。7.実際にメールを送信する
コントローラーに送信する処理を記述する。
そうすれば、該当のアクションを実行された時にメールが送信されます。app/controllers/inquiries_controller.rbclass InquiriesController < ApplicationController 〜中略〜 def create @inquiry = Inquiry.new(inquiry_params) if @inquiry.save # こちらのコマンドを実行することでメールが送信される InquiryMailer.send_mail(@inquiry).deliver redirect_to inquiries_path, flash: {success: '送信が完了しました'} else flash.now[:alert] = '必須項目を入力、もしくは入力内容に間違いがあります' render :index end end private def inquiry_params params.require(:inquiry).permit(:name, :text) end endコンソールで確認してみても良いです○
$ rails c irb(main):001:0> inquiry = Inquiry.new(name: "サンプル太郎", text: "問い合わせメール") irb(main):002:0> InquiryMailer.send_mail(inquiry).deliver_now終わりに
意外と簡単に実装出来ますね。
個人的にGmailの設定をするってことに気付くのに少し遅れて時間がかかりましたが、そこだけしっかり設定すればつまづくことも少ないと思います!
よく使う機能だと思うので、実装できるようにしておきましょう!!参考
- 投稿日:2020-12-27T13:14:37+09:00
WebPacker 3.x -> 5.x
はじめに
※この文章はベータ版です。
既存のプロジェクトで Rails5.2 + WebPacker 3.5.5 -> Rails6.1 + WebPacker5.2.1
したので、手順etcをメモしておきます。Rails5.2 -> Rails6.1
プロジェクトのrails & Webpacker gem を更新する
プロジェクトのルート・パスに移動後、gems.rb(Gemfile)を編集し、
バンドルされたgemを更新します。% vim gems.rb gem 'rails', '~> 6.1.0' gem 'webpacker' % bundle update表示されるメッセージでgemの依存関係を確認し、依存関係に問題がなくなるようにgems.rb(Gemfile) を編集し、'bundle update' を実行します。
この作業をエラーが出なくなるまで繰り返します。アップデートタスクを実行する
% bundle exec rails app:updateプロジェクトをGit etcでリポジトリでバージョン管理していない場合には
バックアップをとってから実行します。実行により、いくつかのファイルのコンフリクトが指摘され、上書きするかどうか
訊いてきますが、全て、上書きします。上書きされたファイルとリポジトリ上(or バックアップ)にある対応するファイルの
差分をチェックし、上書きされたファイルに必要な記述を復元します。Webpacker 3.5.5 -> 5.2.1
% bundle exec rails webpacker:install実行により、いくつかのファイルのコンフリクトが指摘され、上書きするかどうか
訊いてきますが、全て、上書きします。上書きされたファイルとリポジトリ上(or バックアップ)にある対応するファイルの
差分をチェックし、上書きされたファイルに必要な記述を復元します。Vue.js まわりのアップデート (オプション)
% bundle exec rails webpacker:install:vue他のフレームワークを利用している場合には、対応した
タスクがあれば、それを実行します、対応したタスクがない
場合には自前で更新します。babel-loader の設定変更 (オプション)
Vue.jsでHTMLテンプレートのコンパイルをブラウザでの実行に行う場合には
config/webpack/environment.js
に次の設定を追加します。// Vue.js フル版(Compiler入り) environment.config.resolve.alias = { 'vue$': 'vue/dist/vue.esm.js' }この設定がないときは、コンパイラなしの
vue/dist/vue.runtime.esm.js
が
読み込まれます。
(Vue.jsでHTMLテンプレートの実行時コンパイルを行なっている場合、エラーに
なります。)rails-erb-loaderのアップデート (オプション)
% bundle exec rails webpacker:install:erbnode_modulesの更新
% yarn install表示されるメッセージで NPM の依存関係を確認し、必要な NPM があれば
yarn add
でインストールしてから、再度、yarn install
を実行します。
この手順をエラーが出なくなるまで繰り返します。.babelrcの削除
Webpackerの3.xでは必要でしたが、Webpacker4.x 以降では、babel.cofig.js、
postcss.config.js、.postcssrc.yml に置き換わっているので、削除します。バンドル
% bin/webpack動作確認
% bundle exec rails srails-ujs -> @rails/ujs (オプション)
% yarn add @rails/ujsSprocketを利用している場合は、
app/assets/javascripts/application.js
の
rails-ujs
を@rails/ujs
に変更します。//= require @rails/ujsWebpackerを利用しているorする場合は、'app/javascript/packs/application.js'
に、次の2行を追加します。import Rails from '@rails/ujs'; Rails.start();Webpackerでの管理に新規に移行する場合には、erbにある
javascript_include_tag
を
'application'javascript_pack_tag 'application'
に変更します。WebPackerの 設定変更 (オプション)
SplitChunkの有効化 (オプション)
config/webpack/environment.js
に次の設定を追加します。environment.splitChunks()erbにある
javascriot_pack_tag
をjavascript_packs_with_chunks_tag
に変更します。babel-loaderの設定変更
config/webpack/environment.js
に次の設定を追加します。environment.loaders.delete('nodeModules')Webpacker4.x以降では、デフォルトでは、
node_modules
ディレクトリにあるファイルが
babel-loader経由でのトランパイルの対象になっています。この追加により、WebPacker3と同様にWebpacker4以降でもbabel-loaderが'node_modules'
ディレクトリを無視する挙動になります。Webpacker4以降でブラウザで動作確認を行なった際に、node_modules下にあるファイルで
エラーが発生している場合、この設定変更を試すことをオススメします。
node_modules
ディレクトリにあるファイルがbabel-loader経由でのトランパイルの
対象になっていることにより、思わぬ変換が行われていることが原因である可能性が
あります。例えば、
node_modules
ディレクトリにあるバンドル対象のファイル内に
module.exports =
の記述がある場合、WebPacker4.x以降のデフォルト設定では、Cannot assign to read only property 'exports' of objectエラーが発生することがあります。
- 投稿日:2020-12-27T13:06:34+09:00
signup後の画面で、profile,logoutを表示されない問題を解決した。
発生した問題
ブログの完成に向けて、ログインシステムを構築する過程でエラーが発生した。
http://localhost:3000/users/new
において、Signupを実行後、UserのProfile画面にリダイレクトはできただが、ページ上部にProfileとLogoutが表示されず、代わりにSignUpとLoginが表示されてしまう。
当初考えられた原因
(1)app/helpers/sessions_helper.rbで定義し、layouts/application.html.erbに記述した”logged_in?”が有効でない。
・・・しかし、コードの記述自体に誤りは見られず、条件分岐もlogged_in?メソッド(※)も発火している。logged_in?メソッドを格納しているapp/helpers/sessions_helper.rbmodule SessionsHelper def current_user @current_user ||= User.find_by(id: session[:user_id]) end def logged_in? current_user.present? end end(2)そもそも、”rails g controller sessions new”実行時に、sessions_helper.rbが生成されなかった。
・・・これは「- CSS、JavaScript、Helperのファイルをrails g コマンドで自動生成しない設定を記述して、これらの余分なファイルができない」ようにするため、”config/application.rb”に下記の記述をしたことで、意図的に自動生成せず、代わりに自分でsessions_helper.rbファイルを作成した。config/application.rbrequire_relative 'boot' require 'rails/all' Bundler.require(*Rails.groups) module HogehogeAppli class Application < Rails::Application #省略 config.generators do |g| g.assets false g.helper false end end endおそらく、上記(2)が原因で上手くlogged_in?が発火していないと予想していた。しかし、
http://localhost:3000/sessions/new
(Loginページ)でログインした場合は、正常にProfileとLogoutが表示されるため、なぜlogged_in?が発火しないのかが分からない。
SignUp後に、ProfileとLogoutを表示させるためにはどうしたらよいのか、悩んでしまった。解決法
logged_in?メソッドは何の問題も発火しているため、問題点は違うところにあった。
そもそもログイン状態とは、ユーザーのブラウザ内のcookiesに暗号化されたユーザーIDを付与することをログインといい、それが保持され続けていることをログイン状態という。(ブラウザとサーバ間で同一のユーザIDが突合し合えている状態)をいい、その仕組みはcreate時にsessionメソッドを使ってcookiesにユーザIDを持たせることでログイン状態が実現できる。
Login(=ドメイン名/sessions/new)後には正常にProfileとLogoutを表示させられて、Signup(=ドメイン名/users/new)では表示されず代わりにSignupとLoginが表示されてしまう…。この違いについて焦点を当てることが解決につながると考え、users_controller.rb内のcreateアクションでログイン状態を作れていないことが判った。
app/controllers/users_controller.rbdef create @user = User.new(user_params) if @user.save #下記1行を追記し、ユーザーのブラウザ内のcookiesに暗号化されたユーザーIDが自動で生成されるようにした。 session[:user_id] = @user.id redirect_to user_path(@user.id) else render :new end end
- 投稿日:2020-12-27T10:58:57+09:00
Rubyで日付のデータを取得する方法
Dateクラスに対しクラスメソッドを使用
Rubyでは日付を扱うクラスとしてDateクラスが用意されており、これを使用することにより
うるう年やひと月ごとの日数、曜日などの管理
といった単なる数字のみでは正確に算出することが困難なデータを簡単に取得することが可能となる。
日付以外にも時間を管理するクラスや、日付と時間の両方を扱うクラスが存在する。日付や時間に関する主なクラス
クラス名 管理可能なデータ Dateクラス 日付 Timeクラス 時間 Datetimeクラス 日付と時刻の双方 Dateクラスを使う前準備(require)
Dateクラスを使用する際には、Rubyのコード上に
"Date"ライブラリーを呼び込む
必要がある。
その役割を果たすのがrequireメソッド
であり、これにより外部ファイルを参照して、そこで定義されているクラスを取得することが可能となる。
※Railsのアプリケーションの場合はクラスはどのファイルにおいても参照できる為、require "~"
の記述は不要・具体的な使用方法
require "date" #日付に関わるライブラリ"date"を取り込む : :Dateクラスのインスタンス(オブジェクト)を取得する主な方法
- todayメソッド(今日の日付を自動で算出してDateオブジェクトを作成)
require "date" today = Date.today #今日の日付を自動で算出してDateオブジェクトを作成
- parseメソッド(引数で渡した文字列をDateオブジェクトに変換して作成)
require "date" today_str = 2020-12-30 Date.parse(today_str) #2020年12月30日のDateオブジェクトが作成される
- newメソッドによる作成(引数で渡した整数を元にDateオプジェクトを作成)
require "date" today = Date.new(2020, 12, 30) #2020年12月30日のDateオブジェクトが作成される作成したDateオブジェクトから年や月などを取得する
上記の方法で作成したDateオブジェクトから特定の情報を取得する場合は、以下のようなコードを使用する。
require "date" today = Date.today today.year # 作成したDateオブジェクトから年を取得 today.mon # 作成したDateオブジェクトから月を取得 today.mday # 作成したDateオブジェクトから日を取得 today.wday # 作成したDateオブジェクトから曜日を数字として取得記載内容に間違い等ございましたらご指摘頂けると嬉しいです。
ご連絡お待ちしております。
- 投稿日:2020-12-27T10:12:37+09:00
Rails5.2でMaterial Design for Bootstrapを使う
何をしたか
Railsの課題を実施しています。装飾に関しては、
Material Design for Bootstrap
を使用することになっていたのですが、WebpackerではないJS系のライブラリの導入が久しぶりで...。
だいぶ忘れていたので手順をメモします。なお、実行環境は以下の通りです。
- Rails 5.2.3
- Ruby 2.6.4
Material Design for Bootstrapとは?
Material Design for Bootstrap(以下、MDB)は、Googleのマテリアルデザインに準拠した、Bootstrapのフレームワークです。
Githubの公式レポジトリに、色々便利なリンクがありました
導入
MDBは5.0系からは、jQueryを前提としたものではなくなっています。先にもあげたこちらのダウンロードリンクからは、さまざまなJSフレームワークに対応したものが入手可能です。
今回は、MDBの
4.1.1
を利用するので、jQuery
の導入から始めます。jQuery
Rails5.1からは、RailsにjQueryはデフォルトで入っていないので、別途導入する必要があります。
Gemfileに以下のように記載し、、、
Gemfilegem 'jquery-rails'
bundle install
します。application.jsには以下のように追記しましょう。(
require turbolinks
は取ってしまっています)assets/javascripts/application.js//= require jquery # 追記 //= require rails-ujs # 追記 //= require activestorage //= require_tree .MDB本体の導入
MDB本体はnpmでダウンロードします。gemもあるのですが、うまく動かない、とのことでカリキュラムではnpmが推奨されていました。サイトを見る限り、少し古そうですね。。。
$ npm install bootstrap-material-design@4.1.1必要なファイル類の読み込み
すみません、ここからはお手本コードの写経であまり深く整理できていないのですが、MDBを動かすために必要なcssファイルを読み込みます。
assets/stylesheets/application.scss@import 'bootstrap-material-design/dist/css/bootstrap-material-design';ここまでで、自分の環境ではCSSと基本的なJSに関するMDBは動作しました。
おそらく、tooltipなど特定のものに関しては、依存するライブラリpopper.js
なども必要になるはずとは思います^^。
まだ、使用する場面はアプリ内にはないので、できたら追記しようかとは思いますが、ここまでで一旦記事はリリースしようと思います。なにか過不足などありましたら、ご指摘いただければ嬉しいです。
- 投稿日:2020-12-27T09:55:27+09:00
日時の文字列を、Time.zone.parseしてRailsに認識させる方法
Time.zoneが一致しなくて検索できなかった問題
筆者がRailsのアプリを開発している時に、
日付を一致させる時にひと悶着あったので、備忘録として残しておきます。今回使用する例
productsテーブル
id date (datetime型) 1 2020-11-01 15:00:00 2 2020-11-02 00:00:00 DBの時刻は
UTC
とします。問題
下記の例が
true
orfalse
を返す理由が説明できるでしょうか?
RailsアプリのTime.zoneは次の状態だとします。[*] pry(#<ProductsController>)> Time.zone => #<ActiveSupport::TimeZone:0x000055cc45b31408 @name="Tokyo", @tzinfo=#<TZInfo::DataTimezone: Asia/Tokyo>, @utc_offset=nil>例題
[1] pry(#<ProductsController>)> Product.find(1).date == "2020-11-01 15:00:00" => true [2] pry(#<ProductsController>)> Product.find(1).date == "2020-11-02 00:00:00" => false [3] pry(#<ProductsController>)> Product.find(1).date == Time.zone.parse("2020-11-01 15:00:00") => false [4] pry(#<ProductsController>)> Product.find(1).date == Time.zone.parse("2020-11-02 00:00:00") => true [5] pry(#<ProductsController>)> Product.find(2).date == "2020-11-01 15:00:00" => false [6] pry(#<ProductsController>)> Product.find(2).date == "2020-11-02 00:00:00" => true [7] pry(#<ProductsController>)> Product.find(1).date == Time.zone.parse("2020-11-01 15:00:00") => false [8] pry(#<ProductsController>)> Product.find(1).date == Time.zone.parse("2020-11-02 00:00:00") => false [9] pry(#<ProductsController>)> Product.find(1).date == Time.zone.parse("2020-11-02 09:00:00") => true回答
[1] pry(#<ProductsController>)> Product.find(1).date == "2020-11-01 15:00:00" => true # 文字列で検索した場合、DBのレコードと一致するものを検索します。 # つまり、2020-11-01 15:00:00という値が一致するのでtrueとなります。 [2] pry(#<ProductsController>)> Product.find(1).date == "2020-11-02 00:00:00" => false # 純粋な文字列を比較してるので、 # 2020-11-01 15:00:00 == 2020-11-02 00:00:00はfalseとなります。 [3] pry(#<ProductsController>)> Product.find(1).date == Time.zone.parse("2020-11-01 15:00:00") => false # 今回のRailsアプリのTime.zoneはTokyoでした。 # Time.zone.parseとは、文字通りアプリのタイムゾーンに合わせて変換することです。 # UTCとTokyoの時間は9時間ずれてる(Tokyoが遅れてる) # DBにsaveする時、2020-11-02 00:00:00 ➡️ 2020-11-01 15:00:00に変換されます。 # RailsがDBからレコードを取り出す時、+9時間して返します。 [4] pry(#<ProductsController>)> Product.find(1).date == Time.zone.parse("2020-11-02 00:00:00") => true # 上記で説明したとおり、Railsのタイムゾーンと同じ値を検索&parseしたので、trueを返します。 [5] pry(#<ProductsController>)> Product.find(2).date == "2020-11-01 15:00:00" => false # 文字列で検索した場合、DBと一致する値を返すため [6] pry(#<ProductsController>)> Product.find(2).date == "2020-11-02 00:00:00" => true # 文字列で検索した場合、DBと一致する値を返すため [7] pry(#<ProductsController>)> Product.find(1).date == Time.zone.parse("2020-11-01 15:00:00") => false # parseした後はDBの値 - 9 されるためfalse # parseした後は、2020-11-01 06:00:00になる [8] pry(#<ProductsController>)> Product.find(1).date == Time.zone.parse("2020-11-02 00:00:00") => false # parseした後はDBの値 - 9 されるためfalse # parseした後は、2020-11-01 15:00:00になる [9] pry(#<ProductsController>)> Product.find(1).date == Time.zone.parse("2020-11-02 09:00:00") => true # parseした後は、2020-11-02 00:00:00になるのでtrue言いたかったこと
今回のRailsのTime.zoneはTokyoなので、
バックエンドのデータに-9時間してsaveしてる。それに合わせて、Time.zoneをTokyoにparseしたら、
欲しかった情報を取得できました!参考
ようやく:こうしきよめ
https://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html助けられたteratail
https://teratail.com/questions/148819RubyとRailsにおけるTime, Date, DateTime, TimeWithZoneの違い
https://qiita.com/jnchito/items/cae89ee43c30f5d6fa2cおまけ
ふと疑問に思ったので、
ransackのコード見たら、Time.zone.parseしてました。def cast_to_time(val) if val.is_a?(Array) Time.zone.local(*val) rescue nil else unless val.acts_like?(:time) val = val.is_a?(String) ? Time.zone.parse(val) : val.to_time rescue val end val.in_time_zone rescue nil end end
- 投稿日:2020-12-27T09:29:33+09:00
[個人開発]経験を共有するWebアプリ作ってみた!
新しいwebアプリ開発しました。「Elder」という人生経験を募集、公開、評価できるサイトです。今回は作ったwebアプリの紹介、サービスのネタの考え方、herokuの無料プランでスリープにさせない方法など書いていきます。今回は前回みたいなヘマしないように頑張ります(^^♪
紹介
↑トップページ
人生経験を共有するコミュニティサイトです。
人生経験の募集、エッセイ、一言だけ投稿、などができます。
現在技術系の記事ばかりですが、分野は問いません。募集中のところはスライドショーになっていて動きます。一か所でも動くところがあると凝ったサイト感が出ます。
イメージカラーは紫を選びました。
使ってみた感想として、いろんな色とは合わないけどその代わりたくさん使っても不自然になりにくいと感じました。
普通、同じ色ばっかり使うとそれはそれで変な感じになるんですがね。なぜつくったか
人生経験ってなかなか聞く機会も話す機会もなく、もっと共有したほうがいいと思ったから。
今回使った技術
gemrails6 ruby2.7 postgresql heroku free Logo Garden gem 'ridgepole' gem 'slim-rails' gem 'html2slim' gem 'pry-rails' gem "devise" gem 'devise-i18n' gem 'devise-i18n-views' gem 'rails-i18n' gem 'carrierwave' gem "kaminari" gem 'ransack'Logo Gardenとはロゴ制作サイトです。地味に今回はじめてちゃんとしたロゴを作りました。
ちょい粗いですがこれが完全無料で作れるんですよ。すごいなー(感心)。もっと凝ったものも作れたんですけどシンプルが一番かなーと。
https://www.logogarden.com/あと、bootstrapは使ってません。
サービスのネタの決め方(個人開発)
なんでサービスを作りたいのか。
- サービスを届けたい人は本当に喜ぶ?
- 本当にそのアプリで問題解決することができる?。
- 有料でも使いたいか(無料で出すとしても)
- お金を扱わない
- 初期費用がいらない
- 個人で管理できる
- ほぼコンテンツがいらない or 自分でコンテンツが作れる
- 幸福になりたいのだったら、人を喜ばすことを勉強したまえ。
こんなもんだと思います。まだ成功するかわからないのにこんなこと書くのはあれですが間違ったことも言ってないと思います。
一時的に当たるネタというのはこれのどれかが抜けていると思います。あと、一応保険かけときます。※個人の意見です
herokuの無料プランで運用
herokuの無料プランで一番きついのは、30分ごとのスリープだと思います。
これがなかったら無料プランで全然いいという方も多いと思います。僕がやったのはのはHeroku Schedulerです。
10分ごとに自動でサーバーになにかさせるというものです。heroku addons:create scheduler:standard heroku addons:open schedulerブラウザが開いたらadd jobをクリックして
Run Commandを$ curl サイトのURLScheduleはEvery 10 minutesにして保存。
これでスリープしなくなります。ただバグがあったりするらしいので注意してくださいねー。
振り返り
よかったこと
- 完全無料で作れた(人件費抜き)
- ロゴも作れた
- railsコードの再利用ができた
悪かったこと
- 途中でなんかいもあきらめそうになった
個人でやるとモチベーション管理が一番むずいです...
なにあともあれ使ってくみてださいね(^^♪
- 投稿日:2020-12-27T09:29:33+09:00
人生経験を共有するコミュニティサイト作ってみた! & サービスの考え方
新しいwebアプリ開発しました。「Elder」という人生経験を募集、公開、評価できるサイトです。今回は作ったwebアプリの紹介、サービスのネタの考え方、herokuの無料プランでスリープにさせない方法など書いていきます。今回は前回みたいなヘマしないように頑張ります(^^♪
紹介
↑トップページ
人生経験を共有するコミュニティサイトです。
人生経験の募集、エッセイ、一言だけ投稿、などができます。
現在技術系の記事ばかりですが、分野は問いません。今回使った技術
gemrails6 ruby2.7 postgresql heroku free Logo Garden gem 'ridgepole' gem 'slim-rails' gem 'html2slim' gem 'pry-rails' gem "devise" gem 'devise-i18n' gem 'devise-i18n-views' gem 'rails-i18n' gem 'carrierwave' gem "kaminari" gem 'ransack'Logo Gardenとはロゴ制作サイトです。地味に今回はじめてちゃんとしたロゴを作りました。
ちょい粗いですがこれが完全無料で作れるんですよ。すごいなー(感心)。もっと凝ったものも作れたんですけどシンプルが一番かなーと。
https://www.logogarden.com/サービスのネタの決め方(個人開発)
なんでサービスを作りたいのか。
- サービスを届けたい人は本当に喜ぶ?
- 本当にそのアプリで問題解決することができる?。
- 有料でも使いたいか(無料で出すとしても)
- お金を扱わない
- 初期費用がいらない
- 個人で管理できる
- ほぼコンテンツがいらない or 自分でコンテンツが作れる
- 幸福になりたいのだったら、人を喜ばすことを勉強したまえ。
こんなもんだと思います。まだ成功するかわからないのにこんなこと書くのはあれですが間違ったことも言ってないと思います。
一時的に当たるネタというのはこれのどれかが抜けていると思います。あと、一応保険かけときます。※個人の意見です
herokuの無料プランで運用
herokuの無料プランで一番きついのは、30分ごとのスリープだと思います。
これがなかったら無料プランで全然いいという方も多いと思います。僕がやったのはのはHeroku Schedulerです。
10分ごとに自動でサーバーになにかさせるというものです。heroku addons:create scheduler:standard heroku addons:open schedulerブラウザが開いたらadd jobをクリックして
Run Commandを$ curl サイトのURLScheduleはEvery 10 minutesにして保存。
これでスリープしなくなります。ただバグがあったりするらしいので注意してくださいねー。
振り返り
よかったこと
- 完全無料で作れた(人件費抜き)
- ロゴも作れた
- railsコードの再利用ができた
悪かったこと
- 途中でなんかいもあきらめそうになった
個人でやるとモチベーション管理が一番むずいです...
なにあともあれ使ってくみてださいね(^^♪
- 投稿日:2020-12-27T09:29:33+09:00
[個人開発]人生経験を共有するコミュニティサイト作ってみた!
新しいwebアプリ開発しました。「Elder」という人生経験を募集、公開、評価できるサイトです。今回は作ったwebアプリの紹介、サービスのネタの考え方、herokuの無料プランでスリープにさせない方法など書いていきます。今回は前回みたいなヘマしないように頑張ります(^^♪
紹介
↑トップページ
人生経験を共有するコミュニティサイトです。
人生経験の募集、エッセイ、一言だけ投稿、などができます。
現在技術系の記事ばかりですが、分野は問いません。募集中のところはスライドショーになっていて動きます。一か所でも動くところがあると凝ったサイト感が出ます。
イメージカラーは紫を選びました。
使ってみた感想として、いろんな色とは合わないけどその代わりたくさん使っても不自然になりにくいと感じました。
普通、同じ色ばっかり使うとそれはそれで変な感じになるんですがね。なぜつくったか
人生経験ってなかなか聞く機会も話す機会もなく、もっと共有したほうがいいと思ったから。
今回使った技術
gemrails6 ruby2.7 postgresql heroku free Logo Garden gem 'ridgepole' gem 'slim-rails' gem 'html2slim' gem 'pry-rails' gem "devise" gem 'devise-i18n' gem 'devise-i18n-views' gem 'rails-i18n' gem 'carrierwave' gem "kaminari" gem 'ransack'Logo Gardenとはロゴ制作サイトです。地味に今回はじめてちゃんとしたロゴを作りました。
ちょい粗いですがこれが完全無料で作れるんですよ。すごいなー(感心)。もっと凝ったものも作れたんですけどシンプルが一番かなーと。
https://www.logogarden.com/あと、bootstrapは使ってません。
サービスのネタの決め方(個人開発)
なんでサービスを作りたいのか。
- サービスを届けたい人は本当に喜ぶ?
- 本当にそのアプリで問題解決することができる?。
- 有料でも使いたいか(無料で出すとしても)
- お金を扱わない
- 初期費用がいらない
- 個人で管理できる
- ほぼコンテンツがいらない or 自分でコンテンツが作れる
- 幸福になりたいのだったら、人を喜ばすことを勉強したまえ。
こんなもんだと思います。まだ成功するかわからないのにこんなこと書くのはあれですが間違ったことも言ってないと思います。
一時的に当たるネタというのはこれのどれかが抜けていると思います。あと、一応保険かけときます。※個人の意見です
herokuの無料プランで運用
herokuの無料プランで一番きついのは、30分ごとのスリープだと思います。
これがなかったら無料プランで全然いいという方も多いと思います。僕がやったのはのはHeroku Schedulerです。
10分ごとに自動でサーバーになにかさせるというものです。heroku addons:create scheduler:standard heroku addons:open schedulerブラウザが開いたらadd jobをクリックして
Run Commandを$ curl サイトのURLScheduleはEvery 10 minutesにして保存。
これでスリープしなくなります。ただバグがあったりするらしいので注意してくださいねー。
振り返り
よかったこと
- 完全無料で作れた(人件費抜き)
- ロゴも作れた
- railsコードの再利用ができた
悪かったこと
- 途中でなんかいもあきらめそうになった
個人でやるとモチベーション管理が一番むずいです...
なにあともあれ使ってくみてださいね(^^♪
- 投稿日:2020-12-27T09:14:44+09:00
Rails開発の変遷2020
概要
- webサイトの作成はRailsを使ってきた。
- 今年はHTML、CSSを学び、UIを作るようになった。
- vue/nuxtを学んでから、開発の仕方が変わった
Webpack
- Rails本来のview作成はerb形式。slimで書くのが普通らしい
- Rails 5.2からWebpackをサポートし、vueを使ってHTMLを作成できるようになった。知らんけど。
- viewsにはjavascriptを参照する記述のみ。実際の中身はjavascriptディレクトリに作成する
やり方
- Qiitaにわかりやすいチュートリアルがあるので、それを参考にするのが良い。
- vue側はvue CLIを使ったほうが開発が捗る。vue CLIである程度完成させてから、railsのjavascriptにコピペするような方法で作成した。
欠点
- 何も設定せずに開発すると、vueを更新した後にrails sを立ち上げなおす必要がある。
- vue-routerを使っていると、ホットリロードした時にルーティングエラーがでてしまう。
サーバー側とフロント側を分離して開発
- railsはサーバーサイドのみに特化し、フロントはvueで作成する。
- サーバーとフロントの切り分け設計ができるようになった。(APIを意識する)
- エラーを見つけやすくなり、開発効率アップした
- DBはfirebaseに移行(それまではpostgreSQLを使っていた)
今年使い方を学んだgem
Rails
active admin
- 管理者画面を作成できる
- Railsではデータを作成する時に、コンソールやseedでデータ作成できるが、active adminを使えば画面上で編集できる
- UIはhtmlテンプレートではない形式で作成されている。そのため、管理者画面にマップとか入れたいと思っても実際無理。
- firebase storageを使うようになってから使わなくなった。
devise
- Railsでログイン機能を作るにあたってのデファクトスタンダード
- session云々やpassword暗号化を良しなに実装してくれる(便利過ぎてsession云々を忘れるくらい)
- バックとフロントを切り分けて開発するようになってから、ヘルパーメソッドを使えなくなった。
- firebase authを使うようになって不要になった。
active record
- Railsで画像をアップしたりする時に使うgem
- erbでviewを作成するなら、恩恵を存分に受けられる。(controllerだけでURLから画像を取得することもできる)
- active recordは本来の使い方をすれば便利だろうと思う反面、本来の使い方以外がしにくい(どこで何がどう動いているのか把握しにくい)
- 画像ファイルのアップロードなら、carrierwaveのほうがどこで何を処理しているのかがわかりやすい
miniMagic
- Railsで画像を加工・編集するためのgem
- 参考文献が多くないため、最低限の使い方しかわからない
- 処理に時間がかかる。LINE Messangerで使おうとしたが、処理スピードが遅く、まともに使えなかった。
- 画像編集はjavascriptで行い、firestorageに画像ファイルを保存するような設計にしたため、サーバー側で画像を作成してフロント側に送るようなことがなくなった。
今後について
- RailsでAPIモードで開発するなら、Railsである必要性はないかな、、、
- node.jsでのexpressかpythonでのfastAPIを検討中
- とはいえ、rubyは好きな言語であるのでrubyとrailsを使うメリットがあるなら、使っていきたい。
- railsの活用法があれば教えてください。d
- 投稿日:2020-12-27T09:13:25+09:00
パラメーターが配列の場合、ストパラのparams.permitに含める方法
パラメーターが配列の場合、ストパラのparams.permitに含める方法
状況
1つのusersテーブルに対して、同時に複数のレコードを作成するために下記のようなパラメーターを送りました。
Parameters: {"users"=>[{"name"}=>{"satoshi"}, {"name"}=>{"yuta"}]}受けるストパラは下記
private def users_params params.require(:users).permit( :id, :name ) end発生したエラー
requireした後にpermitメソッドを使うと、
「permit?そんなメソッドは知らんよ」と言われてしまいました。[1] pry(#<UsersController>)> params.require(:users).permit NoMethodError: undefined method `permit' for #<Array:0x00007f2024a3ee40>from (pry):62:in `users_params'(binding.pryの結果を出力しています)
理由
params.require(:publisheds)はArrayクラスだから、permitメソッドが使えない。
[2] pry(#<UsersController>)> params.require(:users).class => Array [3] pry(#<UsersController>)> params.require(:users).respond_to?("permit") => false情報:配列番号を指定するとpermitが通る
[4] pry(#<UsersController>)> params.require(:users)[0].respond_to?("permit") => true [5] pry(#<UsersController>)> params.require(:users)[0].permit(:name) => <ActionController::Parameters {"name"=>"satoshi"} permitted: true>配列(Array)で来てるなら、1個ずつ取り出せばいいんじゃね?って思いました。
解決法
mapで回して、配列をばらしてpermitして返す
private def users_params params.require(:users).map do |user| user.permit( :id, :name ) end endmapが使えた理由
ブロックを評価して配列を戻り値として持つ=rubyの仕様は、最後に評価した値を暗黙的に返す(returnする)から。
eachが使えないのはなぜ?
配列を回して引数を取るけど、その中でpermitをしても値を返さないから?
permitメソッド自体が、値の変更(代入)ではなく、許可だから少し挙動が違う?細かな違いが難しい。。。
rubyマスターの方がいらっしゃいましたら質問させてほしいです。参考:るりまのリンク
eachの仕様
https://docs.ruby-lang.org/ja/latest/method/Array/i/each.htmlmapの仕様
https://docs.ruby-lang.org/ja/latest/class/Array.html#I_COLLECT
- 投稿日:2020-12-27T04:59:29+09:00
scopeメソッドの主な機能
scopeメソッド、名前から機能を推察するのがむずかしいだけでなく出てくる場面もいろいろでややこしいので整理した。
1 scope(name, body, &block)
特定の条件を持ったオブジェクトをデータベースへ問い合わせるためのクラスメソッドを生成する。モデルで呼び出す。コントローラのアクションの記述をシンプルにしたいときに使える。
shirt.rbclass Shirt < ActiveRecord::Base scope :red, -> { where(color: 'red') } end↓同義
shirt.rbclass Shirt < ActiveRecord::Base def self.red where(color: 'red') end end第一引数にメソッド名を表すシンボル、第二引数に検索条件を示すブロック{ where.. }を引数として受けたラムダ式“->“が返すProcオブジェクトが渡されている。
->はlambdaに代替しても同じ。2 scope(*args)
ルーティングに関する処理。リソースルーティングをカスタマイズしたいときに使える。routes.rbで呼び出す。いろいろな用法、記法があるので一部抜粋。
2-1 パスにプレフィックスをつける
routes.rbscope path: "/admin" do resources :posts end/admin/postsからpostsコントローラへのルーティングが可能になる。
2-2 名前付きルーティングヘルパーにプレフィックスをつける
routes.rbscope as: "secret" do resources :posts endsecret_posts_path, new_secret_posts_pathなどのヘルパーが生成され、それぞれ/posts, /posts/newに割り当てられる。
2-3 ある名前空間のコントローラへのルーティング
routes.rbscope module: "admin" do resources :posts end/postsからAdminという名前空間の中にあるコントローラ(Admin::PostsController)へのルーティングが可能になる。
3 フォームヘルパーform_withにおけるオプション “:scope”
inputフィールド名にプレフィックスをつける
new.html.erb<%= form_with scope: :post, url: posts_path do |form| %> <%= form.text_field :title %> <% end %> # => <form action="/posts" method="post" data-remote="true"> <input type="text" name="post[title]"> </form>:scopeオプションで渡されるpostが、text.fieldに渡された属性名titleをネストした形のフィールド名になる。これによりコントローラでparams[:post][:title]にアクセスできるようになる。
:modelオプションでインスタンスを渡した場合、Railsがスコープを推察しプレフィックスをつける。
スコープ情報がない場合、フィールド名は“title”となり、コントローラでアクセスできるのはparams[:title]になる。まとめ
- 特定の条件を持ったオブジェクトをデータベースへ問い合わせるためのクラスメソッドを生成する
- リソースルーティングをカスタマイズする
- (オプション)inputフィールド名にプレフィックスをつける
- 投稿日:2020-12-27T04:12:08+09:00
FactoryBotで関連データを一緒に作成 自分用
after(:crate)を使いましょう
case
userがteacher_accountにアップデートした際、
user_performanceを関連データとして作成。user_performanceはポリモーフィック関連を利用
code
FactoryBot.define do factory :user do sequence(:username) { |n| "Testuser#{n}" } sequence(:email) { |n| "tester#{n}@example.com" } password { 'password' } phone_number { "0#{rand(0..9)}0#{rand(1_000_000..99_999_999)}" } confirmed_at { Date.today } trait :teacher_account do teacher { true } after(:create) do |user| create(:user_performance, performancable: user) end end end end