- 投稿日:2020-10-28T23:08:28+09:00
Rails+herokuでLINEbotを作ってみた
作ったもの
毎朝ゴミ出しの通知をしてくれるBOTがあったら便利だなーと思い、
勉強がてら作ってみました。使用言語
Ruby
Ruby On Rails6
Heroku
LINE Messager APISTEP 1 メッセージをオウム返しするLINEBOTの作成
こちらについては他の方が詳しく投稿されているので割愛します。
参考記事
https://qiita.com/y428_b/items/d2b1a376f5900aea30dc
https://qiita.com/natsukingdom-yamaguchi/items/e84dffdd90d7f5ef8224
STEP 2 PUSHメッセージ
タスクを追加し、決まった時間になったらメッセージを送信します。
タスクの作成
$rails g task reminder_task
次にコントローラーを生成
$rails g controller webhook trash
descriptionとtaskを記述
lib/tasks/reminder_task.rakenamespace :reminder_task do desc "ここにタスクのお題" task :trash => :environment do webhook = WebhookController.new puts webhook.trash end end次にWebhookcontrollerのアクションを定義
app/controllers/webhook_controller.rbdef trash puts "メッセージ" endここでrakeタスクに追加されているか確認
$ rake -T rake reminder_task:trash タスクのお題
追加されているか確認が出来たら
$ rake reminder_task:trash
【メッセージ】が送信されたらOK
環境変数の設定
PUSHメッセージを利用する場合は環境変数を設定しなければなりません。
環境変数については以下を参照しました。
https://qiita.com/yuichir43705457/items/7cfcae6546876086b849
https://qiita.com/noraworld/items/bfa80811c9e30b4474af設定方法
dotenvをgemに追加します
gem 'dotenv-rails'.envファイルをアプリケーションディレクトリのルートディレクトリに作成
(appやgemfileがある場所に作成)LINEチャネルの諸々を設定
/.envLINE_CHANNEL_SECRET='xxxxxxxxxxxxxxxxxxxxxxxxxxxxx' LINE_CHANNEL_TOKEN='yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy' LINE_USER_ID='zzzzzzzzzzzzzzzzzzzzzz'Webhookcontrollerのtrashアクションを書き換える
app/controller/webhook_controller.rbclass WebhookController < ApplicationController require 'line/bot' def trash message = { "type": "text", "text": WebhookController.contents } client = Line::Bot::Client.new { |config| config.channel_secret = ENV["LINE_CHANNEL_SECRET"] config.channel_token = ENV["LINE_CHANNEL_TOKEN"] } response = client.push_message(ENV["LINE_USER_ID"], message) end def self.contents date = Date.today case date.strftime('%a') when "Mon" "今日は月曜日、燃えるゴミの日!" when "Tue" "無し!" when "Wed" "今日は水曜日、燃えないゴミ・段ボールの日" when "Thu" "今日は木曜日、普通ゴミの日だわ!" when "Fri" "今日は金曜日、缶・瓶・ペットボトルの日!" when "Sat" "一週間お疲れ!今日は無し!" else "" end end endHerokuにPushしスケジューラーを設定すれば、メッセージが届くはずです。
最後に
rubyを勉強して初めて作ったサービス?になりますので、間違ってる点などが多々あるかと思われます。
その際は、ご指摘いただけると嬉しいです!(参考記事の方々、ありがとうございました。)
- 投稿日:2020-10-28T22:48:37+09:00
【Ruby On Rails】FactoryBotを用いてRSpecでモデル単体テストを行うと外部キーが入力されていないことでエラーになる
初投稿
備忘録です。エラー背景
RSpecでテストを実行する際に、FactoryBot内に記述すべき外部キーについて未入力であった。
FactoryBot.define do factory :order_form do zipcode {'123-4567'} prefecture_id {1} city {'亜嗚呼市あああ区'} address {'亜嗚呼1-1-1'} phone_number {'09012345678'} end endエラー内容
OrderForm 商品購入 商品購入がうまくいく時 全項目が存在すれば購入できる (FAILED - 1) Failures: 1) OrderForm 商品購入 商品購入がうまくいく時 全項目が存在すれば購入できる Failure/Error: expect(@order_form).to be_valid expected #<OrderForm:0x00007fe44961c1e8 @zipcode="123-4567", @prefecture_id=1, @city="亜嗚呼市あああ区", @address="亜嗚呼1-1-1", @phone_number="09012345678", @validation_context=nil, @errors=#<ActiveModel::Errors:0x00007fe448aeeaa0 @base=#<OrderForm:0x00007fe44961c1e8 ...>, @messages={:user_id=>["can't be blank"], :item_id=>["can't be blank"]}, @details={:user_id=>[{:error=>:blank}], :item_id=>[{:error=>:blank}]}>> to be valid, but got errors: User can't be blank, Item can't be blank # ./spec/models/order_form_spec.rb:10:in `block (4 levels) in <top (required)>' Finished in 0.17606 seconds (files took 1.9 seconds to load) 1 example, 1 failure Failed examples: rspec ./spec/models/order_form_spec.rb:9 # OrderForm 商品購入 商品購入がうまくいく時 全項目が存在すれば購入できる注目すべき点はこちらです。
@errors=#<ActiveModel::Errors:0x00007fe448aeeaa0 @base=#<OrderForm:0x00007fe44961c1e8 ...>, @messages={:user_id=>["can't be blank"], :item_id=>["can't be blank"]}, @details={:user_id=>[{:error=>:blank}], :item_id=>[{:error=>:blank}]}>> to be valid, but got errors: User can't be blank, Item can't be blank外部キーとしていたuser_id、item_idが空欄になっているということを教えてくれました。
エラー修正
エラー内容より、FactoryBot内の記述を修正すれば良いことがわかりました。
あとは指示された通りuser_idとitem_idをFactoryBotに追加してあげれば大丈夫です。user_id { FactoryBot.create(:user).id } item_id { FactoryBot.create(:item).id }修正後のターミナル
OrderForm 商品購入 商品購入がうまくいく時 全項目が存在すれば購入できる Finished in 0.3807 seconds (files took 3.22 seconds to load) 1 example, 0 failures
成功です。
- 投稿日:2020-10-28T22:35:01+09:00
rails + postgres sqlでポートフォリオ作成
記事の概要
私が作成したポートフォリオの解説です。
作った背景、機能、苦労した点、工夫したところ、今後の課題をまとめました。実際に作成したサイトやソースコードは下記のリンクからご覧いただけます。
https://github.com/rotosiri-zu/pcparts
https://pcparts-staging.herokuapp.com/作った背景
趣味で自作PCを作成したりしているのですが自分が知らないPCパーツのスペックをしりたい他のユーザーはどんなPCパーツを使っているのか気になり、自作PCを作成している他のユーザーからの紹介で使用しているPCパーツや購入したもので作成するときのパーツ選びに参考になればと思いWebアプリを作りました。
また、現職を退職し、Web系開発企業のバックエンドエンジニアになろうと考えていたので、
このアプリを転職活動のポートフォリオとすることに決めました。スペック
言語
Ruby 2.6.6
フレームワーク
ruby on rails 5.2.4.3
cssフレームワーク
bootstrap4
データベース
postgres sql
バージョン管理
github
本番環境
heroku + Amazon S3
主な機能
ログイン・ログアウト機能
登録したユーザーやゲストログインでログインできます。ホーム画面からもゲストログインでログインすることができます。
投稿機能
会員登録することで自由に投稿することができます。
入力に誤りがあれば、投稿はされずエラ-メッセージが表示されます。マイページ機能
ユーザーが投稿したアイテム一覧を確認することができます。
商品名検索機能
投稿時に記入したタイトル名で検索できます。
カテゴリー検索機能
投稿時に選択肢したカテゴリーで検索できます。
口コミ投稿機能
PCパーツの感想を投稿できます。
入力に誤りがあれば、投稿はされずエラ-メッセージが表示されます。アイテム更新・削除機能
投稿したアイテムを更新・削除ができます。
口コミ更新・削除機能
投稿した口コミを更新・削除ができます。
苦労した点
カテゴリー機能の機能追加でIDエラーの解決に時間がかかったところです。
解決した方法は検証と仮説を立てその後に検索して調べ見つけた記事の通りやってみたところ解決しました。工夫した点
ホーム画面からゲストログインできるようにしホーム画面に機能の説明を記載したり説明とアイテム投稿一覧の境目に黒線を追加、詳細画面の口コミ投稿のフォームに黒線を追加してわかりやすくしました。
なぜruby on railsの言語を選んだのか
ruby on railsを選んだ理由は初心者が入りやすく参考にする記事やコミニティが多いからruby on railsを選択しました。
今後の課題
今後の課題はテストコードがかけていないのでテストの実装やパンくずリストの実装を追加しようと考えております。
参考文献
- 投稿日:2020-10-28T22:13:42+09:00
railsでapp名を変更する方法
環境
Rails 6.0.3.4
流れ
1.gemを入れる
2.dbを削除(不要なら)
3.app名を変更
4.db作成手順
1.gemを入れる
Gemfileに以下を追記
gem 'rename'bundleする
$ bundle2.dbを削除(不要なら)
特になければdbを削除
$ rake db:drop3.app名を変更
$ rails g rename:into {{新しいapp名}}作成したapp名のフォルダへ移動
$ cd ../{{新しいapp名}}4.db作成
dbを作成して
$ rake db:createマイグレーションする
$ rake db:migrate
- 投稿日:2020-10-28T21:44:36+09:00
【忘備録】Rubyをやってみて何度も調べたコマンド一覧
はじめに
Rubyを半年程さわってみてなんとなく調べる頻度が多かったコマンドをここでまとめてます。初学者兼初投稿なのでコメントやLGTMなどでフィードバック頂けると励みになります。よろしくお願いします。
Capistrano関連
デプロイ実行 $ bundle exec cap production deploy 1つ前の状態にロールバック $ bundle exec cap production deploy:rollbackunicorn関連
起動状態を確認する $ ps auxwww | grep unicorn プロセスを終了する $ kill -9 ○○○○○○ すべてのログを確認する ($ cd /var/www/app/log にて) $ less unicorn.staderr.log 直近10件のログを確認する ($ cd /var/www/app/log にて) $ tail unicorn.staderr.lognginx関連
再起動する $ sudo service nginx restart すべてのログを確認する (本番環境のホームディレクトリにて) $ sudo less /var/log/nginx/error.logMySQL関連
起動状況を確認する $ sudo service mysqld status 起動する $ sudo service mysqld start本番環境まわりのコマンドばかりになってしまいましたが、過不足があれば随時更新していきます。
- 投稿日:2020-10-28T20:53:48+09:00
HerokuでSequel ProからClearDBに接続する方法
- 投稿日:2020-10-28T20:21:31+09:00
【Rails】ActiveHash(データベースに保存しないデータ)
ActiveHash
Active_Hashとは、都道府県名などの変更されないデータをモデルファイル内に直接記述することで、データベースへ保存せずにデータを取り扱うことができるGem。
実装手順
gemの追加
gem 'active_hash'モデル作成
% rails g model genre --skip-migration--skip-migration」とは、モデルファイルを作成するときに、マイグレーションファイルの生成を行わないためのオプションです。データベースに保存しないため、マイグレーションファイルを作成する必要はありません。
モデル設定
ActiveHash::Baseは、ActiveRecordと同様のメソッドが使用できるようになります。
ActiveHash::Baseを継承することで、Genreモデルに定義したオブジェクトに対してActiveRecordのメソッドが使用できるようになります。genre.rbclass Genre < ActiveHash::Base #ApplicationRecordから自分で変更する。 self.data = [ { id: 1, name: '--' }, { id: 2, name: '経済' }, { id: 3, name: '政治' }, { id: 4, name: '地域' }, { id: 5, name: '国際' }, { id: 6, name: 'IT' }, { id: 7, name: 'エンタメ' }, { id: 8, name: 'スポーツ' }, { id: 9, name: 'グルメ' }, { id: 10, name: 'その他' } ] endマイグレーションファイル
カラムをgenre_idにする理由は、ジャンルのidをarticlesテーブルに保存するため。
class CreateArticles < ActiveRecord::Migration[6.0] def change create_table :articles do |t| t.string :title , null: false t.text :text , null: false t.integer :genre_id , null: false t.timestamps end end endアソシエーションを設定
ActiveHash::Associations::ActiveRecordExtensionsについては、詳細の説明は省きますが、この記述をArticleクラスに記述する事で、belongs_to_active_hashメソッドを使用できます。
article.rbclass Article < ApplicationRecord extend ActiveHash::Associations::ActiveRecordExtensions #自分で追記する。 belongs_to_active_hash :genre endバリデーションを設定
genre_idに関するバリデーションです。
このバリデーションは、genre_idのid:1以外のときに保存できるという意味です。article.rbclass Article < ApplicationRecord extend ActiveHash::Associations::ActiveRecordExtensions belongs_to_active_hash :genre #空の投稿を保存できないようにする validates :title, :text, :genre, presence: true #ジャンルの選択が「--」の時は保存できないようにする validates :genre_id, numericality: { other_than: 1 } endコントローラーの設定
articles_controller.rbclass ArticlesController < ApplicationController def index @articles = Article.order("created_at DESC") end def new @article = Article.new end def create @article = Article.new(article_params) if @article.save redirect_to root_path else render :new end end private def article_params params.require(:article).permit(:title,:text,:genre_id) end endフォームの設定
<%= form.collection_select(保存されるカラム名, オブジェクトの配列, カラムに保存される項目, 選択肢に表示されるカラム名, オプション, htmlオプション) %>引数 値 役割
第一引数
(保存されるカラム名) :genre_id 保存先のカラム名
第二引数
(オブジェクトの配列) Genre.all 配列データを指定する
(今回はジャンル情報の配列)
第三引数
(カラムに保存される項目) id 表示する際に参照するDBのカラム名
第四引数
(選択肢に表示されるカラム名) name 実際に表示されるカラム名
第五引数
(オプション) {} 今回はオプションの指定なし
(include_blankという値のない選択肢を先頭にするオプションなどがあります。)
htmlオプション {class:"genre-select"} 今回はクラス名を付与
(cssを当てるため)<%= form_with model: @article, url:articles_path, local: true do |f| %> <div class="article-box"> 記事を投稿する <%= f.text_field :title, class:"title", placeholder:"タイトル" %> <%= f.text_area :text, class:"text", placeholder:"テキスト" %> <%= f.collection_select(:genre_id, Genre.all, :id, :name, {}, {class:"genre-select"}) %> <%= f.submit "投稿する" ,class:"btn" %> </div> <% end %>ビューでの表示
@article.genre.name
- 投稿日:2020-10-28T19:28:52+09:00
【Ruby on Rails】try(:[ ], :key)を読み解く
はじめに
user.try(:[],:name)初めてこのコードを見た時、
「なんで空の配列をメソッドの部分に入れているんだ、、、?」
と思いました。
Ruby(Rails)の文法をすっ飛ばしてきた弊害ですね、、、そもそもRailsのtryとは?
Active Supportに搭載されているメソッド (Rubyだけでは使えない)
対象のオブジェクトがnilでない時のみ、指定したメソッドを使う
第一引数に使いたいメソッド、第二引数にその引数(必要であれば)を与えますuser = {name: "test"} # user[:group]がnilであるため、メソッドエラーが起きる user[:group].replace("A") # => NoMethodError: undefined method 'replace' for nil:NilClass # nilな対象に対してtryを使うとエラーは起きず、nilが帰ってくるだけ user[:group].try(:replace,"A") => nil空の配列がメソッドに?
それでは本題ですが、rubyのHashには[]のメソッドがあります。
引数にkey名を取ってそのvalueを返します。user.[] :name => "test" # これはuser[:name]と同じちなみに、「+」などもメソッドとして使えます。
user[:name].+ 2 => "test2"
今回の場合はtryとこのメソッドの組み合わせなので
user.try(:[],:name) => "test"という結果が返ってきます。
まとめ
[]についてなかなかヒットしなかったので少し理解に苦しみました。
ruby/railsの文法を勉強し直します、、、
- 投稿日:2020-10-28T19:16:43+09:00
【Rails】星★の評価を実装する(入力、保存、表示)
はじめに
開発しているメモアプリにランク付けをしていきたいと思います。
今回は三段階で評価していこうと思います。
それに伴い、星★による評価の入力・保存・表示について学習していきます。参考
マイグレーションファイルにカラムを追加
notesテーブル(メモテーブル)のrateカラム(型:float)に評価値を保存する
すでに、テーブルとカラムは作成されていることを前提に進めます。カラムは、半分の星による評価を行う場合、「0.5」や「1.5」という値を保存することになるため、float型にしておく必要があります。
もし、integerやstringの型として作成してしまっていた場合は、データベースによって変更方法は異なりますが、型の変更が必要になります。下記の記事でこの型の変更の沼にハマってしまった時の解決策を書いています。
class CreateNotes < ActiveRecord::Migration[5.2] def change create_table :notes do |t| t.text :title t.integer :user_id t.integer :category_id t.text :explanation t.float :rate t.timestamps end end endrails db:migrate:resetjavascriptの読み込み、★画像の読み込み
上記参考リンクを確認しながら、javascriptの読み込みと星の画像の読み込みを行います。
やり方(2種類)
①jQuery Ratyを使用するには、https://github.com/wbotelhos/raty からjquery.raty.jsをダウンロードする。
ダウンロードしたスクリプトをウェブサイトの任意の場所に配置する。
app/javascriptsのフォルダの中にダウンロードしたjquery.raty.jsファイルを配置する
②jQuery Ratyを使用するHTMLの中でJavaScriptを読み込む。RatyはjQueryのプラグインなので、jQueryのスクリプトも必要である。
<script src="/js/jquery.min.js"></script> <script src="/js/jquery.raty.js"></script>今回は①のやり方で実装していきます。
*ここでJavaScriptも定義していきます。
javascripts/application.js
ファイルに追加する//= require rails-ujs //= require activestorage //= require turbolinks //= require jquery #追加 //= require jquery_ujs #追加 //= require_tree .Gemファイル追加
gem 'jquery-rails'budle installモデルの記述(紐付け)
note.rbclass Note < ApplicationRecord # ユーザーとの紐付け belongs_to :user,optional: true # バリデーション validates :title, presence: true validates :explanation, presence: true # カテゴリーと紐付け belongs_to :category validates :rate, presence: true validates :rate, numericality: { # only_integer: true, less_than_or_equal_to: 3, greater_than_or_equal_to: 1, } # numericality=空を許可する numericalityは、デフォルトでは小数も許容してしまいます。rateカラムでは整数のみ許可したいので、 only_integerを。 例 validates :param3, :numericality => { :less_than_or_equal_to => 3} # 数字が3以下であるか validates :param3, :numericality => { :greater_than_or_equal_to => 1 } # 数字が1以上であるか endコントローラーの記述
notes_controller.rbclass NotesController < ApplicationController before_action :authenticate_user! def new @note = Note.new end def create # @note = Note.new(note_params) @note = current_user.notes.build(note_params) @note.save redirect_to notes_path end def index # is_validがマッチするレコードを全て取得 @categorys = Category.where(is_valid: true) @q = Note.all.ransack(params[:q]) @notes = @q.result(distinct: true) end def show @note = Note.find(params[:id]) end def edit @note = Note.find(params[:id]) end def update @note = Note.find(params[:id]) @note.update(note_params) redirect_to note_path end def destroy @note = Note.find(params[:id]) @note.destroy redirect_to notes_path end def search @categorys = Category.where(is_valid: true) @category = Category.find(params[:id]) @q = @category.notes.all.ransack(params[:q]) @notes = @q.result(distinct: true).page(params[:page]) @title = @category.name render 'notes/index' end private def note_params params.require(:note).permit(:title, :category_id, :explanation,:user_id,:rate) end endここでは
note_params
メソッドにrate
カラムを追加します。メモ登録フォームを作る
_form.html.erb<%= form_with model:note, local: true do |f| %> <div class='form-group'> <%= f.label :タイトル %> <%= f.text_field :title, class: 'form-control', id: 'note_title' %> </div> <div class='form-group'> <%= f.label :カテゴリー %> <%= f.collection_select :category_id, Category.all, :id, :name %> </div> <!-- 評価 --> <div class="form-group row" id="star"> <%= f.label :rate,'重要度 ', class:'col-md-1 col-form-label' %> <%= f.hidden_field :rate, id: :review_star %> </div> <div class='form-group'> <div id='editor'> <%= f.label :内容 %> <%= f.text_area :explanation, rows: 10, class: 'form-control', id: 'note_explanation', "v-model" => "input", name: "note[explanation]" %> <h2><i class="fas fa-eye"></i> Preview</h2> <div id="preview-field" v-html='input | marked'> </div> <div ></div> </div> <%= f.submit '登録', class: 'btn btn-success' %> </div> <% end %> <!-- リアルタイムプレビュー --> <script type="text/javascript"> window.onload = function() { new Vue({ el: '#editor', data: { input: '<%== j @note.explanation %>', }, filters: { marked: marked, }, }); }; <!-- 評価 --> $('#star').raty({ size : 36, starOff: '<%= asset_path('star-off.png') %>', starOn : '<%= asset_path('star-on.png') %>', starHalf: '<%= asset_path('star-half.png') %>', scoreName: 'note[rate]', half: true, }); </script>ポイントは下記
# ★の半分の入力ができるようにするため half: true,星による評価の表示
メモ一覧にて、★を表示したい。
上記の「★の入力、保存」と異なる点は、1.入力はせず表示する 、 2.繰り返し処理をするということになります_notes_index.html.erb<div class='row'> <table class='table'> <thead> <tr> <th>タイトル</th> <th>カテゴリー</th> <th>重要度</th> </tr> </thead> <tbody> <% @notes.each do |note| %> <% if user_signed_in? && current_user.id == note.user_id %> <tr> <td> <%= link_to note_path(note) do %> <%= note.title %> <% end %> </td> <td><%= note.category.name %></td> <!-- 評価 --> <td> <div id="star-rate-<%= note.id %>"></div> <script> // 繰り返し処理でもidをidを一意にできるようにnote_idを入れる $('#star-rate-<%= note.id %>').raty({ size: 36, starOff: '<%= asset_path('star-off.png') %>', starOn : '<%= asset_path('star-on.png') %>', starHalf: '<%= asset_path('star-half.png') %>', half: true, // 読み込みだけで入力できない readOnly: true, score: <%= note.rate %>, }); </script> </td> </tr> <% end %> <% end %> </tbody> </table> </div>ポイントは下記
# 繰り返し処理を実行してもidを一意に保てるようにreview.idを埋め込む <div id="note-rate-<%= note.id %>"></div> # 読み取り専用(入力できない) readOnly: true, # 星の入力値を読み込む score: <%= note.rate %>,これで完成!
最後に
説明が分かりづらかったりすると思いますがご了承ください。
また、間違っているところがあればご教授いただけると幸いです。
- 投稿日:2020-10-28T18:55:08+09:00
Railsで多言語化対応する!
今自分が開発しているwebアプリを英語に対応しようとしたときにやったことを書いていきます。
インストール
Gemfilegem 'rails-i18n'インストール
bundleconfig/application.rbに設定
config/application.rbconfig.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s] # 対応する言語。今回は日本語(ja)と英語(en)だけ config.i18n.available_locales = %i(ja en) # 上記の対応言語以外の言語が指定された場合、エラーとするかの設定 config.i18n.enforce_available_locales = true # デフォルトの言語 config.i18n.default_locale = :jacontroller
controller/application_controller.rbbefore_action :set_locale def set_locale I18n.locale = locale end def locale @locale ||= params[:locale] ||= I18n.default_locale end def default_url_options(options={}) options.merge(locale: locale) endroutes.rb
routes.rbscope '(:locale)', locale: /#{I18n.available_locales.map(&:to_s).join('|')}/ do root "posts#index" resources :posts endscopeで囲んだ部分が多言語対応するページです。
多言語化
en.ymlとja.ymlを作ります。
多言語化したい文にviews<%= t(:hello) %>と書きます。helloのところは自由に変えてください
ja.ymlja: hello: こんにちは # モデルは全て activerecord を起点にする。 # これにより、User.model_name.human / User.human_attribute_name({attr_name})でアクセス可能。 activerecord: models: user: 'ユーザー情報' attributes: user: name: '名前' mail: 'メールアドレス' url: 'ウェブページ'en.ymlen: hello: "hello" # モデルは全て activerecord を起点にする。 # これにより、User.model_name.human / User.human_attribute_name({attr_name})でアクセス可能。 activerecord: models: user: 'User' attributes: user: name: 'Name' mail: 'Email' url: 'URL'こんな感じでやっていきます。
- 投稿日:2020-10-28T17:57:56+09:00
Railsのフォームで過去の日付を入力させない方法
はじめに
カレンダーから日付を入力してもらう際に、過去の日付を選択できないようにしたい。
保存するモデルのカラムはDate型を使用。
ビューでのフォーム作成にはform_withを使用。開発環境
ruby 2.6.5
Rails 6.0.3.3方法
※余計な記述は省いています
私の場合はorderモデルのstart_date(Date型)に保存するためのフォームindex.html.erb<%= form_with model: @order, url: item_order_path, local: true do |f|%> <%= f.date_field :start_date, class:"order-date-form %> <% end %>カレンダー表示ができて、日付を選択できるようになってます。
しかし、現状では過去の日付も選択できてしまいます。
これを解消するために記述を追加します。
index.html.erb<%= form_with model: @order, url: item_order_path, local: true do |f|%> <%= f.date_field :start_date, class:"order-date-form, min: Date.current %> <% end %>同じようにカレンダーは表示されますが、過去の日付は選択できないようになりました。
"Date"についてはActive_supportが用意してくれているもので、デフォルトで使えるようです。
"Date.today"ではなく"Date.current"が推奨されています。詳しくはこちら Railsガイド
さいごに
バリデーションやコントローラーで防ぐのは各々で追加してみてください。
- 投稿日:2020-10-28T17:17:56+09:00
【Rails】遷移前のURLのパス名を取得してリンク先を変更する
- 投稿日:2020-10-28T17:17:56+09:00
Railsで遷移前のURLのパス名を取得してリンク先を変更する
- 投稿日:2020-10-28T16:33:32+09:00
Railsのエラーメッセージの日本語化【devise/Formオブジェクト等】
背景
未経験からエンジニアになるために勉強中です。
簡単なアプリケーションを作成している際に、バリデーションエラーのメッセージが英語なことに引っ掛かり、
エラーメッセージを日本語化する方法を調べていたところ、
知りたい情報が1つにまとまっている記事が見つからなかったため、
自分の備忘録かつ、同じようにプログラミングを勉強中でお困りの方の役に立てばと思い記事を作成しました。
まだ至らぬ点があるとは思いますが、何かお気づきの点があればコメントにてご指摘ください。環境
- ruby 2.6.5
- Rails 6.0
変更前の画面(一例)
何も設定をしていないと、バリデーションエラーのメッセージは以下の画像のように英語で出力されます。
変更後の画面(一例)
変更後は以下の画像のように日本語でエラーメッセージが出力されます。
日本語化の準備
・下準備①(Gemのインストール)
エラーメッセージを日本語化するためには、rails-i18nというgemを使用します。
Gemfileに以下の一文を追加して、ターミナルにてbundle installを実行してください。gem 'rails-i18n' # Gemfileに上記コードを記載・下準備②(localeの言語設定変更)
次にconfig/application.rbに以下の一文を追記し、言語設定を変更します。
追記後に、サーバ再起動すると下記画像のようにエラーメッセージの一部が日本語化されます。config/application.rbclass Application < Rails::Application config.load_defaults 6.0 # この下に下記のコードを記載 config.i18n.default_locale = :ja # 上記のコードを記載 endしかし、このままではmodelの属性名は英語のままです。
ですので、次はそこを日本語に変更します。・カラム名を日本語に変更する
modelの属性名を変更するためには、日本語での対応表を作る必要があります。
config/locales/models/に、ja.ymlというファイルを作成して、以下のようにカラム名とそれに対応する日本語を記述してください。config/locales/models/ja.ymlja: activerecord: models: item: 商品 attributes: item: image: 商品の画像 name: 商品名 details: 商品の説明 price: 価格私はitemというモデルの属性名を変更したかったので、コード内にitemと記載しております。自身の変更したいモデルに合わせて、上記コードのitemという所を変更してください。
・上記の対応表を読み込む
上記で設定したファイルは自動では読み込まれません。
なので、config/application.rbにこのymlファイルの読み込む一文を追記します。config/application.rbclass Application < Rails::Application config.load_defaults 6.0 config.i18n.default_locale = :ja # この下に下記のコードを記載 config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.yml').to_s] # 上記のコードを記載 endここまで設定ができていれば、下記のように全て日本語表記に変わっているはずです。
・わかりやすいエラーメッセージへ変更
rails-i18nというGemを使用すれば大体のエラーメッセージを日本語に変換してくれますが、
自分でバリデーションを設定した際などに下記のように、
一見しただけではわからないような出力をされる場合があります。
そのような場合は自身でエラーメッセージを設定してあげましょう。
以下は一例になります。【例】
ActiveHashを用いて都道府県名をプルダウン形式で選択できるようにし、それに対して自身でバリデーションをかけた場合
«変更前»
バリデーションをかけたモデル内のコード# 省略 with_options presence: true do # 省略 validates :prefecture_id, numericality: { other_than: 1 } # 省略 end«変更後»
バリデーションをかけたモデル内のコード# 省略 with_options presence: true do # 省略 validates :prefecture_id, numericality: { other_than: 1 ,message: 'を選択してください'} # 省略 end上記のようにmessage: 'メッセージ内容'という風にオプションを設定してあげるとよりわかりやすい日本語に変更できます。
・さらにカラム名を追加したい場合
カラム名をさらに追加したい場合は、下記のように自身で追加してください。
config/locales/models/ja.ymlja: activerecord: models: item: 商品 attributes: item: image: 商品の画像 name: 商品名 details: 商品の説明 price: 価格 # ここから下に下記のように自身でカラム名と日本語の対応表を記載 category_id: カテゴリー status_id: 商品の状態 prefecture_id: 発送元の地域独自に定義したFormオブジェクトの日本語化する場合
・下準備
上記までの設定ができていれば特に必要ありません。
できていなければ、上記手順に従って下準備(Gemのインストール等)と対応表(ja.yml)の作成、
対応表の読み込み(config/application.rbに追記)まで行いましょう。・config/locales/models/ja.ymlを編集
config/locales/models/ja.ymlを下記のように追記します。
config/locales/models/ja.ymlja: activerecord: models: item: 商品 attributes: item: image: 商品の画像 name: 商品名 price: 価格 details: 商品の説明 # ここから下に下記のコードを追記 activemodel: attributes: user_purchase: city: 市区町村 postal_code: 郵便番号 phone_number: 電話番号 prefecture_id: 都道府県 house_number: 番地 building: 建物名 # 上記のコードを追記(カラム名等は自身で変更してください)自身で定義したFormオブジェクトを日本語化するには、activemodel:と記載しその下に設定してください。
きちんと設定をしないと日本語に変更をされません。補足
ActiveModel::Modelと設定しているため、activerecord:下のattributes:にコードを記載しても反応しません。
Formオブジェクトを設定したモデル内のコードclass UserPurchase include ActiveModel::Model # 自身でActiveModel::Modelを設定している # 省略 endconfig/locales/models/ja.ymlja: activerecord: models: item: 商品 attributes: item: image: 商品の画像 name: 商品名 price: 価格 details: 商品の説明 # 設定がActiveRecordではないので、ここから下にコードを書いても反応しませんdeviseの日本語化
簡単にユーザー登録機能等が実装できるdeviseもデフォルトの設定は英語です。
こちらも日本語に変更できます。変更前の画面(一例)
変更後の画面(一例)
・Gemのインストール
deviseのエラーメッセージを日本語化するためには、devise-i18nとdevise-i18n-viewsというgemを使用します。
Gemfileに以下の一文を追加して、ターミナルにてbundle installを実行してください。gem 'devise-i18n' gem 'devise-i18n-views' # Gemfileに上記コードを記載・日本語対応表の作成
コマンドにて日本語翻訳ファイルを生成します。
ターミナルにて下記のコマンドを実行してください。rails g devise:views:locale ja # 下記のように実行結果が表示されれば成功です。 create config/locales/devise.views.ja.ymlきちんとファイルが生成されているか確認しましょう。
config/locales/devise.views.ja.ymlja: activerecord: errors: models: user: attributes: email: taken: "は既に使用されています。" # 以下長すぎるため省略 unlocks: new: resend_unlock_instructions: "アカウントの凍結解除方法を再送する" # 上記が最後の行です・localeの言語設定変更
すでに設定をしてある場合はこの作業は不要です。
してない場合は下記のコードを追記しましょうconfig/application.rbclass Application < Rails::Application config.load_defaults 6.0 # この下に下記のコードを記載 config.i18n.default_locale = :ja # 上記のコードを記載 endここまで作業が完了したら、サーバーを再起動したら日本語に変更されているはずです。
・さらにカラム名を追加したい場合
カラム名をさらに追加したい場合は、下記のように自身で追加してください。
config/locales/models/ja.ymlja: activerecord: errors: # 以下長いので省略 confirmation: "が内容とあっていません。" attributes: user: current_password: "現在のパスワード" name: 名前 email: "メールアドレス" password: "パスワード" password_confirmation: "確認用パスワード" remember_me: "次回から自動的にログイン" # 下記に必要があれば自分でカラム名とそれに対応する日本語を追加 nickname: "ニックネーム" first_name: "名前" last_name: "名字" birthday: "生年月日" # 上記のように記載 models: user: "ユーザ" # 以下長いので省略まとめ
以上が私が行ったエラーメッセージの日本語化でした。
必要があれば、修正・追記をしていきます。
ここまでご覧いただき誠にありがとうございました。
何かお気づきの点などございましたら、コメントにてご連絡ください。参考文献
Railsのバリデーションエラーのメッセージの日本語化
RailsのFormオブジェクトの日本語化
ActiveRecordのvalidatesで表示されるエラーメッセージのフォーマットを変更する
【Rails5】Devise-i18nで日本語化する
上記の記事を参考にさせていただきました。こちらの記事の方が詳しく書いていることもありますので、
そちらも是非参考にしてみてください。
- 投稿日:2020-10-28T16:28:31+09:00
Expected exactly 2 elements matching "a[href="/"]", found 0.. のエラーメッセージ
Expected exactly 2 elements matching "a[href="/"]", found 0..のエラーメッセージ
Railsチュートリアルをやっている時にエラーが起きたので、解決した方法を書きます。やっていたのは5章の「5.3.4 リンクのテスト」の所です。
エラーメッセージはFAIL["test_layout_links", SiteLayoutTest, 2.2938910419998138] test_layout_links#SiteLayoutTest (2.29s) Expected exactly 2 elements matching "a[href="/"]", found 1.. Expected: 2 Actual: 1 test/integration/site_layout_test.rb:10:in `block in <class:SiteLayoutTest>' 1/1: [===================================] 100% Time: 00:00:02, Time: 00:00:02 Finished in 2.29667s 1 tests, 2 assertions, 1 failures, 0 errors, 0 skips }
私の場合はこのファイルに異常がありました。
app/views/layouts/_header.html.erb<header class="navbar navbar-fixed-top navbar-inverse"> <div class="container"> <%= link_to "sample app", root_path, id: "logo" %> <nav> <ul class="nav navbar-nav navbar-right"> <li><%= link_to "Home", 'root_path' %></li> <li><%= link_to "Help", 'help_path' %></li> <li><%= link_to "Log in", '#' %></li> </ul> </nav> </div> </header>
この中でも今回は、上記のroot_pathとhelp_pathに' 'がついていたことが原因みたいでした。このエラーが出た原因は、もともとあった'#'にroot_pathなどを入れたことで外し忘れていたみたいでした。
正しくはこちらになります。<li><%= link_to "Home", root_path %></li> <li><%= link_to "Help", help_path %></li>
因みに、app/views/layouts/_fotter.html.erbにも同じようなミスがあったので、上記のエラーが起こった方は確認してみると良いかもしれません。参照元
- 投稿日:2020-10-28T16:12:45+09:00
HerokuにデプロイしたMysqlのロールバック方法をメモ
はじめに
RubyOnRailsでアプリを作成しデプロイ。
Heroku上でマイグレーションファイルを実行後のベータデースのリセットをメモしておく。
● エラーメッセージから環境変数を確認
コマンドを実行
$ heroku run rake db:migrate:reset!
● 確認した環境変数 DISABLE_DATABASE_ENVIRONMENT_CHECK=1 を付与して、データベースをdropする
コマンドを実行
$ RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bundle exec rake db:drop
● 再生成
コマンドを実行
データベースの生成 $ heroku run rails db:create マイグレーションを実行 $ heroku run rake db:migrate参考
[Rails5] heroku db:resetからmigrateまで
Rails5のproductionでrake db:dropはできない、普通には
- 投稿日:2020-10-28T16:12:45+09:00
herokuにデプロイしたMysqlのロールバック方法をメモ
はじめに
RubyOnRailsでアプリを作成しデプロイ。
heroku上でマイグレーションファイルを実行後のベータデースのリセットをメモしておく。
● エラーメッセージから環境変数を確認
コマンドを実行
$ heroku run rake db:migrate:reset!
● 確認した環境変数 DISABLE_DATABASE_ENVIRONMENT_CHECK=1 を付与して、データベースをdropする
コマンドを実行
$ RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bundle exec rake db:drop
● 再生成
コマンドを実行
データベースの生成 $ heroku run rails db:create マイグレーションを実行 $ heroku run rake db:migrate参考
[Rails5] heroku db:resetからmigrateまで
Rails5のproductionでrake db:dropはできない、普通には
- 投稿日:2020-10-28T12:59:20+09:00
Railsを勉強する際の基本の用語
- 投稿日:2020-10-28T12:36:45+09:00
Rails Tutorial 第4章学習編
Rails Tutorial 第4章で(。´・ω・)ん?って思ったところ
前提知識と復習でアウトプットしているからだと思いますが、
この章は特に(。´・ω・)ん?って思ったところはないです。
動画もテキストも非常に分かりやすかったです。Rails 第4章 簡単な内容のおさらい
第四章はRails風味のRubyです。こんなに分かりやすいオブジェクト指向は初めてです。
ProgateのPython、TECH::CAMPのRubyでも学習しましたが。。。
(゜-゜)う~ん オブジェクト指向それって美味しいの?って感じでした。よく説明に・・・全てのモノはオブジェクトです。
人も一つのオブジェクト、車も一つのオブジェクト
ジョンという人がいる。ジョンは人に属している。
人は職業・性別・年齢などの要素を持っている。。。
こんな内容に沿ってコードを書かされて(。´・ω・)ん?って感じになります。私の言葉でのオブジェクト指向を説明すると・・・
"文字列"があります。 オブジェクト指向で記述されていると、 "12345".length #文字をカウントするメソッドが使える。 "12345".to_i #文字列を整数に変換するメソッドが使える。 .lengthメソッド・.to_iメソッドを定義していないのに何で使えるの? ⇒ 答えはオブジェクト指向で書かれているからです。 まだ、(。´・ω・)ん?って感じですよね 実は"文字列"と書けば文字列と認識されていますが、 String.new("文字列")というコードの省略形です。 文字列(String)クラスのオブジェクト"文字列"を作りなさいという意味なんです。 予め文字列(String)クラスに様々なメソッドが用意されています。 String.new("")で生成したオブジェクトは文字列オブジェクトなので定義済みメソッドが使えるのです。 文字列クラスで.to_iメソッドが用意されているので、 新しく生成した文字列も.to_iなどの様々なメソッドが使えるという事です。 オブジェクト指向の最大の利点は、 文字列は必ず文字列オブジェクトとして生成する事で.to_iなどメソッドを共有出来きる事です。('ω')ノ 文字列クラスに新しいメソッドを追加すれば、全ての文字列オブジェクトで使用できるって事です。 Progateで学んだ時は(。´・ω・)ん?でしたが、今になって便利さが分かりました(´-ω-`)クラスと継承
"文字列"はStringクラスに属しています。 何処に属しているか確認する為に.classメソッドが使えます。 s = "文字列" s.class ⇒ String 実はStringクラスもObjectクラスに属しています。 >> s.class.superclass # superclass : 親クラスを調べる => Object Objectクラスも更に上のクラスに属しています。 >> s.class.superclass.superclass => BasicObject BasicObjectは更に上のクラスに属している? 答えはNoでした。nilは存在しないという意味です。 >> s.class.superclass.superclass.superclass => nil なんでこんな事をしているのかというと・・・機能を引き継ぐ為です。('ω')ノ Objectクラスの下には、String(文字列)・Integer(整数)・Array(配列)クラスなどがあります。 配列も、整数も、文字列も、.lengthメソッドが使えますよね。 3つそれぞれ追加していくのは大変ですよね。 なのでObjectに追加して下位クラスで利用出来るようにすれば手間が省けます。 この様に上位のクラスで定義されたメソッドを下位メソッドに引継ぐ事を『継承』と言います('ω')ノ #class <クラス名>で新しいクラスを定義できます。 >> class Word < String # < StringでStringクラスを継承出来ます('ω')ノ >> # 文字列が回文であればtrueを返す >> def palindrome? # defで新しいメソッドを定義できます。 >> self == self.reverse # selfは文字列自身を表します >> end >> end => :palindrome?Ruby 基礎
$ rails console #整数の足し算 >> 17 + 42 => 59 #文字列の結合 >> "foo" + "bar" # 文字列の結合 => "foobar" #変数の代入 >> first_name = "Michael" => "Michael" #文字列の式展開 これ便利('ω')ノ Railsでも使うよ。 >> "#{first_name} Hartl" => "Michael Hartl" #式展開('ω')ノ >> first_name = "Michael" => "Michael" >> last_name = "Hartl" => "Hartl" >> first_name + " " + last_name # 苗字と名前の間に空白を入れた結合 => "Michael Hartl" >> "#{first_name} #{last_name}" # 式展開を使って結合 (上と全く同じ) => "Michael Hartl" #文字列の出力 (puts) >> puts "foo" # 文字列を出力する foo => nil #戻り値はnilは「何にもない」 #文字列の出力 (print) >> print "foo" # 文字列の画面出力 (putsと同じだが改行しない) foo=> nil >> print "foo\n" # \nは改行。これでputsと同じ出力になる。 foo => nil #''シングルクォーテーションと""ダブルクォーテーション >> '#{first_name} #{last_name}' # ''は式展開できない。 => "/#{first_name} #{last_name}" >> "#{first_name} #{last_name}" # ""は式展開できる。 => "Michael Hartl" # empty?メソッド >> "foobar".empty? => false >> "".empty? => true #条件分岐 (if) ・.include?("文字列") ・.nil? メソッド >> if s.nil? >> "The variable is nil" >> elsif s.empty? >> "The string is empty" >> elsif s.include?("foo") >> "The string includes 'foo'" >> end => "The string includes 'foo'" # バン!バン! 強制的に論理値(True/False)で出力する >> !!nil #Rubyオブジェクトはnilだけfalse => false >> !!0 #その他のあらゆるRubyのオブジェクトはtrue => trueこれで半分程度の内容ですかね。結構ボリューム多いです。
配列やハッシュといった重要な内容がこの後に続くのですが・・・
全部書くと著作権的にどうなのかなと思うのでシンボルについて書いたら終わりッス('ω')ノシンボルと整数、文字列について
#これはハッシュというラベル付配列です。 user1 = { "name"=>"test_user", "email" => "test_user@example.com" } user2 = { "name"=>"test_user", "email" => "test_user@example.com" } user1 == user2 => false 同じ内容なのに falseになるのはなんで?('ω')ノ 実はobject_idというモノが違っているから、異なっているのを確かめてみてください。 user1.object_id user2.object_id このobject_idってデータの格納されている場所みたいなものです。 文字列でも試してください。実行する度にobject_idが代わるんです。 "name".object_id "name".object_id "name".object_id 次に数字です。数字はどうでしょうか? 数字は常に同じobject_idになるんです。 1.object_id 1.object_id 1.object_id 最後に・・・シンボルです。 シンボルも数字と同じくobject_idが変化しないんです。 :name #:+文字列をシンボルって言うのですが、object_idにラベル付けたモノって思ってください。 なんでこんな事をするかというと、文字列を使うよりも処理速度が速くなるからです。('ω')ノ なのでハッシュのラベル名は文字列よりもシンボルの方が好まれます。 ◎ user = { :name=> "test_user" , :email => "test_user@example.com" } △ user = { "name"=>"test_user", "email" => "test_user@example.com" } 更にもっと簡単に記述もできます。 user = { :name=> "test_user" , :email => "test_user@example.com" } user = { name: "test_user", email: "test_user@example.com" }カスタムヘルパー
自分でメソッドを定義する場合にヘルパーというファイルに記述します('ω')ノ
app/helpers/application_helper.rbmodule ApplicationHelper # ページごとの完全なタイトルを返します。 def full_title(page_title = '') base_title = "Ruby on Rails Tutorial Sample App" if page_title.empty? base_title else page_title + " | " + base_title end end end感想
第四章は非常に内容が濃くて面白いです。
自分で様々なメソッドを定義する為にはRubyの知識が必要になってきますね。
いろんなメソッドが存在するけど、ほんの僅かしか覚えていないので
Railsの学習が終わったら、Rubyもきちんと学習しないと駄目ですね・・・。
はぁー、先が長い長い( ^ω^)・・・。
- 投稿日:2020-10-28T12:25:36+09:00
Railsで簡単な通知機能(フォローされた時のみ)
Railsでの簡単な通知機能です。(とりあえずフォローされた時のみ)
ルーティングの設定
config/routes.rbresources :notifications, only: [:index]コントローラの作成
$ rails g controller notificationsモデルの作成
$ rails g model Notification visitor_id:integer visited_id:integer$ rails db:migrateモデルとアソシエーションの設定
app/models/user.rbhas_many :active_notifications, class_name: "Notification", foreign_key: "visitor_id", dependent: :destroy has_many :passive_notifications, class_name: "Notification", foreign_key: "visited_id", dependent: :destroy def create_notification_follow!(current_user) temp = Notification.where(["visitor_id = ? and visited_id = ? ",current_user.id, id]) if temp.blank? notification = current_user.active_notifications.new(visited_id: id) notification.save if notification.valid? end endapp/models/notification.rbbelongs_to :visitor, class_name: 'User', foreign_key: 'visitor_id' belongs_to :visited, class_name: 'User', foreign_key: 'visited_id'コントローラの設定
app/controllers/relationships_controller.rbdef create @user = User.find(params[:user_id]) current_user.follow(params[:user_id]) @user.create_notification_follow!(current_user) #追記部分 redirect_to request.referer endapp/controllers/notifications_controller.rbdef index @notifications = current_user.passive_notifications.order(created_at: :DESC) endビュー(通知一覧)の設定
app/views/notifications/index.html<h1>おしらせ</h1> <% if @notifications.exists? %> <% @notifications.each do |notification| %> <table> <tr> <td> <%= attachment_image_tag notification.visitor, :image, size: "50x50" %> </td> <td> <%= link_to user_path(notification.visitor) do %> <%= notification.visitor.name %> <% end %> </td> <td> からフォローされました。 </td> <td> <%= " (#{time_ago_in_words(notification.created_at)}まえ)" %> </td> </tr> </table> <% end %> <% else %> <p>おしらせはありません</p> <% end %>
- 投稿日:2020-10-28T12:25:36+09:00
カラムのBoolean型とは
Booleanとは、一般的に真と偽のような2つの状態を表すデータ型のこと
Railsではbooleanにデフォルト値を渡してあげることによって、
true,false,nilという3つの情報を必ず2つに収束するようにできる
nilというものが存在しないようにチェックすることができる。なので必ずデフォルト値を入れてあげるとよい。
- 投稿日:2020-10-28T08:32:51+09:00
Rails Tutorial 拡張機能の返信機能を作ってみた(その3):仕様の勘違いを修正
Rails Tutorialの第14章にある、返信機能を作る件の続きです。
postされたらmodelのin_reply_toにIDを入れる機能
@replyが書いてあるmicropostがpostされたら、modelのin_reply_toにIDを入れる機能を
作ります。変更するのはpostを受け取って、modelをsaveするところです。どこなのか探します。
文字列の操作をするメソッドをネットで検索します。
https://www.sejuku.net/blog/11843
start_with?(指定の文字列で始まっているか調べる)
http://rubytips86.hatenablog.com/entry/2014/03/28/132953
を読みます。仕様を勘違いしていることが判明
機能を深堀りしている途中で、contentが@replyで始まるのだと思っていたのが実は勘違いであることが分かりました。
「@reply exampleuser hogehoge...」
だと思っていたのですが、正しくは
「@exampleuser hogehoge...」
でした。そうだとして、nameにブランクが含まれていると問題があると分かります。
例えば、nameが「Ola Lakin I 」は「@Ola Lakin I 」とpostしてもnameは「@Ola」しか探せないことに思い当たりました対応方法としては、ユニークなidを追加する方法が考えられます。実はテキストで同じことを言っているのですが、この時点でやっとピンときました。
@以下がユニークになる方法はテキストでも具体的な方法が書いてあることから、後で考えることにします。
当面は@nameがブランクを含まずユニークになっている前提で進めることにします。この前提で機能を作った後、ユニークにする変更を加えることにします。文字列から@で始まる単語を取り出す
ネットで調べた方法をコンソールで試します。
>> s = "@Example hoge hoge aa" => "@Example hoge hoge aa" >> b = s.scan(/@\w+/) => ["@Example"]文字列に@xxが含まれないときどうなるかを調べます。
>> s2 = "Example hoge hoge aa" => "Example hoge hoge aa" >> b2 = s2.scan(/@\w+/) => [] >> b2[0] => nilnilになりました。
次に先頭の@を削除する方法を試します。
>> b = s.scan(/@\w+/) => ["@Example"] >> b[0].slice!(0) => "@" >> b[0] => "Example"これで@xxxの単語を取り出せました。
controllerの変更
画面は変更する必要がないと考え、controllerのどこを変更するかテキストを調べます。
controllers/microposts_controller.rbでcreateをしています。controllers/microposts_controller.rbdef create @micropost = current_user.microposts.build(micropost_params) # replyかチェックする if reply_id = @micropost.content.scan(/@\w+/) @micropost.in_reply_to = reply_id[0].slice![0] end if @micropost.save flash[:succsess] = "Micropost created!" redirect_to root_url else @feed_items = [] render 'static_pages/home' end end変更点のテストをどこで書くか
controllerを変更するので、先にtestを書きます。
テスト項目は、replyのmicropostをcreateすると、受信者の件数が1増えることです。
テストをどこで書くかで、integration testとのすみわけを考えます。controllerのテストの例について、tutorialを読み返します。
第13章、第14章のmicropostでは、modelのテストの次はintegrationテストをしていました。
13.3.1でcontrollerのテストの内容は、ログインしているかどうかのテストでした。実際にtestのソースを見てみます。controllersフォルダの下です。いずれもログインしているかどうかや正しいページを表示しているかのテストでした。処理した結果を検証するのはintegrationテストで良いと分かりました。
integrationテストを書いてみます。
test/integration/reply_test.rb REDtest "reply to user " do log_in_as(@user) content = "@#{@other.name} reply test content" post microposts_path, params: { micropost: {content: content }} log_in_as(@other) get root_path assert_not @other.following?(@user) assert_match content, response.body endfixtureのデータでエラー
テストを実行したところ、fixtureのデータでエラーが起きました。
ERROR["test_reply_to_user_", ReplyTest, 0.3831760289999693] test_reply_to_user_#ReplyTest (0.38s) NoMethodError: NoMethodError: undefined method `id' for nil:NilClass test/fixtures/microposts.yml:54:in `get_binding'not foundのようです。
ネットで調べると、fixtureを呼び出す順番に依るためで、外部制約があると
面倒なことになるようです。fixtureでテストデータを作るのではなく、modelのtest内でpostするようにしてみます。
ついでに前にfixtureを作ったときの@replyの仕様の勘違いを修正することにします。
test/models/user_test.rbtest "feed should have the reply posts" do michael = users(:michael) malory = users(:malory) assert_not malory.following?(michael) reply_post = michael.microposts.create!(content: "@malory reply test", in_reply_to: malory.id) assert michael.feed.include?(reply_post) assert malory.feed.include?(reply_post) endこれでテストは通るようになりました。
controllerを変更
controllerを変更します。
controllers/microposts_controller.rbdef create @micropost = current_user.microposts.build(micropost_params) # replyかチェックする if reply_id = @micropost.content.scan(/@\w+/)[0] reply_id.slice!(0) @micropost.in_reply_to = User.find_by(name: reply_id) end if @micropost.save flash[:succsess] = "Micropost created!" redirect_to root_url else @feed_items = [] render 'static_pages/home' end endテストデータを修正
テストデータを直します。姓と名の間にスペースがないuserを作ります。
test/fixtures/users.ymlBob: name: Bob email: bob@example.gov password_digest: <%= User.digest('password') %> activated: true activated_at: <%= Time.zone.now %>間違いの修正
テストがRedのままなので、putsでデバッグしたところ、間違いが分かり修正しました。idが必要でした。
修正前 @micropost.in_reply_to = User.find_by(name: reply_id)
修正後 @micropost.in_reply_to = User.find_by(name: reply_id).idcontrollers/microposts_controller.rbdef create @micropost = current_user.microposts.build(micropost_params) # replyかチェックする if reply_id = @micropost.content.scan(/@\w+/)[0] reply_id.slice!(0) @micropost.in_reply_to = User.find_by(name: reply_id).id end if @micropost.save flash[:succsess] = "Micropost created!" redirect_to root_url else @feed_items = [] render 'static_pages/home' end endこれでテストがGREENになりました。
画面でテストしてみます。
スペースがないユーザーを作り、動くことを確認できました。所要時間
10/11から10/17までの2.5時間です。
- 投稿日:2020-10-28T02:24:31+09:00
to_sメソッドについて。
to_sメソッドの説明
数値が持つメソッドです。数値を文字列に変換してくれます。
ちなみに、 to_sのsの意味は「string(文字列)」です。
以下の例を見てください。【例】irb# 数値「20」にto_sメソッドをつけて実行 irb(main):001:0> 20.to_s => "20"to_sメソッドによって、文字列"20"が実行結果になっています。
それでは、文字列と数値を連結させて、
"i am 20 years old."を表示しましょう。irbで以下のコードを実行しましょう
では、実際にターミナルでto_sメソッドを試してみましょう。
ターミナル# to_sで数値を文字列に変換し、連結 irb(main):001:0> "i am " + 20.to_s + " years old." # 続けてこのように表示されれば成功 => i am 20 years old.「はじめから文字列"20"を用意すればよかったのでは?」と思うかも
しれません。しかし、足し算した結果を文字列として利用したい場合など、
数値を文字列に変換するto_sメソッドを利用する場面は多くあります。
この方法は必ず覚えておきましょう。反対に文字列を数値に変換するメソッドもあります。それがto_iメソッドです。これは文字列がもつメソッドです。
to_iメソッドについては、次回説明させていただきます。まとめ
to_sメソッドとは、数値を文字列に変換するメソッド。
以上。
- 投稿日:2020-10-28T01:17:38+09:00
RSpec Setup
RSpecのセットアップ
参考文献
Everyday Rails - RSpecによるRailsテスト入門
https://leanpub.com/everydayrailsrspec-jp環境 Mac
Ruby 2.4.9
Rails 5.1.1Rspec導入における忘備録である。
RSpecのインストール
GemFileを開き、テスト環境と開発環境で使用可能なように
下記のグループにRSpecを追記する。GemFile.group :development, :test do #追加 バージョン指定は各環境に応じて変更してください。 gem 'rspec-rails', '~> 3.6.0' end下記のコマンドを入力
ターミナル.bin/rails g rspec:installすると下記のフォルダが作成される。
ターミナル.Running via Spring preloader in process 53239 create .rspec create spec create spec/spec_helper.rb create spec/rails_helper.rbこれで準備完了。
お次に、テスト時にターミナルに流れるRSpecの出力を読みやすいドキュメント形式に変更
.rspecに下記を記載する。#デフォルトで記載されている。 --require spec_helper #こっちを追記 --format documentationrspec binstubの導入
binstubとはなんぞや?
アプリケーションの起動を早くすることが可能で、bundle exec ~からbin/~と呼び出しも楽になる便利屋さん。参考URL
https://qiita.com/tanaka51/items/bc22c1c364202d3cce4e開発環境に追記してbundle
GemFile.group :development do gem 'spring-commands-rspec' end続いてターミナルに下記コマンドを打ち込むと、
Railsアプリケーションディレクトリ直下にあるbinディレクトリ内にRSpecが新たに加わる。ターミナル.bundle exec spring binstub rspecここまで完了したら
ターミナル.bin/rspecでテストが走るか確認する。
rspecディレクトリ内のテストを一括で回してくれるので、最高に楽である。
そして、2回目の実行がめちゃくちゃ早い。VSCode民のためのテストプラグイン
これはテストコードを開いてcmd + shift + t でその画面のテストをVSCodeが実行してくれるという便利拡張機能!
かなりオススメ
rails g で一緒にRSpecファイルも作成してもらう
ジェネレーターでアプリケーションにコードを追加する際に一緒にRSpecのテストファイルも作ってもらう。
しかし、使用しないディレクトリ及びテストファイルまで作成されては困るので、同時に、使用しないものを作らない設定も行う。config/application.rb内に追記していく。
config/application.rbmodule Projects class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 5.1 # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. #ここから下を追記 config.generators do |g| #ジェネレート時にRSpecのテストファイルも作成 g.test_framework :rspec, #テストデータベースにレコードを作成するファイルの作成をスキップ fixtures: false, #ビュースペックを作成しないことを指定 view_specs: false, #ヘルパーファイル用のスペックを作成しないことを指定 helper_specs: false, #ルーディング用のスペックファイルの作成を省略 routing_specs: false end #ここまで end endもし手動で追加したいのであれば、
テストしたいファイルのディレクトリ名とファイル名を合わせて作成する
app/helpers/projects_helper.rb をテストするのであれば、spec/helpers/projects_helper_spec.rb を作成する。最後に、Railsがデフォルトで用意してあるテストディレクトリを削除しておきましょう!
ちなみに、RSpecのファイルのみ作成したい場合は下記のジェネレートコマンドを入力すれば、作成される。
下記の場合は、RSpecディレクトリに、modelディレクトリが作成されて、userのRSpecファイルが作成される。spec/models/user_spec.rb
ターミナル.bin/rails g rspec:model user #結果 create spec/models/user_spec.rb今回はここまでにします。
間違い、誤記、ご助言等ございましたらご教授くださると幸いです。
ありがとうございました。