- 投稿日:2021-03-14T23:49:17+09:00
Action Cableでできることと実装方法
Action Cableは、Railsのアプリケーションと同様の記述で、WebSocket通信という双方向の通信によるリアルタイム更新機能を実装できるフレームワークで、Rails5から実装されました。
Action Cableを利用することで、たとえばリアルタイムで更新されるチャット機能を実装することができます。
チャネルの作成
channel
リアルタイム更新機能を実現するサーバー側の仕組みでデータの経路を設定したり、送られてきたデータを画面上に表示させたりします。
チャネルを作成するコマンド
ターミナルrails g channel message #チャネル名 # ↓実行結果↓ Running via Spring preloader in process ***** invoke test_unit create test/channels/message_channel_test.rb create app/channels/message_channel.rb identical app/javascript/channels/index.js identical app/javascript/channels/consumer.js create app/javascript/channels/message_channel.js生成されるファイルのうち以下の2つが重要です。
app/controller/message_controller.rb
→ クライアントとサーバーを結びつけるためのファイル
app/javascript/channels/message_channel.js
→ サーバーから送られてきたデータをクライアントに描画するためのファイルクライアントとサーバーを結びつける
stream_fromメソッド
サーバーとクライアントを関連づけるメソッドでAction Cableにあらかじめ用意されています。
app/controller/messages_controller.rbclass MessageChannel < ApplicationCable::Channel def subscribed stream_from "message_channel" #記述箇所 end def unsubscribed # Any cleanup needed when channel is unsubscribed end endbroadcast
stream_fromメソッドで関連付けられるデータの経路で、サーバーから送られるデータの経路です。broadcastを介してデータをクライアントに送信します。
broadcast
を使ってコントローラーへ以下のように記述します。app/controller/messages_controller.rbclass MessagesController < ApplicationController def new @messages = Message.all @message = Message.new end def create @message = Message.new(text: params[:message][:text]) if @message.save ActionCable.server.broadcast 'message_channel', content: @message end end end
broadcast
という経路を通して、message_channel
に向けて@message
をcontent
に入れてデータを送信しています。JavaScriptへの記述
サーバーから送信されたデータは
data
の中にcontent
という名称で入っているので、data.content.text
で使用できます。app/javascript/channels/message_channel.jsimport consumer from "./consumer" consumer.subscriptions.create("MessageChannel", { received(data) { // 以下で使用 const html = `<p>${data.content.text}</p>`; const messages = document.getElementById('messages'); const newMessage = document.getElementById('message_text'); messages.insertAdjacentHTML('afterbegin', html); newMessage.value=''; } });ちなみにビューはこんな感じです。
app/views/messages/new.html.erb<h3>mini-talk-app</h3> <%= form_with model: @message do |f| %> <%= f.text_field :text %> <%= f.submit '送信' %> <% end %> <div id="messages"> <% @messages.reverse_each.each do |message| %> <p><%= message.id %></p> <p><%= message.text %></p> <% end %> </div>content以外もクライアントに送信できる
app/controller/messages_controller.rb
では保存したメッセージの値をcontent
に入れて送信していましたが、設定すれば他の値も送ることができます。ぼくが今開発しているアプリでは、こんな感じで情報を追加してクライアント側に送信しています。
app/controllers/chats_controller.rbclass ChatsController < ApplicationController def create @chat = Chat.new(chat_params) if @chat.save # userとtimeにそれぞれ@userと@timeを入れている @user = current_user @time = @chat.created_at.strftime("%Y-%m-%-d %-H:%-M") ActionCable.server.broadcast 'chat_channel', content: @chat, user: @user, time: @time end end private def chat_params params.require(:chat).permit(:text).merge( user_id: current_user.id, group_id: params[:group_id] ) end endクライアント(JavaScript)側ではこのようにデータを利用しています。JavaScript側で投稿日時の表示形式を変更する方法が分からなかったので、事前にサーバー(Ruby)側で表示形式を変更してから送信しています。
app/javascript/channels/chat_channel.jsimport consumer from "./consumer" consumer.subscriptions.create("ChatChannel", { received(data) { // 送信されたデータを以下で使用 const html = `<div class="each-chat"> <p class="chat-time">${data.time}</p> <p class="chat-text">${data.content.text}</p> <p class="chat-user">${data.user.name}</p> </div>`; const chats = document.getElementById("chats"); chats.insertAdjacentHTML("afterbegin", html); const newChat = document.getElementById("chat_text"); newChat.value=""; } });参考資料
- 投稿日:2021-03-14T23:23:44+09:00
docker内でGem(特にbundler)のdefault設定を解除したい!
概要
ローカル環境でも厄介なGemのdefault設定。
「このバージョンのGemで運用していきたいのに!」といった気持ちに反して、bundle installすると、default設定されたバージョンでインストールされてしまう。。。ローカル環境ではその解除はできるが、Dockerのコンテナ内では少しだけ訳が違ったので、まとめたいと思い本記事を制作しました。
不足点、誤りがあれば遠慮なくご指摘いただけますと幸いです。
経緯
これまでローカル環境にて開発を行い、いざ本番環境へデプロイ!となるとエラーが返され、苦い思いをしてきた私。
今回はdocker-compose up
で立ち上げたコンテナ内でgem list
を見ると、ローカルでのgem list
とバージョンの違いが生じていました。
そこで、コンテナ内でも指定したバージョンのGemで運用したく奮闘したのが経緯です。方法
①コンテナ内に入る
ローカルにて自身のアプリのディレクトリにて
% docker-compose exec web bash root@コンテナID:/アプリ名# 以降プロンプト以外は省略します②Gemを確認(省略可能)
# gem list bundler ※ちなみに全てのGemをリスト化するには"bundler"を省略 *** LOCAL GEMS *** bundler (2.1.4, default: 1.17.2)**この忌々しいdefaultを解除していきます。
③default設定されているGemのありかを探る。
# gem environment RubyGems Environment: ...略 - INSTALLATION DIRECTORY: /usr/local/bundle - USER INSTALLATION DIRECTORY: /root/.gem/ruby/2.6.0 ...略 - GEM PATHS: - /usr/local/bundle - /root/.gem/ruby/2.6.0 - /usr/local/lib/ruby/gems/2.6.0 ...略ここでちなみにローカルで同様に
gem environment
コマンドを実施した時の結果を下記に記します。% gem environment RubyGems Environment: ...略 - INSTALLATION DIRECTORY: /Users/ユーザー/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0 - USER INSTALLATION DIRECTORY: /Users/ユーザー/.gem/ruby/2.6.0 ...略 - GEM PATHS: - /Users/ユーザー/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0 - /Users/ユーザー/.gem/ruby/2.6.0 ...略INSTALLATION DIRECTORYに注目してください。
指定されているディレクトリがわずかに違います。
⑤の項目にてさらに解説します。④ホームに戻る
# cd root@コンテナID:~#⑤default設定のあるディレクトリまでたどり着く
ここで、ローカル環境でのたどり着き方の場合は、INSTALLATION DIRECTORYに記載されているパスまで
cdコマンド
で行けばいいのですが・・・ローカルの場合!
% cd /Users/ユーザー/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0 ユーザー@PC 2.6.0 %コンテナ内の場合!!
# cd /usr/local/lib/ruby/gems/2.6.0 root@コンテナID:/usr/local/lib/ruby/gems/2.6.0#INSTALLATION DIRECTORYに記載されているパスでは「そんなディレクトリは無い!!」と怒られたので、別のディレクトリを探したところ,
GEM PATHSに記載のあったディレクトリが正解だったようです。⑥specificationsの中のdefaultを削除する
lsコマンド
を使ってみると、このディレクトリの中にspecifications
というディレクトリがあるはずです。
この中にdefault設定があります。
※気になる方はここで、cd specifications
して、lsコマンド
をすると、default
と記載のあるGemがいくつかあると思います。# rm -rf specifications/default/これでspecifications内のdefaultディレクトリが全て削除されます。
⑦念の為、確認。
# gem list bundler *** LOCAL GEMS *** bundler (2.1.4)bundlerのdefaultが解除されています。
ここでbundle installし、Gemfile.lockを確認すると最後の行に・・・BUNDLED WITH 2.1.4と、自分の好きなバージョンでバンドルされていることが確認できました!
考察
ここで学んだことが2つあります。
まず1つ
当然ではありますが、ローカル環境とコンテナ環境は別物。Gemのバージョンの相違に気づけたこと。もう1つ
同じgem environment
に返される結果は、似てこそあれども微妙な違いがあること。
自分の求める情報はどこに記載があるのか注視しなければならない。これまでデプロイの時に何かしらのエラーに叩きのめされていたので、docker使用時に未然にGemのバージョンを合わせれて良かったと思います。
誰かの参考になれば幸いです。
ありがとうございました。
- 投稿日:2021-03-14T19:53:27+09:00
ゲッター・セッター・アクセサメソッド
前提
インスタンス変数はクラスの外から呼び出すことができない
class User def initialize(name) @name = name end end user = User.new('Alice') puts @name => #クラスの外からインスタンス変数を呼び出した為出力されずゲッターメソッドとは
クラス内からインスタンス変数を参照するメソッド
セッターメソッドとは
クラス内からインスタンス変数を更新するメソッド
@nameをクラスの外から参照するためのメソッドを定義してみる(ゲッターメソッド)
class User def initialize (name) @name = name end #ゲッターメソッド def name @name end end user = User.new('Alice') puts user.name => 'Alice'@nameの内容をクラスの外から変更したい場合も変更用のメソッドを定義する(セッターメソッド)
class User def initialize(name) @name = name end # ゲッターメソッド def name @name end # セッターメソッド(rubyでは=で終わるメソッド名を定義すると変数に代入する形式でそのメソッドを呼び出す) def name=(value) @name = value end end user = User.new('Alice') # ↓ここは変数に代入してる訳ではなく、name=というメソッド(セッター)を呼び出してる。また=の前にスペースがあっても使える user.name = 'Bob' puts user.name =>'Bob'アクセサメソッド
上記でやったセッターやゲッターを定義せずに省略することができる
メソッド名 内容 attr_reader: 変数名 参照を可能にする(ゲッター) attr_writer: 変数名 更新を可能にする(セッター) attr_accessor: 変数名 参照と更新両方可能にする(ゲッター・セッター) attr_accessorメソッド
参照と更新両方可能にする(ゲッター・セッター)
class User attr_accessor :name def initialize (name) @name = name end end user = User.new('Alice') #変更 user.name = 'Bob' #参照 puts user.name => 'Bob'attr_readerメソッド
参照できるが変更はできない(ゲッター)
class User attr_reader :name def initialize (name) @name = name end end user = User.new('Alice') #参照は可能 puts user.name => 'Alice' user.name = 'Bob' => 'undefined method `name=' for #<User:0x00007fca8b11eb28 @name="Alice"> (NoMethodError) Did you mean? name'attr_writerメソッド
変更できるが参照できない(セッター)
class User attr_writer :name def initialize (name) @name = name end end user = User.new('Alice') #変更は可能 user.name = 'bob' puts user.name => undefined method `name' for #<User:0x00007fc7c48d87c0 @name="bob"> (NoMethodError) Did you mean? name=まとめ
インスタンス変数はクラスの外から参照することができない
セッターゲッターがあることでクラスの外からインスタンス変数を参照したり更新することができる
アクセサメソッド使うとセッターとゲッターの定義を省略することができる
- 投稿日:2021-03-14T19:47:36+09:00
Rubyにおけるオブジェクト、クラス、インスタンス、メソッド、インスタンス変数とは
※この文章はアウトプットに挑戦した初学者の単なる走り書きです。
タイトル通り、Rubyにおけるオブジェクト、クラス、インスタンス、メソッド、インスタンス変数という言葉がどのような意味を持つのかを記述していきます。プログラミングにおいては何かが何かを包含してピラミッド構造のようなものを構成している点が特徴的だと感じたので、それに着目し、より高次の概念を表す用語が上に来るように書きました。
オブジェクト
Rubyではあらゆる「データ」がオブジェクトです。Rubyのなかでオブジェクトではないものはないと思い込んでいたのですがそれは誤りで、「データ」でないメソッドなどはオブジェクトではありません。
クラス
クラスはオブジェクトを生み出し、オブジェクトの振る舞いを規定するものです。
インスタンス
全てのオブジェクトは何らかのクラスに属します。その際に「所属先」のクラスに対し「所属するオブジェクト」がインスタンスと呼ばれます。
メソッド
メソッドとはオブジェクトについての一連の処理を定義したものです。例として文字列オブジェクトの文字数を返すlengthメソッドなどがあります。メソッドはデータではないため、必然的にオブジェクトではないということになります。
また、メソッドが呼び出されたオブジェクトをそのメソッドのレシーバといいます。インスタンス変数
メソッド内で定義された変数は通常メソッドの外では機能しませんが、@から始まるインスタンス変数なら、クラス内のインスタンスの中でならどこでも使えます。
では結局オブジェクトとは何なのか?
オブジェクトとは何かを理解するには、理屈だけでなく感覚的にオブジェクトを理解することが必要だそうです。自分がその域に達するのはまだ先のように思えますが、今のところオブジェクトとは、自然言語における主語と述語のような相互補完関係をメソッドと築いているものなのかなと思います。(メソッドは繋げられるが自然言語で述語が連続したら文法的におかしいという違いはありますが)
- 投稿日:2021-03-14T18:45:17+09:00
【Rails6】flatpickrのカレンダーを使ってDBにパラメータを保存する方法
flatpickrのカレンダーを使ってDBにパラメータを保存する方法を解説します。
flatpickrのカレンダーを使ってみたけど、DBにパラメータを保存できない。
視覚的にわかりやすいカレンダータイプの日付選択を採用したい。
カレンダーからポチポチして日付を選べるようにしたい。など、ポートフォリオ作成などにも役立つと思い記事にしてみました。
完成後のアプリ
開発環境
・macOS Catalina 10.15.7
・Ruby 2.7.2
・Rails 6.0.3.4
・flatpickr 4.6.9YouTube
・近々YouTubeに動画投稿予定
1. 環境構築
- 以下を前提に進行
- トップページはcalendars#indexの前提で進行
- データベースはPosgreSQL
1.1 アプリの作成
ターミナルrails new flatpickr_sample -d postgresql cd flatpickr_sample
- 今回アプリ名はflatpickr_sampleとします。
- アプリ作成後はcdコマンドで該当アプリのディレクトリに移動することを忘れないようにしましょう。
1.2 gemのインストール
Gemfile# 中略 gem 'bootsnap', '>= 1.1.0', require: false # ***** 以下を追加 ***** # 日本語化 gem 'rails-i18n', '~> 6.0' # ***** 以上を追加 ***** # 中略 group :development do # 中略 # ***** 以下を追加 ***** # デバッグで利用 gem 'pry-byebug' # ***** 以上を追加 ***** endターミナルbundle install rails db:create
- gemの追加後は忘れずbundle installを実行
- その後rails db:createでデータベースを作成
【要確認】ターミナルにてrails sでサーバーを起動して、http://localhost:3000/ に接続して「Yay! You’re on Rails!」が出るか確認しましょう。
1.3 モデル、テーブル、コントローラの作成
ターミナルrails g model Calendar date:date rails db:migrate
- 今回モデル名はCalendar、カラムはdateカラムを使用します。
- rails db:migrateによりテーブルが作成されます。
【要確認】上記コマンドによりapp/models/calendar.rbファイル、db/migrate/..._create_calendars.rbファイル、db/schema.rbファイルが作成されています。
ターミナルrails g controller calendars index new create
- コントローラ名はcalendarsとします。コントローラ名は原則複数形なので注意しましょう。
- rails g controller calendars(コントローラ名) index(コントローラアクション名)で、アクション名のビューファイルも一緒に作成されます。
ターミナルrm -f app/views/posts/create.html.erb
- 今回使用しない不要なファイルをrm -fコマンドで削除しましょう。
1.4 ルーティング設定
config/routes.rbRails.application.routes.draw do root "calendars#index" resource :calendars, only: [:index, :new, :create] end1.5 flatpickrの導入
ターミナルyarn add flatpickr
- yarnを使用してflatpickrを導入します。
- yarnが使用できない場合、先にyarnのインストールをしましょう。
app/assets/stylesheets/application.scss/* ... *= require_tree . *= require_self # ***** 以下を追加 ***** *= require flatpickr # ***** 以上を追加 ***** */
【注意】app/assets/stylesheets/application.cssの拡張子cssをscssに変更するのを忘れずに
app/javascript/packs/application.jsrequire("@rails/ujs").start() require("turbolinks").start() require("@rails/activestorage").start() require("channels") // ***** 以下を追加 ***** require('flatpickr') require('flatpickr/dist/l10n/ja') // ***** 以上を追加 *****app/javascript/packs/calendar.js// ***** 以下を追加 ***** flatpickr.localize(flatpickr.l10ns.ja) const config = { inline: true, } flatpickr('#calendar_form', config); }); // ***** 以上を追加 *****
- app/javascript/packsディレクトリ内にcalendar.jsファイルを作成する。
- 今回id名はcalendar_formとします。上記の5行目の#以降がid名となります。
app/views/layouts/application.html.erb<!DOCTYPE html> <html> <head> <title>FlatpickrSample</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> <!-- ***** 以下を追加 ***** --> <%= javascript_pack_tag 'calendar', 'data-turbolinks-track': 'reload' if controller_name == 'calendars' %> <!-- ***** 以上を追加 ***** --> </head> <body> <%= yield %> </body> </html>
- 上記の追加は、コントローラ名がcalendarsと時のみ、packs内のcalendar.jsに対してターボリンクスをするという記述になります。
2 パラメータをDBに保存する
2.1ビューファイルの編集
app/views/calendars/new.html.erb<!-- ***** 以下を追加 ***** --> <%= form_with model: @calendar do |form| %> <input id ="calendar_form" type="text" name="calendar[date]" readonly="readonly" > <%= form.submit "送信" %> <% end %> <!-- ***** 以上を追加 ***** -->
- dateカラムのパラメータを保存するためにヘルパーメソッドのform_withを使用します。
- app/javascript/packs/calendar.js内で設定したid名と、上記2行目のinput id ="id名"を一致させることでflatpickrのカレンダーを呼び出します。
app/views/calendars/index.html.erb<!-- ***** 以下を追加 ***** --> <%= link_to "日付投稿ページへ", new_calendars_path %> <h1>日付一覧</h1> <% @calendars.each do |calendar| %> <%= calendar.date %> <% end %> <!-- ***** 以上を追加 ***** -->・上記はカレンダーで送信されたパラメータを一覧表示するための記述です。
2.2 コントローラの編集(index,new,create)
app/controllers/calendars_controller.rbclass CalendarsController < ApplicationController def index # ***** 以下を追加 ***** @calendars = Calendar.order(id: :asc) # ***** 以上を追加 ***** end def new # ***** 以下を追加 ***** @calendar = Calendar.new # ***** 以上を追加 ***** end def create # ***** 以下を追加 ***** save_params = params[:calendar][:date].to_date Calendar.create!(date: save_params) redirect_to root_path # ***** 以上を追加 ***** end end
- 結論から言うと、上記のコードを追加したらパラメータがDBへ保存されます。なぜ保存できたかを次に詳しく説明します。
2.3 なぜそのままではパラメータが保存できないのか
app/controllers/calendars_controller.rbclass CalendarsController < ApplicationController def index @calendars = Calendar.order(id: :asc) end def new @calendar = Calendar.new end def create # ***** 以下を追加 ***** binding.pry # ***** 以上を追加 ***** save_params = params[:calendar][:date].to_date Calendar.create!(date: save_params) redirect_to root_path end end【確認手順】
1. binding.pryを上記の位置に追加する。
2. ターミナルにてrails sでサーバーを起動して、http://localhost:3000/ に接続する。
3. カレンダーから適当な日付を選択して送信する。
4. 下記のように処理が止まったのを確認し、paramsと入力する。送信されたパラメータの中身を確認できます。
ターミナル10: def create 11: binding.pry => 12: save_params = params[:calendar][:date].to_date 13: Calendar.create!(date: save_params) 14: redirect_to root_path 15: end [1] pry(#<CalendarsController>)> params => <ActionController::Parameters {"authenticity_token"=>"0E0nP7UnRkkg+4ZL2h7vZ160OkJP0NAQEkNaYF4nAC5+KH6JKSOKkN6rMB0y4eMthFRZIYGtBHHOLIOTCf5ekg==", "calendar"=>{"date"=>"2021-03-09"}, "commit"=>"送信", "controller"=>"calendars", "action"=>"create"} permitted: false> [2] pry(#<CalendarsController>)>
- 上記の青字のコードがカレンダーから送られたパラメータになります。不要な部分が多いことがわかります。必要な部分は"calendar"=>{"date"=>"2021-03-09"}部分のみになります。
ターミナル[2] pry(#<CalendarsController>)> params[:calendar] => <ActionController::Parameters {"date"=>"2021-03-09"} permitted: false>
- params[:calendar]と入力することで青字の"date"=>"2021-03-09"が抽出できました。ですが、まだ保存できる形ではありません。
ターミナル[4] pry(#<CalendarsController>)> params[:calendar][:date] => "2021-03-09"
- params[:calendar][:date]と入力することで青字の"2021-03-09"が抽出できました。これで保存されそうな気がしますが、これでは文字列扱いなので保存ができません。
ターミナル[6] pry(#<CalendarsController>)> params[:calendar][:date].to_date => Wed, 03 Mar 2021
- params[:calendar][:date].to_dateとすることで=> Wed, 03 Mar 2021という結果となりました。to_dateメソッドを使うことでdateカラムに保存されるようにうまいこと変換してくれます。
save_params = params[:calendar][:date].to_date Calendar.create!(date: save_params)
- 最後にparams[:calendar][:date].to_dateを変数save_paramsにして、Calendar.create!(date: save_params)でdateカラムに該当する日付を保存します。
3 まとめ
flatpickrのカレンダーを利用した場合、コントローラのcreateアクションでパラメータを以下のようにする必要があります。これでDBに保存できるようになりました。
save_params = params[:calendar][:date].to_date Calendar.create!(date: save_params)flatpickrにBootstrapを適応させてキレイに作成したり、日付を複数選択できるようにする方法を追い追い追記していきます。ここまでお疲れさまでした。
- 投稿日:2021-03-14T16:26:37+09:00
サーバーの構築からソースコードのデプロイまで(Amazon Linux 2, Nginx + Puma, Rails 6.1, Ruby2.7.2)
この記事での注意
この作業はローカル環境からの作業とサーバーでの作業が複雑に入り交じっています。その為、ターミナルで実行するコマンドの説明に「ローカル」「サーバー」と記載しています。お間違えないように気をつけてください。
アプリケーション名を「sample611」 としています。ご自身のアプリケーション名に読み替えてご参考ください。
サーバーにインストールする環境
- Amazon Linux 2
- Ruby 2.7.2 (rbenv)
- Rails 6.1
- MySQL or PostgreSQL
- Nginx + Puma 5
- Node.js 12
- Yarn
本番サーバーの構築
本番サーバーのEC2のOSがAmazon Linux2の場合の設定手順を紹介します。
1. システムライブラリアップデート
まずはAmazon Linux 2のシステムライブラリを更新します。
サーバー$ sudo yum update -y2. タイムゾーン、ロケール
日本での運用する場合はタイムゾーンと言語の設定を日本にした方がわかりやすいと思います。
サーバー$ sudo timedatectl set-timezone Asia/Tokyo $ sudo localectl set-locale LANG=ja_JP.UTF-83. NTP
サーバーの時刻のずれを自動で補正するタイムサーバーの設定を行います。
サーバー$ yum info chrony $ chronyc sources -v4. 標準パッケージインストール
Rubyのインストールなどで必要になるライブラリをインストールします。
サーバー$ sudo yum -y install gcc-c++ glibc-headers openssl-devel readline libyaml-devel readline-devel zlib zlib-devel libffi-devel libxml2 libxslt libxml2-devel libxslt-devel git5. データベースモジュールのインストール
Railsからデータベースにアクセスするためのアダプタをインストールする必要がありますが、そのインストールに必要なライブラリをデータベース別にインストールします。
- PostgreSQLの場合
サーバー$ sudo yum -y install postgresql-devel
- MySQLの場合
サーバー$ sudo yum -y install mysql-devel6. Rubyのインストール
Railsを動かすためにはRubyのインストールが必要です。いろんなインストール方法がありますが、Rubyのバージョンを切り替えることができるrbenvを使った方法を説明します。
6.1 rbenvのインストール
サーバー$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile $ source ~/.bash_profile $ rbenv -v6.2 ruby-buildのインストール
サーバー$ git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build $ cd ~/.rbenv/plugins/ruby-build $ sudo ./install.sh $ rbenv install -l6.3 Rubyのインストール
rbenvとruby-buildをインストールが終わったので、Rubyのインストールを行います。
サーバー$ rbenv install 2.7.2 $ rbenv global 2.7.2rubyのインストールにはすこし時間がかかります。
rbenv globalでシステム全体で使用するRubyのバージョンを指定しています。7. Rails 6で必要なモジュールのインストール
7.1 Node.jsのインストール
Rails 6からは Node.js や Yarn が必要になりました。Node.jsはサーバーサイドでのJavaScript実行環境で、Yarnはfacebook製のJavaScriptのパッケージマネージャーです。
サーバー$ curl -sL https://rpm.nodesource.com/setup_14.x | sudo bash - $ sudo yum install -y nodejs $ sudo npm install -g n $ sudo n stable $ sudo ln -snf /usr/local/bin/node /usr/bin/node7.2 Yarnのインストール
サーバー$ curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo $ sudo yum install yarn -y8. Railsのインストール
Rails 6のインストールを行います。gem install railsでもインストールできますが、ここではパッケージ管理ソフトbundlerからインストールする方法を紹介します。
サーバー$ cd ~ $ mkdir rails $ cd rails $ bundle init $ vim Gemfile (gem "rails"をコメントアウト解除) $ bundle install $ bundle exec rails -v (インストールされたことを確認) $ cd .. $ rm -rf railsデータベースの設定
9. 本番データベースの作成
ここではRDSの設定については詳しく説明しません。すでにRDSにデータベースが設定されていることを前提に進めていきますが、下記をご確認ください。
- RDSにて作成したデータベースのユーザー名、パスワード、データベースエンドポイントをご確認ください。
- RDSのセキュリティグループでウェブサーバーとなるEC2のセキュリティグループのアクセス許可を設定してください。
10. Railsアプリと本番データベースの接続設定
Railsとデータベースの接続設定を行います。データベースの設定にはデータベースにアクセスするためのパスワードが含まれますが、これを直接database.ymlに記載すると、github上でパスワードを知ることができてしまい危険です。
こういった機密情報は config/credentials.yml.enc にセットします。(Rails5.2以降で可能)
このファイルはエディタで表示すると暗号化された文字列になっていますが、 master.key を使うことで閲覧、編集することができます。この credentials.yml.enc と master.key の関係を理解しておいてください。
次のコマンドでcredentials.yml.encを編集します。ここではエディタをvimに指定しています。
ローカル$ EDITOR=vim bin/rails credentials:edit下記のようにdbの項目を追記し、RDS作成時に設定したユーザー名、パスワード、データベースエンドポイントを記述します。
credential.yml.enc(ローカル)# aws: # access_key_id: 123 # secret_access_key: 345 # Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies. secret_key_base: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx db: username: (username) password: (password) host: (database endpoint)終わったら、:wqでエディタを終えます。
次に本番環境において、データベースの設定が適用されるようconfig/database.ymlを編集します。database.ymlの最後の方にproductionの項があります。そこを下記のように修正します。
database.yml(ローカル)production: <<: *default database: sample611_production username: <%= Rails.application.credentials.db[:username] %> password: <%= Rails.application.credentials.db[:password] %> host: <%= Rails.application.credentials.db[:host] %> port: 5432Rails.application.credentials.dbとすることでcredentials.yml.encのdbの項を読みにいきます。
portはデータベースで使用するポートを指定します。一般的にはPostgreSQLの場合は 5432、MySQLの場合は 3306 になります。ここで、改修したコードをいったんコミットし、githubへプッシュしましょう。
ローカル$ git add . $ git commit -m "Setup database" $ git push origin masterデプロイ設定
デプロイツールCapistranoを使ったデプロイの設定を行います。
11. Capistranoのインストール
Capistranoをインストールします。下記のようにGemfileのdevelopmentグループにcapistrano, capistrano-rails, capistrano-rbenvを追加し、bundle installします。
Gemfile(ローカル)group :development do gem "capistrano", "~> 3.14", require: false gem "capistrano-rails", "~> 1.6", require: false gem 'capistrano-rbenv', '~> 2.2' endローカル$ bundle install $ bundle exec cap install12. Capfileの設定
下記のようにCapfileに追記します。
Capfile(ローカル): # require "capistrano/rails/migrations" # require "capistrano/passenger" require 'capistrano/rails' require 'capistrano/rbenv' :13. デプロイの設定
Capistranoのデプロイ設定を行います。全体的なデプロイの設定を「config/deploy.rb」、本番環境用の設定を「config/deploy/production.rb」に記述します。
config/deploy.rb(ローカル)lock "~> 3.15.0" set :application, "sample611" # 自分のリポジトリを設定 set :repo_url, "git@github.com:yukeippi/sample611.git" # rbenvの設定 set :rbenv_type, :user set :rbenv_ruby, '2.7.2' # Railsアプリの設置先 set :deploy_to, "/var/rails/sample611" # 共有ファイルの設定 append :linked_files, "config/master.key" # 共有ディレクトリの設定 append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system" # リリース保存数 set :keep_releases, 5linked_filesはデフォルトではconfig/database.ymlとなっていますが、config/master.keyに変更してください。
次にconfig/deploy/production.rbを編集します。下記の (server ip) にはデプロイ先EC2のIPをセットしてください。
githubへのキー登録については下記をご参照ください。config/deploy/production.rb(ローカル)set :rails_env, 'production' set :branch, 'master' # githubへの設定 set :ssh_options, { auth_methods: [ 'publickey' ], keys: [ '~/.ssh/aws.pem' ], } server '(server IP)', user: 'ec2-user', roles: %w{app db web}区切りが良いので、ここでいったんコミット、プッシュしましょう。(プッシュは任意です)
ローカル$ git add . $ git commit -m "Setup capistrano" $ git push oririn master14. Githubへのキー登録
デプロイ時にデプロイ先サーバーがgithubからソースコードを取得するための設定を行います。
この設定は下記の記事をご参照ください。
15. デプロイ先ディレクトリの作成
Railsアプリのプログラムの設置(デプロイ)を行います。アプリケーションの設置場所を「/var/rails」、実行者を「ec2-user」とした場合、下記のコマンドを実行し、ディレクトリを作ります。
サーバー$ cd /var/ $ sudo mkdir rails $ sudo chown ec2-user:ec2-user railsここで「cap deploy:check」を実行しますが、下記のように失敗します。この処理の目的は、Capistranoにデプロイに必要なディレクトリを作らせることです。
ローカル$ bundle exec cap production deploy:check 00:02 deploy:check:make_linked_dirs 01 mkdir -p /var/rails/sample611/shared/config ✔ 01 ec2-user@(server IP) 0.078s 00:02 deploy:check:linked_files ERROR linked file /var/rails/sample611/shared/config/master.key does not exist on (server IP)エラーメッセージにあるように「master.key」がないことが原因です。サーバーに入って下記のようにmaster.keyを作成してください。
サーバー$ cd /var/rails/sample611/shared/config/ $ vim master.key (ローカルにあるmaster.keyを貼り付け)これで問題は解決しましたので、再度、デプロイチェックを行います。
ローカル$ bundle exec cap production deploy:check成功するはずです。これでデプロイ先ディレクトリができました。
16. Databaseのcreate
しかし、まだこの時点でもデプロイ途中で失敗します。それはデータベースがcreateされていないからです。deployでデータベースのmigrateは実行しますが、createしていないため、migrateできずに失敗してしまいます。
そこで、失敗前提でデプロイを実行し、そのときにデプロイされたソースコードを使ってcreateします。
ローカル$ bundle exec cap production deploy最初はgemをインストールするため、時間がかかります。
しばらく待つとデプロイは終わり、途中で失敗していることが確認できます。その後、本番サーバーに入り、下記のようにデプロイされたソースコードのルートに移動し、データベースを作成します。サーバー$ cd /var/rails/sample611/releases/(最新リリース)/ $ bundle exec rails db:create RAILS_ENV=production(最新リリース)は「20210216104333」といったディレクトリ作成日時を意味するディレクトリを指します。ソースコードがデプロイされると、Capistranoがこのようなディレクトリを作成し、そこにプログラムを保存します。
これでデータベースが作成されたら、デプロイが可能になります。
再度デプロイします。ローカル$ bundle exec cap production deployこれで成功するはずです。
WebサーバーとRailsアプリの連携
17. Pumaの設定
本番環境のPumaの設定を行います。
config/puma/production.rb(ローカル)# Puma can serve each request in a thread from an internal thread pool. # The `threads` method setting takes two numbers: a minimum and maximum. # Any libraries that use thread pools should be configured to match # the maximum value specified for Puma. Default is set to 5 threads for minimum # and maximum; this matches the default thread size of Active Record. # max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } threads min_threads_count, max_threads_count # Specifies the `port` that Puma will listen on to receive requests; default is 3000. # port ENV.fetch("PORT") { 3000 } # Specifies the `environment` that Puma will run in. # environment ENV.fetch("RAILS_ENV") { "production" } # Specifies the `pidfile` that Puma will use. # pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } # Specifies the number of `workers` to boot in clustered mode. # Workers are forked web server processes. If using threads and workers together # the concurrency of the application would be max `threads` * `workers`. # Workers do not work on JRuby or Windows (both of which do not support # processes). # # workers ENV.fetch("WEB_CONCURRENCY") { 2 } # Use the `preload_app!` method when specifying a `workers` number. # This directive tells Puma to first boot the application and load code # before forking the application. This takes advantage of Copy On Write # process behavior so workers use less memory. # # preload_app! # Allow puma to be restarted by `rails restart` command. plugin :tmp_restart bind "unix:///var/rails/sample611/shared/tmp/sockets/puma.sock"RAILS_ENVをproductionに指定しているところと、最下行でsocketを指定しているのがポイントです。
ここでいったんコミット、プッシュしてください。
ローカル$ git add . $ git commit -m "Setup puma for production" $ git push origin master18. Nginxのインストール
ここからはサーバーでの作業になります。
サーバーにNginxをインストールします。サーバー$ sudo amazon-linux-extras install nginx1 -y19. NginxとPumaの紐付け
次にNginxとPumaを紐付けるための設定ファイルを作成します。ポイントはuptreamの設定、rootの指定、proxy_passの指定です。
サーバー$ sudo vim /etc/nginx/conf.d/sample611.conf/etc/nginx/conf.d/sample611.conf(サーバー)upstream puma { server unix:///var/rails/sample611/shared/tmp/sockets/puma.sock fail_timeout=0; } server { listen 80; server_name example.com; root /var/rails/sample611/current/public; try_files $uri/index.html $uri @railsapp; location @railsapp { proxy_pass http://puma; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; } error_page 500 502 503 504 /500.html; client_max_body_size 4G; keepalive_timeout 10; }upstream puma内にあるpuma.sockのパスに気をつけてください。これは15のbindで設定したパスにあわせなければなりません。
20. Pumaのサービス設定
次にpumaをsystemctlで起動や再起動ができるように設定を行います。
サーバー$ sudo vim /etc/systemd/system/puma.service/etc/systemd/system/puma.service(サーバー)[Unit] Description=Puma HTTP Server After=network.target [Service] Type=simple Environment="RAILS_ENV=production" WorkingDirectory=/var/rails/sample611/current ExecStart=/home/ec2-user/.rbenv/shims/bundle exec /var/rails/sample611/shared/bundle/ruby/2.7.0/bin/puma -C /var/rails/sample611/current/config/puma/production.rb Restart=always [Install] WantedBy=multi-user.targetここでpumaの実行パスや実行時の設定ファイルを指定しています。
あと、このままでは実行権限がないため、下記のコマンドでpuma.serviceに実行権限を付与してください。サーバー$ sudo chmod +x /etc/systemd/system/puma.serviceこれでサーバー側の設定は終わりです。
21. Puma, Nginxの起動
いよいよウェブサーバー、アプリケーションサーバーの起動です。まず、Pumaを起動します。
サーバー$ sudo systemctl daemon-reload $ sudo systemctl start puma下記のコマンドで起動を確認します。
サーバー$ sudo systemctl status puma ● puma.service - Puma HTTP Server for sample611 (production_mysql) Loaded: loaded (/etc/systemd/system/puma.service; enabled; vendor preset: disabled) Active: active (running) since 土 2021-02-20 15:47:30 JST; 27min ago Main PID: 2876 (bundle) CGroup: /system.slice/puma.service └─2876 puma 5.1.1 (tcp://0.0.0.0:3000,unix:///var/rails/sample611/shared/tmp/sockets/puma.sock) [20210216072308]上記のようになければ「Active: active」になっていれば、起動成功です。
もし「Active: inactive」になっていれば、何かしらの設定に間違いがある可能性があります。
journalctl -xe等を使って原因を調べてください。次にnginxの起動します。
サーバー$ sudo systemctl start nginx.serviceこれでブラウザを使って下記のようにサイトにアクセスすれば画面に表示されるはずです。
http://(サイトのIP)/
21. デプロイ時のリスタート設定
プログラムをデプロイしたときはアプリケーションサーバーをリスタートする必要があります。capistranoのrestartタスクを追加しておくと、それも自動で実行してくれます。
config/deploy.rb(ローカル)namespace :deploy do task :restart do on roles(:web), in: :sequence, wait: 5 do within release_path do execute "sudo systemctl daemon-reload" execute "sudo systemctl restart puma" end end end after :finishing, :restart endこれでローカル側のコード改修が終わりです。
最後にここまでをコミットしましょう。ローカル$ git add . $ git commit -m "Setup restart puma"再起動することを確認するため、デプロイします。
ローカル$ bundle exec cap production deploy : 00:34 deploy:cleanup Keeping 5 of 6 deployed releases on (server IP) 01 rm -rf /var/rails/sample611/releases/20210314010936 ✔ 01 ec2-user@(server IP) 0.797s 00:35 deploy:restart 01 sudo systemctl daemon-reload ✔ 01 ec2-user@(server IP) 0.199s 02 sudo systemctl restart puma ✔ 02 ec2-user@(server IP) 0.094s 00:35 deploy:log_revision 01 echo "Branch master (at 0e3b185044e3a56f20a3bf37d7c6ce31f5a92b54) deployed as release 20210314015609 b… ✔ 01 ec2-user@(server IP) 0.119sデプロイログからrestartが実行されていることがわかると思います。
これでデプロイは成功です!お疲れ様でした。puma, nginxの自動起動設定
最後にpuma,nginxの自動起動設定を行っておくとよいでしょう。これを行うことでサーバーを再起動しても自動でWebアプリケーションを起動してくれます。
サーバー$ sudo systemctl enable puma.service $ sudo systemctl enable nginx.service以上です。
- 投稿日:2021-03-14T16:11:45+09:00
エスケープシーケンスでターミナルにカラー表示するチートシート
こんなふうにテキストに色や下線を付けてターミナルで表示させるには、
Rubyなら
\e[...m
でputs("ABC\e[4;31;44mDEF\e[0mGHI") puts("ABC\e[38;5;45mDEF\e[0mGHI")Perlなら
\e[...m
でprint "ABC\e[4;31;44mDEF\e[0mGHI\n"; print "ABC\e[38;5;45mDEF\e[0mGHI\n";PHPなら
\e[...m
でprint("ABC\e[4;31;44mDEF\e[0mGHI\n"); print("ABC\e[38;5;45mDEF\e[0mGHI\n");Bashなら
\e[...m
でecho -e "ABC\e[4;31;44mDEF\e[0mGHI" echo -e "ABC\e[38;5;45mDEF\e[0mGHI"Pythonなら
\x1b[...m
でprint("ABC\x1b[4;31;44mDEF\x1b[0mGHI"); print("ABC\x1b[38;5;45mDEF\x1b[0mGHI")Node.jsなら
\x1b[...m
でconsole.log("ABC\x1b[4;31;44mDEF\x1b[0mGHI"); console.log("ABC\x1b[38;5;45mDEF\x1b[0mGHI");Scalaなら
\u001b[...m
でprintln("ABC\u001b[4;31;44mDEF\u001b[0mGHI"); println("ABC\u001b[38;5;45mDEF\u001b[0mGHI");Javaなら
\033[...m
または\u001b[...m
でSystem.out.println("ABC\033[4;31;44mDEF\033[0mGHI"); System.out.println("ABC\033[38;5;45mDEF\033[0mGHI");
[
とm
の間の数字が色や装飾を表すパラメータです。パラメータが複数の場合はセミコロンで区切ります。上記サンプルであれば4は下線、31は赤文字、44は青背景、0はリセットです。
\e[4;31;44m
は\e[4m\e[31m\e[44m
としても同じです。38と48は、セミコロン区切りで続くパラメータが必須で、詳細な色を指定できます。
装飾
パラメータ 効果 Windows Terminal Windows Tera Term Mac Terminal 1 太字(Bold) ○ △ ○ 2 細字(Faint, light font weight) ○ × ○ 3 斜体(Italic) △ △ △ 4 下線(Underline) ○ ○ ○ 5 点滅(Blink) ○ △ ○ 6 速い点滅(Rapid blink) × × × 7 背景色と文字色を入れ替える ○ ○ ○ 8 文字を隠す(Conceal) ○ × ○ 9 取り消し線(Strike) ○ × × ○:対応していそう
△:エスケープシーケンスに反応して変化はしているが、思ってたのとちがう
×:非対応8の文字を隠す効果は、対応している端末では、文字は見えませんが、マウスで選択すると文字が現れ、テキストをコピーできます。tmuxでもテキストをコピーできます。
Windows Terminal
WindowsのTera Term
MacのTerminal
色
色 標準の8色 明るい8色 256色 RGB 文字色 30~37 90~97 38;5;n 38;2;r;g;b 背景色 40~47 100~107 48;5;n 48;2;r;g;b 8色は下1桁で次の色を表します。
0 1 2 3 4 5 6 7 黒 赤 緑 黄 青 紫 水 白 256色のnは0~255の範囲で指定します。nを0~7にすると標準の8色と同じ色で、8~15にすると明るい8色と同じ色になります。
RGBのr, g, bの箇所も0~255の範囲で指定します。
WindowsのTera Termでは8色までしか対応していないようです。Windows TerminalとMacのTerminalは、256色もRGB指定も機能するようです。
Windows Terminal
WindowsのTera Term
MacのTerminal
リセット
パラメータ 効果 0 リセット 色や装飾の指定をすべて解除します。
この0は省略できます。Rubyなら
\e[m
でリセットになります。サンプルコード
この記事の装飾と色のサンプル出力に使ったコードは以下です。Rubyです。
puts() def showcase1(str, text) "\e[#{str}m\\e[#{str}m#{text}\e[0m " end def showcase2(str) "\e[#{str}m\\e[#{str}m" + (" " * (8 - str.length)) + "\e[0m " end def showcase3(str, text) "\e[#{str}m#{text}\e[0m" end line = " " (1..9).each do |i| line += showcase1("#{i}", "いろは") end puts(line) puts() line1 = " " line2 = " " (0..7).each do |i| line1 += showcase2("#{30+i}") line2 += showcase2("#{40+i}") end puts(line1) puts(line2) line1 = " " line2 = " " (0..7).each do |i| line1 += showcase2("#{90+i}") line2 += showcase2("#{100+i}") end puts(line1) puts(line2) puts() (0..256).each do |i| if i % 8 == 0 line1 = " " line2 = " " end line1 += showcase2("38;5;#{i}") line2 += showcase2("48;5;#{i}") if i % 8 == 7 puts(line1) puts(line2) end end puts() (0..256).each do |i| if i % 64 == 0 line1 = " " end line1 += showcase3("48;2;0;255;#{i}", " ") if i % 64 == 63 puts(line1) end end puts()※エスケープシーケンスは、ほかにもカーソル移動や画面のクリアなどもできますが、本稿では色やテキストの装飾にとどめておきます。
- 投稿日:2021-03-14T15:22:51+09:00
プログラミング初学者がLINE-botを作ってみた
概要
私事ですが、全く天気予報を見ないです。
そのため朝に雨が降っていなければ傘を持っていかず、毎回コンビニで傘を買ったり、雨に打たれながら帰宅することが多々あります。
そこで!傘代の節約、これ以上家に傘を増やさないためにも、自分用に朝7時に傘が必要か通知してくれて、こちらが「明日・明後日・今日・などなど」と入力すればその日に雨が降るかを返してくれるLINE Botを実装してみました。手順
・事前にRailsの環境を整える
新規Railsアプリケーションの作成「rails new」コマンドを実行$ rails new アプリケーション名作成されたディレクトリ(フォルダ)に移動
$ cd 作成されたディレクトリ名Gemfileの一番下に以下のコードを追加
gem ' dotenv-rails ' gem 'line-bot-api' #dotenv-railsは環境変数を扱うために使用するgem以下のコマンドでGemをインストール
$bundle installUserモデルを作成
$ rails generate model モデル名 カラム名:データ型上記のコマンドで新しくマイグレーションファイルも作成される。このマイグレーションファイルを以下のように編集
class CreateUsers < ActiveRecord::Migration[5.2] def change create_table :users do |t| t.string :line_id, null: false # この行を修正 t.timestamps end end end以下のコマンドでデータベース・テーブルを作成
$ bundle exec rails db:create $ bundle exec rails db:migrate新規作成されたファイルを編集
lib/tasks/scheduler.raketask :update_feed => :environment do require 'line/bot' # gem 'line-bot-api' require 'open-uri' require 'kconv' require 'rexml/document' #line-bot側の設定 client ||= Line::Bot::Client.new { |config| config.channel_secret = ENV["LINE_CHANNEL_SECRET"] config.channel_token = ENV["LINE_CHANNEL_TOKEN"] } # 使用したいxmlデータURLを入力 # xmlデータをパース # パスの共通部分を変数化 # 6時〜12時の降水確率 # メッセージを発信する降水確率の下限値の設定 min_per = 20 if per06to12.to_i >= min_per || per12to18.to_i >= min_per || per18to24.to_i >= min_per word1 = ["テキスト入力",].sample word2 = ["テキスト入力"].sample # 降水確率によってメッセージを変更する閾値の設定。 #ifの条件式の中で降水確率によって送信されるメッセージを変更 mid_per = 50 if per06to12.to_i >= mid_per || per12to18.to_i >= mid_per || per18to24.to_i >= mid_per word3 = "テキスト入力" else word3 = "テキスト入力!" end # 発信するメッセージの設定 push = "#{word1}\n#{word3}\n降水確率\n 6〜12時 #{per06to12}%\n 12〜18時 #{per12to18}%\n 18〜24時 #{per18to24}%\n#{word2}" # メッセージの発信先idを配列で渡す必要があるため、userテーブルよりpluck関数を使ってidを配列で取得。 #multicastsメソッドは、今回利用しているgem「line-bot-api」で定義されており、このメソッドを呼び出している user_ids = User.all.pluck(:line_id) message = { type: 'text', text: push } response = client.multicast(user_ids, message) end "OK" end以下のコマンドでコントローラの作成
$ bundle exec rails g controller linebot作成されたコントローラーの編集
app/controller/linebot_controller.rbclass LinebotController < ApplicationController require 'line/bot' # gem 'line-bot-api' require 'open-uri' require 'kconv' require 'rexml/document' def callback body = request.body.read signature = request.env['HTTP_X_LINE_SIGNATURE'] unless client.validate_signature(body, signature) return head :bad_request end events = client.parse_events_from(body) events.each { |event| case event # メッセージが送信された場合の対応を入力 # ユーザーからテキスト形式のメッセージが送られて来た場合の対応を入力 when /.*(明日|あした).*/ # info[2]:明日の天気 per06to12 = doc.elements[xpath + 'info[2]/rainfallchance/period[2]'].text per12to18 = doc.elements[xpath + 'info[2]/rainfallchance/period[3]'].text per18to24 = doc.elements[xpath + 'info[2]/rainfallchance/period[4]'].text if per06to12.to_i >= min_per || per12to18.to_i >= min_per || per18to24.to_i >= min_per push = "テキスト\nテキスト\n降水確率\n 6〜12時 #{per06to12}%\n 12〜18時 #{per12to18}%\n 18〜24時 #{per18to24}%\nテキスト" else push = "テキスト" end # テキスト以外(画像等)のメッセージが送られた場合 else push = "テキスト" end message = { type: 'text', text: push } client.reply_message(event['replyToken'], message) # LINEお友達追された場合 when Line::Bot::Event::Follow # 登録したユーザーのidをユーザーテーブルに格納 line_id = event['source']['userId'] User.create(line_id: line_id) # LINEお友達解除された場合 when Line::Bot::Event::Unfollow # お友達解除したユーザーのデータをユーザーテーブルから削除 line_id = event['source']['userId'] User.find_by(line_id: line_id).destroy end } head :ok end private def client @client ||= Line::Bot::Client.new { |config| config.channel_secret = ENV["LINE_CHANNEL_SECRET"] config.channel_token = ENV["LINE_CHANNEL_TOKEN"] } end end記号の意味
・「.」:何か1文字(「あ」や「a」など1文字なら何でもヒットします)
・「*」:直前の文字が0回以上繰り返す場合にマッチ
ルーティングの設定
メッセージが来た時、友達追加された時、解除がされた時に、linebotコントローラのcallbackアクションが呼ばれるようにしています。config/routes.rbRails.application.routes.draw do post '/callback' => 'linebot#callback' endこの後、お好きなレンタルサーバー、共有サーバーでデプロイ
(私はHerokuでデプロイしました)
こちらの
LINE Botアカウント作成・設定
をして完成!!
- 投稿日:2021-03-14T14:40:46+09:00
オプション引数の使い方と機能について
はじめに
オプション引数の使い方と機能について説明します。
オプション引数とは
使い方:(** 引数) ←引数の前に" ** "をつけます。
オプション引数は、引数としてハッシュしか受け取れないようにする働きがあります。
使用する目的としては、間違ってハッシュ以外の引数を渡したときに、エラーが出るようにするためです。
(データの整合性を保つためにオプション引数で記述する)処理の流れ
newメソッドよってinitializeメソッドが呼び出され、ハッシュの引数(name: "山田太郎")が(**params)に渡されます。
そして @name = params[:name]によって、@nameに"山田太郎"が代入されます。
同時にこのとき、Personクラスがインスタンス化されます。次にperson.introductionによってintroductionメソッドが呼び出され
puts "私の名前は#{name}です。"の#{name}に"山田太郎"が代入されてputsが出力されます。class Person attr_reader :name # (**params)と書いてオプション引数を使用し、ハッシュしか受け取れないようにしている def initialize(**params) @name = params[:name] end def introduction puts "私の名前は#{name}です。" end end #ハッシュ(name: "山田太郎" )をinitializeメソッドに渡している person = Person.new(name: "山田太郎" ) person.introduction #出力結果 私の名前は山田太郎です。ちなみに
オプション引数を使用した状態で引数をハッシュ以外にした場合、下記エラーが発生します。
#変更前 person = Person.new(name: "山田太郎" ) #変更後 person = Person.new("山田太郎" ) #変更後の出力結果 `initialize': wrong number of arguments (given 1, expected 0) (ArgumentError)最後に
今回は、オプション引数について説明させていただきました。
データの整合性を保つことを意識して、今後使用していきたいと思います。
ありがとうございまいした。
- 投稿日:2021-03-14T13:54:38+09:00
postとgetの違いについて
はじめに
sinatraを使ってformから得た値を出力する、という処理について、getだけを使った処理とpostを使った処理を両方行ったので、両者の違いを記事にまとめます。
getとpostって何?
getとpostはどちらも代表的なHTTPリクエストのメソッドです。
HTTPとは、Webサイトを表示する際に使用するプロトコルで、クライアントとサーバー間でのWebページの送受信で使用されます。
クライアントがgetやpostなどのリクエストをサーバーへ投げることで、Webサーバーがクライアントにレスポンスを返す、という仕組みになっており、私たちがブラウザで単語を検索する時にも、無意識のうちにgetやpostを使ってリクエストを投げています。行った処理
・formに名前を入力して送信
・~~/hello というurlに「こんにちは、 <名前>さん。」と表示getについて
getでは、urlで指定したファイルを要求するメソッドです。この際、urlの末尾に情報を付与するのが大きな特徴です。
以下にコードを示します。
form.erbの中で、form<method = "get">
として、getメソッドを指定しています。main.rbrequire 'sinatra' require 'sinatra/reloader' get '/form' do erb :form end get "/hello" do "こんにちは、#{params[:name]}さん。" endform.erb<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"/> <title>名前</title> </head> <body> <form action="/hello" method="get"> <input type="text" name="name"> <input type="submit"> </form> </body> </html>以下のように、名前を入力し...
送信を押すと、挨拶してもらえる!
注目して欲しいのは、2枚目の画像のurlです。helloの後ろに
?name=hogehoge
と書かれているのがわかるかと思います。
このように、getメソッドでは?<キー>=<バリュー>
という形でリクエストを指定し、送信します。postについて
getはurlの末尾に情報を付与しサーバーへ送っていました。
一方、postはメッセージボディに入力した情報を記述してリクエストします。
以下にコードを示します。
form.erbの中で、form<method = "post">
として、postメソッドを指定しています。main.rbrequire 'sinatra' require 'sinatra/reloader' get '/form' do erb :form end post '/hello' do "こんにちは、#{@params[:name]}"さん。 endform.rb<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"/> <title>名前</title> </head> <body> <form action="/hello" method="post"> <input type="text" name="name"> <input type="submit"> </form> </body> </html>hello.erb<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"/> <title>hello</title> </head> <body> こんにちは、<%=@name%>さん。 </body> </html>コード自体はgetを使った場合とほぼ同じです。
こちらについても、実行結果を画像で示しておきます。
送信ボタンをクリックし、
挨拶してもらう。先ほどと違い、urlの末尾に情報が付与されていません。
これは、メッセージボディの箇所に入力した内容が記入されているからなのです。developerツールで確認
実際のメッセージボディの内容は、chromeのdeveloperツールから確認することができます。
chrome上でoption + command + I
コマンドからdeveloperツールを開き、network
タブをクリックしてください。
すると以下のような画面が出てくると思います。
ファイルをクリックし、Form Data
と書かれているところを開きます。
フォームに入力したデータがメッセージボディ(正確にはリクエストボディ)に格納されていることが実際に確認できました。やったね!
ちなみに、getを使った場合、下の画像ようになります。
メッセージボディではなく、クエリストリング(つまり、urlの後ろに付与している情報)として読み込まれていることが分かります。
- 投稿日:2021-03-14T13:07:31+09:00
VRoid Studioデータのヘアマテリアルを削除する
この記事の趣旨
下記のソフトウェアを作った本人ではあるのですが、この辺りのソフトウェアで既に実装済みであって、これとは別の実装を作りたい人とか、pixivの中の人とか、原理がわからないとツールを使うのが不安の人とか、いろんな立場の人に読んでもらいたいなと思っています。
VRoid運営がなんと言おうと.vroid内の不要マテリアルは削除していい
複製ボタンで一発で増殖したマテリアルは削除ボタン一発で削除できるのがUI/UXとして好ましいし削除機能を実装しないのは(某天才プログラマーさんの言葉を借りるなら)「けしからん」と思うわけです。
間違えてマテリアル増やしちゃうことだってあるわけじゃないですか。そういううっかりって取り消せること国は権利として認められているのですね。民法95条にも書いてある。削除処理の実装の実際
それでは処理を順を追って説明します、
.vroidファイルの構造
VRoidファイルは、ZIPで固めた複数のファイルで構成されますが、説明に必要な部分に絞って表示しております。
Hairishesから参照されている/いないHair-Materialをグループ分けする
髪が参照しているマテリアルというのはhairs_defs.jsonのHairishesの各ノードのParam > _MaterialValueGUIDの値がこれに該当します。
なお、Hairishesは髪グループと髪との2階層構造になっていますが、両方の階層を見る必要があります。ポイント:material_defs.jsonは髪以外のマテリアルも含む
新しめのバージョンで新規作成したモデルは、便宜上、3つの分類が存在することになります。今回は2のみが削除対象となります。
- Hairから参照されているヘアマテリアル
- Hairから参照されていないヘアマテリアル
- 髪以外のマテリアル
髪のマテリアルであることの識別方法は3つ
また髪かそうでないかを見分けるには以下のいずれかのKey-Value値を見れば良いかと思います。
_PrototypeId => "Flora/F00_000_Hair_00_HAIR" _SphereAddTextureId => "/Matcaps/Matcap_RimHair" _Tags => ["HairEditor"]私は_SphereAddTextureIdを使っています。
というのも"Flora/F00_000_Hair_00_HAIR"の部分は条件によって異なる場合があるからです。削除するテクスチャの選定
削除対象のマテリアルノードの _MainTextureId キーに格納されているIDが削除対象のテクスチャとなります。
一応用心のため、削除しないマテリアルから参照されているテクスチャIDが削除対象のテクスチャIDに含まれていないことを確認し、もし重なる部分があれば削除対象から除外しましょう。SQLiteのエントリー削除
テクスチャの管理テーブルはcanvasとlayerの2つのテーブルで十分じゃないかという気もしないでもないのですが、4つのテーブルから構成されています。
正攻法としてはcanvas_idからこれに属するlayer_idを求め、layer_order, layer_info, raster_layer_contentの各テーブルのレコードを削除し、canvas_infoのレコードを削除する流れとなるかと思います。
髪のテクスチャIDはcanvas_infoのIDではなくnameの方に紐づいているのでその点だけ注意。各レイヤーのテクスチャ本体はraster_layer_contentのBLOBに上下反転した状態で入っています。
レンダリング済みテクスチャの削除
rendered_texturesの下にPNGファイルが複数あるかと思いますが、削除対象は先のテクスチャIDに.pngを付けたものが対応しています。
Rubyの実装例
そんなわけで以前実装したものを紹介しておきます。
実はヘアプリセットの出力でもマテリアルは削減している。
実はVRoid Studioのヘアプリセットを出力する処理においても、Hairishesから参照されていないヘアマテリアルのノードとこれに紐づくテクスチャのみしか出力しない処理がなされています。
(出力内容を見る限りでは)等価の処理を再現したのが下記のスクリプトです。こちらも meta.json + hair_defs.json + material_defs.jsonと関連するテクスチャ(PNGファイル)から生成するので、原理としてはかなり近いです。
これは、VRoid Studioにおいてもヘアプリセットのエクスポートの処理を転用すればヘアマテリアルの削除が容易に実装できることを意味しています。
まとめ
VRoidのサポートページを見る限り、マテリアルを削除できないこと、これを削除できるよう要望があることは十分認識していて、それでもなお実装を後回しにしているのは何かしらの事情がありそうだということ。
困っているユーザーがいるのに「何もしない」という答えは最善ではないと思うので、私はマテリアルを削除する手段を作りました。
- 投稿日:2021-03-14T12:29:50+09:00
【Ruby on Rails6】gem "devise" のviewsのpasswordsだけが編集できない。
【Rails6】gem "devise" のviewsのpasswordsだけが編集できない。
↑記事で解決できました。
しかし、私の場合passwordsのviewsだけhtml.erb編集が反映されなかったので事象を記録します。環境 Ruby 2.6.6p146/Rails 6.0.3
通常通りdeviseを導入後、viewを編集。なぜかpasswordsだけ編集できずググって解決。
結論
config/initializers/devise.rb
devise.rb# ==> Scopes configuration # Turn scoped views on. Before rendering "sessions/new", it will first check for # "users/sessions/new". It's turned off by default because it's slower if you # are using only default views. # config.scoped_views = falseのコメントアウト箇所…
devise.rb# ==> Scopes configuration # Turn scoped views on. Before rendering "sessions/new", it will first check for # "users/sessions/new". It's turned off by default because it's slower if you # are using only default views. config.scoped_views = true
config.scoped_views = true
にしてください。
そのままのコメントアウトだとconfig.scoped_views = false
なので注意です。その後ターミナルで
rails s
でサーバー再起動も忘れずに。
※僕は再起動しないと反映されませんでした。これにて解決。
ここからが??な事象です。もし、謎を知っている方がいたら教えていただきたいです。
反映されない該当箇所をブラウザリロードをすると、ターミナル表示が
Started GET "/users/password/new" for ::1 at 2021-03-14 11:49:26 +0900 Processing by Devise::PasswordsController#new as HTML Rendering /Users/sxkx/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/devise-i18n-1.9.2/app/views/devise/passwords/new.html.erb within layouts/application Rendered /Users/sxkx/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/devise-i18n-1.9.2/app/views/devise/shared/_error_messages.html.erb (Duration: 0.1ms | Allocations: 15) Rendered /Users/sxkx/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/devise-i18n-1.9.2/app/views/devise/shared/_links.html.erb (Duration: 0.4ms | Allocations: 246) Rendered /Users/sxkx/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/devise-i18n-1.9.2/app/views/devise/passwords/new.html.erb within layouts/application (Duration: 2.5ms | Allocations: 863) [Webpacker] Everything's up-to-date. Nothing to do Rendered layouts/_header.html.erb (Duration: 0.3ms | Allocations: 119) Rendered layouts/_sidemenu.html.erb (Duration: 0.2ms | Allocations: 135) [Webpacker] Everything's up-to-date. Nothing to do Completed 200 OK in 28ms (Views: 26.4ms | ActiveRecord: 0.0ms | Allocations: 11089)
Rendering /Users/sxkx/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/devise-i18n-1.9.2/app/views/devise/passwords/new.html.erb within layouts/application
??なんだか長い…。 devise-i18n…. 日本語化のために入れたgemが悪さをしている??devise.rbconfig.scoped_views = trueをすると
Started GET "/users/password/new" for ::1 at 2021-03-14 11:54:00 +0900 Processing by Devise::PasswordsController#new as HTML Rendering users/passwords/new.html.erb within layouts/application Rendered users/shared/_error_messages.html.erb (Duration: 0.1ms | Allocations: 15) Rendered users/shared/_links.html.erb (Duration: 0.9ms | Allocations: 225) Rendered users/passwords/new.html.erb within layouts/application (Duration: 4.7ms | Allocations: 1058) [Webpacker] Everything's up-to-date. Nothing to do Rendered layouts/_header.html.erb (Duration: 0.5ms | Allocations: 119) Rendered layouts/_sidemenu.html.erb (Duration: 0.3ms | Allocations: 135) [Webpacker] Everything's up-to-date. Nothing to do Completed 200 OK in 41ms (Views: 37.7ms | ActiveRecord: 0.0ms | Allocations: 12092)
Rendering users/passwords/new.html.erb within layouts/application
うん。なんかちゃんと狙いのファイルを拾ってくれていそう。スコープを指定したから、しっかりできた感じなんですね。
ただなぜpasswordsだけがそうなったのかは謎です。以上。
- 投稿日:2021-03-14T12:28:26+09:00
複数タグ投稿機能の実装(formオブジェクト使用)
投稿に複数のタグを紐付ける
現在作成中のポートフォリオの中で複数のタグをつけることができる機能をつけたかったのでそれを実践した際のコードの記述についてまとめておこうと思います。またポートフォリオ完成した際には別記事で解説したいと思います。
それでは実際の実装を書いていきます。。conntrollerの記述
def new @room = RoomsTag.new end def create @room = RoomsTag.new(room_params) tag_list = params[:room][:name].split(",") if @room.valid? @room.save(tag_list) redirect_to root_path else render "new" end end def edit @form = RoomsTag.new(room: @room) end def update @form = RoomsTag.new(room_params, room: @room) tag_list = params[:room][:name].split(",") if @form.valid? @form.save(tag_list) redirect_to room_path(@room) else render :edit end end private def room_params params.require(:room).permit(:image, :title, :content, :place_id, :floor_id, :style_id, :name).merge(user_id: current_user.id) endformオブジェクトの記述
class RoomsTag include ActiveModel::Model attr_accessor :image, :title, :content, :place_id, :floor_id, :style_id, :name, :user_id # バリデーションをカットしています。 delegate :persisted?, to: :room def initialize(attributes = nil, room: Room.new) @room = room attributes ||= default_attributes super(attributes) end def save(tag_list) ActiveRecord::Base.transaction do @room.update(image: image, title: title, content: content, place_id: place_id, floor_id: floor_id, style_id: style_id, user_id: user_id) @room.room_tag_relations.each do |tag| tag.delete end tag_list.each do |tag_name| tag = Tag.where(name: tag_name).first_or_initialize tag.save room_tag = RoomTagRelation.where(room_id: @room.id, tag_id: tag.id).first_or_initialize room_tag.update(room_id: @room.id, tag_id: tag.id) end end end def to_model room end private attr_reader :room def default_attributes { image: room.image, title: room.title, content: room.content, place_id: room.place_id, floor_id: room.floor_id, style_id: room.style_id, name: room.tags.pluck(:name).join(',') } end endまずデータベースに保存できるところまでを記述していきます。
controller内の記述について
tag_list = params[:room][:name].split(",")上記の記述はsplitメソッドを用いて , で区切って、配列に変換しています。
その後formオブジェクトへ送ります。formオブジェクト内の記述について
delegate :persisted?, to: :roomこちらの記述から新規作成か更新かを判別して、formのメソッドをPUTとPATCHで分けている。
def initialize(attributes = nil, room: Room.new) @room = room attributes ||= default_attributes super(attributes) endformオブジェクトパターンで編集機能を実装する際は、編集画面でそれぞれのデータを表示させておくには、今回私の実装で行くところのRoomsTagのインスタンスを生成して、それをformに持っていかなくてはいけません。上記のinitializeメソッドの定義によってnewアクションの時は中身は空で、editアクションの時は中身がある状態でformに持っていくことができます。
super(attributes)の記述がないとinitializeメソッドが機能しないようです。続いてtag_listを引数にとっているsaveメソッド内について。
ActiveRecord::Base.transaction do endこの間に囲まれた部分で何か処理の失敗が起きた時、do~end間の処理を全てなかったことにするものです。
@room.update(image: image, title: title, content: content, place_id: place_id, floor_id: floor_id, style_id: style_id, user_id: user_id) @room.room_tag_relations.each do |tag| tag.delete end@room.updateにてデータの更新をします。
その下の記述で、このroomに紐付く全てのタグを一旦削除しています。tag_list.each do |tags| tag = Tag.where(name: tags).first_or_initialize tag.save room_tag = RoomTagRelation.where(room_id: @room.id, tag_id: tag.id).first_or_initialize room_tag.update(room_id: @room.id, tag_id: tag.id) end配列で運ばれてきたtag_listをeachメソッドを使って、一つずつ取り出し、whereメソッドとfirst_or_initializeメソッドで今までに保存したことがないタグだけ保存しています。その後中間テーブルのものを更新しています。
ここまででsave(tag_list)内の記述は終了です。def to_model room endcreateかupdateか適切なコントローラーへのパスをしてあげる記述みたいです、、
最後、privateメソッド内の記述でこれで読み取り専用のメソッドが定義されるようです。以上で複数タグの投稿機能の実装を行いました。かなり手探りで色々な記事を参考にしながらのものだったので拙い表現となっているかと思います。ご了承ください。。
- 投稿日:2021-03-14T12:17:34+09:00
【クソサイト】世界一情報量が多いサイト【個人開発】
はじめに
情報量が多い画像、情報量が多い動画などはたくさんあるのに「情報量が多いサイト」というのは見つからなかったので作ってみました。
概要
為替
ニュース
名言
じゃんけん
投稿
情報量の多い画像
日付け
イカれた鳥
などの情報が載ってます。あと隠しページがありますので暇な人は探してみてください。そこそこむずいです。
工夫した点
APIを大量に使う
大量と言っても3つですが
NewsAPI...ニュース
exchangeratesapi...為替
名言教えるよ...名言を使いました。
色使い
原色、反対色、相性の悪い色
をあえて大量に使いまとまりをなくしました。画像
あえてリサイズをせずサイズをバラバラにしてみました。
動き
スライドショーやイカれた鳥を使い動きを持たせさらに混乱するようにしました。
まとめ
深夜テンションで決めたネタを続投しないよう法が良い
ツイッターやってます
https://twitter.com/yamada1531追記
皆さん、隠しページ見つけるの早いですね...。公開して3日くらいは絶対見つからないと思ってたのにもう1、2人...。
もうちょっと難しくしようかなーなんて思ってます。
- 投稿日:2021-03-14T11:48:17+09:00
[Rails]Fakerで日本語名を生成する方法
- 投稿日:2021-03-14T11:00:11+09:00
[WIP]Rails6.1ハンズオン(4)~6.0の機能を触る
はじめに
※この記事は執筆途中です。5-1までで力尽きたので5-2以降はまた今度書きます...
Rails6.1ハンズオン(3)の続きです。
6.1ハンズオンと言いながら、実は6.0をまともに触っていない筆者。。。
ですので今回は6.0で追加された機能を触ってみます。
コードはGithubにあげています。章ごとにコミットしてますので、参考にしていただければ幸いです。やること
個人的に気になった(面白そうor仕事で使いそう)機能をピックアップして、現在のRails_6.1_hands_onプロジェクトに追加してみます。
- Action Text
- Action Mailbox
- ActiveRecord::Relation#pick
参考:Ruby on Rails 6の主要な新機能・機能追加・変更点 - Qiita
5-1. Action Text
5-1-1. Action Text, Active Storageの導入
まずはActiveStorageが必要なので、
rails active_storage:installをしたが、
rails aborted! Don't know how to build task 'active_storage:install' (See the list of available tasks with `rails --tasks`)と出た。ActiveStorageのREADMEをみると、
Run bin/rails active_storage:install to copy over active_storage migrations.
NOTE: If the task cannot be found, verify that require "active_storage/engine" is present in config/application.rb.らしいので、config/application.rbをみると、
require "rails" # Pick the frameworks you want: require "active_model/railtie" require "active_job/railtie" require "active_record/railtie" # require "active_storage/engine" require "action_controller/railtie" # require "action_mailer/railtie" # require "action_mailbox/engine" # require "action_text/engine" require "action_view/railtie" require "action_cable/engine" require "sprockets/railtie"となっていた。rails new で色々無効にしていたのでコメントアウトされていたらしい。
action_text/engine
も無効化されているのでこちらも有効にしておく。そしてやっと、
rails active_storage:install rails action_text:installmigrationファイルができているので、忘れずに
rails db:migrate
する。config/storage.ymlを作る(最初からあるイメージだが、今回は無かった)
local: service: Disk root: <%= Rails.root.join("storage") %> test: service: Disk root: <%= Rails.root.join("tmp/storage") %>config/environments/development.rb(test.rbも任意で、このハンズオンでテスト書くのかな...)に追加:
config.active_storage.service = :local5-1-2. ActionTextをモデルに適用する
Commentのcontentがtextになっていたのを、Action Textに置き換える。
rails g migration RemoveContentInCommentclass RemoveContentInComment < ActiveRecord::Migration[6.1] def change remove_column :comments, :content, :text end end
rails db:migrate
して、app/models/comment.rb
class Comment < ApplicationRecord belongs_to :community has_rich_text :content end
has_rich_text
でcontentカラムを作ったかのように振る舞ってくれるようになる。app/views/comments/new.html.haml(一部)
= form.label :content, class: 'form-label' = form.rich_text_area :content, class: 'form-control mb-4'app/views/communities/show.html.haml
= comment.contentsimple_formatを外した。
すると以下のようになる。
思ってたのと違う。cssが読み込まれていない。action_text:installしたときに新しく生成されたcssは、app/assets/stylesheets/actiontext.scss。内容がこちら
// // Provides a drop-in pointer for the default Trix stylesheet that will format the toolbar and // the trix-editor content (whether displayed or under editing). Feel free to incorporate this // inclusion directly in any other asset bundle and remove this file. // //= require trix/dist/trix // We need to override trix.css’s image gallery styles to accommodate the // <action-text-attachment> element we wrap around attachments. Otherwise, // images in galleries will be squished by the max-width: 33%; rule. .trix-content { .attachment-gallery { > action-text-attachment, > .attachment { flex: 1 0 33%; padding: 0 0.5em; max-width: 33%; } // (以下省略)trix/dist/trixをrequireしていて、更に添付ファイルの表示に関するスタイルを上書きしているらしい。
app/views/layouts/application.html.hamlでは、
= stylesheet_link_tag 'application'
を消して、= stylesheet_pack_tag 'application'
に変えているので、上記ファイルは読み込まれない。
= stylesheet_link_tag 'application'
を復活させれば動く(動作確認済み)。だが、せっかくなので、webpackerに寄せる。
app/javascript/stylesheets/application.scss
@import "~@fortawesome/fontawesome-free/scss/fontawesome"; $primary: #9400d9; @import "bootstrap"; @import "trix/dist/trix"; @import "actiontext.scss";app/javascript/stylesheets/actiontext.scssではsprocket用のコードを外して記述。
// We need to override trix.css’s image gallery styles to accommodate the // <action-text-attachment> element we wrap around attachments. Otherwise, // images in galleries will be squished by the max-width: 33%; rule. .trix-content { .attachment-gallery { > action-text-attachment, > .attachment { flex: 1 0 33%; padding: 0 0.5em; max-width: 33%; } &.attachment-gallery--2, &.attachment-gallery--4 { > action-text-attachment, > .attachment { flex-basis: 50%; max-width: 50%; } } } action-text-attachment { .attachment { padding: 0 !important; max-width: 100% !important; } } }すると、
できた。
こんな感じで入力できる。
それで投稿すると
画像が表示されない。
chromeのconsoleを見ると、
GET http://localhost:3000/rails/active_storage/representations/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBCZz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--dce7eada98f7015981b311d8495658640b895ad9/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCem9MWm05eWJXRjBTU0lJY0c1bkJqb0dSVlE2RkhKbGMybDZaVjkwYjE5c2FXMXBkRnNIYVFJQUJHa0NBQU09IiwiZXhwIjpudWxsLCJwdXIiOiJ2YXJpYXRpb24ifX0=--9a6414b9afa153c394bf23eb32d0e368370e8b60/Screenshot_20210304-220735.png 500 (Internal Server Error)読み込めてない。500なので内部的なエラー。
したがってrailsのコンソールを見ると、
LoadError (Generating image variants require the image_processing gem. Please add `gem 'image_processing', '~> 1.2'` to your Gemfile.)ちゃんと書いてあった。Gemfileに
gem 'image_processing', '~> 1.2'
を追加。bundle install。表示されました。
5-2. Action Mailbox
(執筆中です)
- 投稿日:2021-03-14T10:45:51+09:00
マイグレーションファイルを変更する方法(Rails)
マイグレーションファイル変更する方法
参考にしたサイト Railsチュートリアル(5.1)
$ rails db:rollback $ rails db:migrate VERSION=0 $ rails db:rollback STEP=○
- 1つ前の状態に戻します。
- 最初の状態に戻したいときは
VERSION=0
つける- 最後のマイグレーションファイルから数えて戻したい数だけ戻せる
$ rails db:rollback $ rails db:migrate:status Status Migration ID Migration Name -------------------------------------------------- up 20200830060821 Devise create users down 20200830062141 Create books
$ rails db:migrate:status
を使うことで変更できるファイルの一覧を確認できます。
downが変更可能でupが変更できないファイルです。
$ rails db:rollback
を使うとdownに変更されていると思います。$ rails g migration add_index_to_users_emailusersテーブルの中にemailカラムをを追加するコマンド
おまけ
$ rails db:migrate $ bundle exec rake db:migrate
- Rails 5以降のコマンド
- Rails 4以前のコマンド
- 投稿日:2021-03-14T09:43:48+09:00
HerokuでMySQLサーバーを使う方法
Heroku CLIをインストールしてから、ClearDBの導入から、Heroku apps:infoまでの手順を紹介します!(学習記録)
Heorkuのインストールからアプリ作成
# heroku cliのインストール % brew tap heroku/brew && brew install heroku # herokuのversionを確認 % heroku --version # herokuにログインする % heroku login --interactive #パスワードとメールアドレスを入力してログイン # heroku createで本番環境用のアプリを作成 cd ~/(アプリまでの相対パス) heroku create (アプリの名前) # アプリが正常に作られていることを確認 % git config --list | grep herokuHerokuにMySQLを導入
# ClearDBを導入 % heroku addons:add cleardb # Railsに対応させる heroku_cleardb=`heroku config:get CLEARDB_DATABASE_URL` # データベースのURLの再設定 heroku config:set DATABASE_URL=mysql2${heroku_cleardb:5}Heroku上で非公開の値を管理
# masterkeyを確認 % cd ~/(アプリまでの相対パス) % EDITOR="code --wait" bin/rails credentials:edit # heroku上に環境変数を設定 % heroku config:set RAILS_MASTER_KEY=`cat config/master.key` # 正しく反映されているか確認 % heroku configHerokuにpush
# herokuに自分のアプリを追加 % git push heroku master # Rubyのバージョンによっては必要なコマンド heroku stack:set heroku-18 -a (アプリの名前) # migrateを実行 heroku run rails db:migrate # heroku apps:infoで確認 heroku apps:info以上がHerokuでMySQLサーバーを使う流れになります。参考までにどうぞ!!
- 投稿日:2021-03-14T09:43:48+09:00
HerokuでMySQLサーバーを使う方法(Rails)
Heroku CLIをインストールしてから、ClearDBの導入、Heroku apps:infoまでの手順を紹介します!(学習記録)
Heorkuのインストールからアプリ作成
# heroku cliのインストール % brew tap heroku/brew && brew install heroku # herokuのversionを確認 % heroku --version # herokuにログインする % heroku login --interactive #パスワードとメールアドレスを入力してログイン # heroku createで本番環境用のアプリを作成 cd ~/(アプリまでの相対パス) heroku create (アプリの名前) # アプリが正常に作られていることを確認 % git config --list | grep herokuHerokuにMySQLを導入
# ClearDBを導入 % heroku addons:add cleardb # Railsに対応させる heroku_cleardb=`heroku config:get CLEARDB_DATABASE_URL` # データベースのURLの再設定 heroku config:set DATABASE_URL=mysql2${heroku_cleardb:5}Heroku上で非公開の値を管理
# masterkeyを確認 % cd ~/(アプリまでの相対パス) % EDITOR="code --wait" bin/rails credentials:edit # heroku上に環境変数を設定 % heroku config:set RAILS_MASTER_KEY=`cat config/master.key` # 正しく反映されているか確認 % heroku configHerokuにpush
# herokuに自分のアプリを追加 % git push heroku master # Rubyのバージョンによっては必要なコマンド heroku stack:set heroku-18 -a (アプリの名前) # migrateを実行 heroku run rails db:migrate # heroku apps:infoで確認 heroku apps:info #最後にHerokuのMySQLサーバーをリセットするコマンド % heroku run DISABLE_DATABASE_ENVIRONMENT_CHECK=1 rails db:drop db:create db:migrate以上がHerokuでMySQLサーバーを使う流れになります。参考までにどうぞ!!
- 投稿日:2021-03-14T04:26:59+09:00
attr_readerメソッド
- 投稿日:2021-03-14T00:31:41+09:00
【Ruby】クラス、メソッドの定義とインスタンス変数について
はじめに
この記事は、Ruby/Railsの学習期間約1ヶ月の著者が書いたものです。
初投稿となりますので、誤った解釈があるかもしれません。その場合は、コメント等頂けますと幸いですm(_ _)m今回は、Ruby学習中によく分からなくなりがちな、クラス、メソッドの定義、インスタンス変数について説明します。
独自のクラスを定義する
まず、Rubyではクラスを定義します。
クラスとは、設計図のようなもので、class
から始まり、end
で終わります。クラス名は、
ClassName
というように、単語の先頭を大文字で定義します。
ラクダのコブのようであることから、CamelCase
と表現します。class.rb#クラスの定義 class ClassName endクラスにメソッドを定義する
クラスの設計図の中にメソッドを定義することで、そのクラス独自が持っているメソッドとして認識されます。
メソッドとは、何らかの処理を示しており、処理内容を
def
とend
で囲みます。
メソッド名は、method_name
のように2単語目以降は、アンダーバーで示しますので注意しましょう。
(このことを蛇に例えて、snake_case
と呼びます。)method.rb#メソッドの定義 class ClassName def method_name # メソッドの処理を書く end end #クラスのインスタンスを作成し、メソッドで呼び出す instance = ClassName.new instance.method_nameRubyのオブジェクトは何らかのメソッドを持っていて、そのメソッドを定義することで、処理を返してくれるようになります。
ローカル変数とインスタンス変数について
次に、ローカル変数とインスタンス変数の違いを見てみましょう。
ローカル変数
ローカル変数は、使い回しできる範囲が他の変数よりも限られています。
例えば、メソッド内で定義した場合は、そのメソッド内でしか使えず、同じクラス内であっても使い回しができません。試しに、以下のローカル変数
message
を、say_morning
のメソッドの処理として定義し、
say_good_morning
のメソッド内で使い回してみましょう。local_variable.rbclass Greeting def say_morning message = "morning!" puts message end def say_good_morning puts "Good #{message}" end end instance = Greeting.new instance.say_morning instance.say_good_morning以下のようなエラーが出てしまいました。
`say_good_morning': undefined local variable or method `message' for #<Greeting:0x00007fe5b1984038> (NameError)つまり、
say_good_morning
のメソッドの中で、message
というローカル変数やメソッドは定義されてませんよ、と言っているわけです。
このように、ローカル変数は、あるメソッド内で定義した変数は、他のメソッド内で使い回すことができません。インスタンス変数
一方、インスタンス変数とは、同じオブジェクト内(同クラス内)で使い回せる変数のことをいいます。
変数の先頭に@をつけて定義します。先程のローカル変数
message
を、インスタンス変数@message
に置き換えて見てみましょう。instance_variable.rbclass Greeting def say_morning @message = "morning!" puts @message end def say_good_morning puts "Good #{@message}" end end instance = Greeting.new instance.say_morning instance.say_good_morning結果は以下の通り。
morning! Good morning!欲しい結果が出ましたね!
つまり、インスタンス変数とは、同じクラス内であれば、異なるメソッド内であっても何度でも使い回せる変数である、ということが証明されました。おわりに
今回はRubyの基本であるクラス、メソッドの定義とローカル変数とインスタンス変数の違いについて、説明しました。
今後も、Ruby/Railsを学習する上で、皆様に有益な情報を発信できればと思いますので、良ければLGTMお願いします。参考記事
- 投稿日:2021-03-14T00:09:43+09:00
【Rails】Cloud9で送信メールのプレビュー時の自分のホスト名と指定のURLの指定方法【Railsチュートリアル11章】
自分がつまづいた時の状況
Railsチュートリアル第11章アカウントの有効化でHTMLメールとテキストメールのプレビューをする際に、アプリケーションのdevelopment環境の設定ファイルの設定と、Railsサーバー起動時のURLが分からず、送信メールのプレビューが表示できませんでした。
・クラウドIDE:AWS Cloud9
・Rails:v6.0.3
・OS:Winconfig/environments/development.rbRails.application.configure do . . . config.action_mailer.raise_delivery_errors = false host = 'example.com' # ここの指定方法が分からなかった(自分のホスト名を指定する) config.action_mailer.default_url_options = { host: host, protocol: 'https' } . . . end自分のホスト名の調べ方
まず、自分のホスト名を調べる方法ですが、
Cloud9のPreview PreviewRunning Applicationを押下し、アドレスバーがついているpreviewタブを表示させます。
その後、そのアドレスバーに表示されているlocalhost以下の文字列が自分のアドレスになります。その自分のホスト名の中でもhttpsから.vsfの間の文字列を先ほどのdevelop環境の設定ファイルに反映します。
config/environments/development.rbconfig.action_mailer.raise_delivery_errors = false host = 'hoge.vfs.cloud9.us-east-2.amazonaws.com' # クラウドIDE config.action_mailer.default_url_options = { host: host, protocol: 'https' }設定ファイルを変更したら、Railsサーバーは再起動してください。
送信メールのプレビューのURL
URLですが、下記でプレビューが表示されました。
ホストの後ろに「/rails/mailers/user_mailer」とつけるだけでした。https://hogehoge.vfs.cloud9.ap-northeast-1.amazonaws.com/rails/mailers/user_mailer参考
Railsチュートリアル第11章アカウントの有効化
rails tutorial にて 送信メールのプレビューができない
rails チュートリアルの11章の2・2にてクラウドIDEのホスト名がわからない