- 投稿日:2021-01-10T22:46:30+09:00
Rails6 Ajaxを使えるようにするために最初にしておくこと
ポートフォリを作成中にAjaxで路頭に迷ったので、未来の自分のためにこの記事を残しておこうと思います。
jQuery関係
jQueryのライブラリをインストール
$ yarn add jquery@3.4.1Webpackの環境編集
config/webpack/environment.jsconst { environment } = require('@rails/webpacker') #下記を追加 const webpack = require('webpack') environment.plugins.prepend('Provide', new webpack.ProvidePlugin({ $: 'jquery/src/jquery', jQuery: 'jquery/src/jquery' }) ) #ここまで module.exports = environmentapplication.jsに追加
app/javascript/packs/application.jsrequire("jquery")ブラウザ関係
ブラウザ側でjavascriptが無効になっていた場合でもAjaxが起動するために
config/application.rbmodule "アプリ名" class Application < Rails::Application . . . # これを追加! config.action_view.embed_authenticity_token_in_remote_forms = true endあとは書きまくるだけ!!
- 投稿日:2021-01-10T22:40:12+09:00
【Ruby】演算にnilが含まれた際のエラーを防ぐ方法
- 投稿日:2021-01-10T21:42:41+09:00
【Rails】よっ!Active Strage!有能なGem!〜2つのテーブルから画像を保存できる〜
ずっと謎だったこと
Active Strageで画像を保存する時に二つのテーブルから保存できるのか?ということがずっと疑問でした。
現在オリジナルアプリを開発中なのですがレビューサイトのため、
①ユーザーのプロフ写真
②レビュー対象の写真
この二つを保存したかったのですが複数のテーブルから保存する方法がいまいちよくわからなかったため、ユーザーのほうはtext型にて保存、Active Strageを使用するのはレビュー対象のみとしていました。
本日、マイグレーションをrollbackしなければいけないミスがあり、ついでだからやってみようと思い立ち、以下の作業をしました。
・ユーザーテーブルに保存していた画像保存予定だったカラムを消去
・ユーザー登録時&レビュー対象登録時にそれぞれ写真が保存できるか確認
まずはマイグレーションを編集します。
% rails db:rollback
このコマンド、最初は実行するのがとてもとても怖かったです(初心者あるある
その後、状況がどうなっているかをしっかり確認するためステータスをチェック。% rails db:migrate:status database: party_freak_development Status Migration ID Migration Name -------------------------------------------------- up 20210107124355 Devise create users ⬅️変更目標はここ up 20210108071047 Create parties up 20210108094951 Create active storage tablesactive storage up 20210108122152 Rename iintroduction column to parties ⬅️リネームした履歴 up 20210108123328 Rename date id column to parties ⬅️リネームした履歴 down 20210108130921 Change column to allow null ⬅️null制約変更した履歴
下の3つは昨日変更したテーブルのカラムの名前とnull制約に関するマイグレーションファイルです。
よくよく考えたらリネームしてマイグレーションファイルを増やすならrollbackしてマイグレーションファイルを直に修正したほうが余計なファイルが増えなくていいんじゃないか?
と気付き、rollbackを繰り返し行って下の3つのマイグレーションファイルをコードエディタ上から右クリック→削除しました。スッキリ。繰り返す時はこのコマンドが便利です。
% rails db:rollback STEP=5 ⬆️=の後にdownを0とし(次のupから1と数える)その回数だけrollback 今回の自分のケースだと5でした
よく見たら一瞬焦ったこと
== 20210108094951 CreateActiveStorageTables: reverting ======================== -- drop_table(:active_storage_attachments, {}) -> 0.0470s -- drop_table(:active_storage_blobs, {}) -> 0.0363s == 20210108094951 CreateActiveStorageTables: reverted (0.0847s) ===============Active Strageがdropになってるううううううううううううう!
またやらかしたああああああああああああああああ!
消したものはしょうがないどうせまた戻るだろ前しか見えねえ(確認犯
db:migrateで、きっとまた会えるよね?そう信じて次に進む。ユーザーモデルにActive Strageを使えるようにする記述を行います。
app/models/user.rbclass User < ApplicationRecord has_one_attached :image ⬅️これを記述 〜以下略〜 end①ユーザーモデル
②レビュー投稿モデル
合計2つのモデルにhas_one_attached :image
を記述しました。そしてマイグレーションファイルから画像保存用の記述を削除して、db:migrateをする。
結果
record_typeというカラムにUserとPartyという2つの表示がされています。
大成功!(やっぱり会えたねActive Strage
気になったこと
ユーザーは複数枚の画像投稿(もしくは動画)が可能なように考えているのですが、もう1つテーブルを作ってそこに
has_many_attached
を使って保存されるのだろうか?
複数の場合はhas_one
からhas_many
に変わるとのことですがこのカラムを見ているとできそうな雰囲気も感じますが、実際にやってみた結果はまたこちらで記事を書こうと思います。以上、Active Strageで2つのテーブルから画像を保存する方法でした。
- 投稿日:2021-01-10T20:49:37+09:00
Rubyで値が〇の倍数であることを判別する
- 投稿日:2021-01-10T18:55:30+09:00
【個人開発】テストユーザーを募集するサイト作ってみた!
初めに
前、MENTAの作成者さんが動画で「webアプリは公開してからじゃないと使われるかわからない」って言っていたので
ベータ版専門のアプリ宣伝サイトをつくってみました。
そんなことサイトもまだベータ版でデザインは相当雑です。使われるようになってきたらデザインも変更しますし機能も追加します。URL:
https://testuser-b.herokuapp.com/テストユーザーはなぜ必要?
webアプリは公開しないと需要があるかわかりません。
「市場調査で調べられる」と思うかもしれないが口先だけ使うと言われただけで、公開したあとその人たちが本当に使うかはわからないんです。だから、本当に需要があるかどうかは実際に公開してみるしかないのですが
何か月もかけて開発したのに誰にも使われなかった...というのは悲しすぎます。
webアプリは当たる確率の方が低いです(6%程)だからヒットしなくてもダメージが少ないようベータ版を作ればいいのですが なかなか使ってもらうのは難しいです。webアプリは万全の状態で宣伝するものなので 今あるwebアプリの宣伝所はベータ版をなかなか受け入れてくれません。 そこでこのTest User βが生まれました。
使った技術
rails6
ruby2.7
heroku free(スリープしないよう設定している)開発時間は数時間
ロゴは自作
開発費用もサーバー代も無料です。まとめ
webアプリは公開してからじゃないと使われるかわからない
市場調査だけではわからない何がともあれ使ってみてください。お願いします(^_-)-☆
URL:
https://testuser-b.herokuapp.com/僕のツイッターもお願いします。
開発中に気づいたことをつぶやいてます。
https://twitter.com/Yuuki49079799
- 投稿日:2021-01-10T18:51:45+09:00
RailsでExtend(Concerns)を利用してControllerの処理を共通化する。
背景
記事一覧をPage#homeに出力したかった。
@ posts = Post.allのデータは、Postモデル、コントローラにある。Pageモデル、コントローラには無い。
PostのデータをPageに持ってくるためにはどうすればいいかググっていた。解決
この情報をPageに持って行きたい。
posts_controller.rbclass PostsController < ApplicationController def index @posts = Post.all end endPageに取り込む。
Page.rbclass Page < ApplicationRecord + extend Post::Models endPageでPostの情報を定義してみる。
pages_controller.rbdef home @posts = Post.all end出力された。
home.html.erb<%= @posts.each do |p| %> <%= p.thumbnail %> <%= p.title %> <%= p.tag %> <%= p.content %> <% end %>もっとうまく説明している記事あります。↓
https://github.com/mc-chinju/qiita_clone/commit/262a6178d5a2eb77c6f507cf9386cb61825bfbaf
https://medium.com/@yavuz255/rake-aborted-2da1233a4561
https://railsguides.jp/active_model_basics.html他のやり方↓
controller/concernにファイルを作って行う方法
https://programming-beginner-zeroichi.jp/articles/142ググる時の関連ワード
extend ActiveSupport::Concern
rails concern
- 投稿日:2021-01-10T17:56:17+09:00
yarnがインストールされていないとのこと
rails new でアプリを作ろうとすると
RubyとRailsがインストールでき、アプリを作ってみようかとすると
yarnがインストールされていませんよと言われたので、yarnをインストールして解消。環境
Mac
Ruby2.6.0
Rails6.1.0rails new実行
今回はデスクトップに作るので、
$ cd Desktop $ Rails new アプリ名実行すると、
しばらく時間がかかったのちに、Yarn not installed.アプリが作られず、エラーになったようで、上記のようにyarnがインストールされていない
と言われる。yarn インストール
参考→Rails6 開発時につまづきそうな webpacker, yarn 関係のエラーと解決方法
$ brew install yarn $ yarn -v $ yarn installこれで無事にインストールされた模様。
再度アプリを作りサーバーで実行
再度、rails new を実行すると今度はうまくいった。
そして、rails server を実行すると、懐かしの画面。1年半ぶり?
ん、Railsのバージョンが変わってる?
yarnのインストールによってRailsのバージョンが6.1.0から6.1.1になったのでしょうか。$ rails -v Rails 6.1.1やはり変わっている。問題ないでしょう。知らんけど。
さて、Rubyの勉強を少し挟んで、Railsアプリの中身を作ることにします。参考書籍
- 投稿日:2021-01-10T17:29:14+09:00
Rubyで黒澤ルビィを作る(Ruby + LINE Messaging API)
黒澤ルビィ、可愛いですよね。
LINE上で喋るルビィちゃんを作りました。Rubyで。
以下の仕組みで動いています。
LINE Messaging API
を用いて、「黒澤ルビィ」としてLINEメッセージの受信、送信を行う。Ruby(Ruby on rails)
でLINE Messaging API
とやり取りするAPIサーバを作る。
- メッセージを形態素解析し、その結果をもとにマルコフ連鎖で新しく文章を生成する
LINEアカウントを作る
前準備としてルビィちゃんとして動くアカウント(厳密に言うと、Messaging APIのチャネル)が必要です。それをつくります。
LINE Developersから登録します。
Create a new channel
から新しく作ります。なお、作るときにどういうTypeか聞かれると思います。今回作りたいものはMessaging APIで作ることができるので、該当するものを選択してください。無事作成できると、アクセストークンを取得できます。
また、アカウントのアイコンや自己紹介欄などを設定できます。1APIサーバを作る
画面を持つ予定はないので、APIモードでRailsプロジェクトを作ります。
line-bot-api
gem2を入れます。先程作成したアカウントのアクセストークンを使ってLINEとやりとりできるようになります。Controllerを作る
先程作成したアカウントに対してWebhook URLを設定すると、そのアカウントに対して送信したメッセージをトリガーにしてLINEがリクエストを送ってくれます。
具体的なリクエストの中身についてはMessaging APIリファレンスを参照してください。以下の例はテキストメッセージに反応して、「メッセージ」と返すだけの仕組みです。def client @client ||= Line::Bot::Client.new { |config| config.channel_secret = ENV["LINE_CHANNEL_SECRET"] config.channel_token = ENV["LINE_CHANNEL_TOKEN"] } end def callback body = request.body.read signature = request.env['HTTP_X_LINE_SIGNATURE'] head :bad_request unless client.validate_signature(body, signature) events = client.parse_events_from(body) events.each do |event| next unless event.is_a?(Line::Bot::Event::Message) next unless event.type == Line::Bot::Event::MessageType::Text client.reply_message(event['replyToken'], message) end head :ok end def message # cf. https://developers.line.biz/ja/reference/messaging-api/#text-message { "type": 'text', "text": 'メッセージ' } endこの
message
に相当する部分を、マルコフ連鎖で生成した文章にさせます。マルコフ連鎖で文章を作る
マルコフ連鎖による文章作成の大枠については解説しているものがたくさんあるので、詳しくは「マルコフ連鎖 文章作成」とかで検索してください。
ざっくり説明すると、あらかじめ形態素解析(言語で意味をもつ最小単位に分解すること)によって言葉のつながりを学習させ、ある単語に対してそれに続く言葉を過去の学習から確率的に選択していくことでそれっぽい文章ができるやつです。
形態素解析する
形態素解析は、Yahoo!が提供している日本語形態素解析を使っています。MeCab(Natto)を使って、オタク用語に特化した辞書を入れるのもアリかなと思います。
LINEメッセージが送られたらそのメッセージをそのまま形態素解析します。結果をパースし、言葉と品詞がセットとなったハッシュの配列にします。3
単語として保存するWord
モデルと、つながりを保存するMarkovDic
モデルを作り、それぞれ保存します。
Word
モデル
カラム名 型 説明 pos String 品詞(例:名詞) surface String 単語(例:庭)
MarkovDic
モデル
カラム名 型 説明 prefix_1 String 単語のつながりをA-B-Cと表現したときのA (例:私) prefix_2 String 単語のつながりをA-B-Cと表現したときのB (例:は) suffix String 単語のつながりをA-B-Cと表現したときのC (例:犬) # 形態素解析を行い、WordレコードとMarkovDicレコードを作成する。名詞の配列を返す。 def record(text, user) text = remove_url(text) # URLを取り除いたりしている morphological_words = exec(text) poses = save_words(morphological_words, user) save_markov_dics(morphological_words) poses end # 単語を保存する。 def save_words(morphological_words) words = [] morphological_words.each do |word| w = Word.new(word) words << w.attributes.compact!.merge({ created_at: now, updated_at: now }) end Word.insert_all(words) if words.present? end def save_markov_dics(morphological_words) markov_dics = [] morphological_words.each_cons(3) do |p1, p2, suf| next if p1['surface'] == "\n" next if p2['surface'] == "\n" md = MarkovDic.new(prefix_1: p1['surface'], prefix_2: p2['surface'], suffix: suf['surface']) md.suffix = 'END_OF_SENTENCE' if md.suffix == "\n" # 文章の終わりを意味するフラグ markov_dics << md.attributes.compact!.merge({ created_at: now, updated_at: now }) end eos = morphological_words.last(2) if eos.size == 2 p1 = eos[0] p2 = eos[1] md = MarkovDic.new(prefix_1: p1['surface'], prefix_2: p2['surface'], suffix: 'END_OF_SENTENCE') markov_dics << md.attributes.compact!.merge({ created_at: now, updated_at: now }) end MarkovDic.insert_all(markov_dics) if markov_dics.present? end文章を作る
LINEに送られたメッセージを保存することができたので、今度は文章を作ります。
始まりの言葉は受け取ったLINEのメッセージからランダムに名詞で始まるMarkovDic
を選んでいます。
ざっくり以下のような感じです。def create_sentence(text, markov_dic) return text if markov_dic.suffix == 'END_OF_SENTENCE' next_markov_dic = MarkovDic.where(prefix_1: markov_dic.prefix_2, prefix_2: markov_dic.suffix).sample(1).first return text unless next_markov_dic text << markov_dic.suffix create_sentence(text, next_markov_dic) end def prefixes prefix_1 + prefix_2 endWebhook URLを設定する
作成したAPIサーバをデプロイします。(今回はHerokuにデプロイしました。)
最初に作成したアカウントの設定画面でWebhook URLを設定し、メッセージがきたタイミングでLINEがリクエストを送ってくれるようにします。
LINEグループに追加します。いい感じにレスポンスしてくれます。
その他
- グループラインにルビィちゃんを混ぜたところ、「かわいい」「キメラが誕生した」「新しいおもちゃ」と非常に好評でした。
- クソデカ羅生門を覚えさせた人がいてめちゃくちゃになりました。
- グループラインにBotアカウントは一つまでしか入れられないようです。黒澤姉妹で話すことはできませんでした。
- 常に返信がくるとグループラインがやかましくなるので、ランダムで投稿したりしなかったりさせています。(ちなみに直接ルビィちゃんに話しかけると100%返信が来ます。)
- push_messageを使うとルビィちゃんから話しかけることもできます。
- 本当はアカウントを紹介したいのですが、記録した言葉の中に含まれる個人情報を考慮すると中々難しいものがあります。
- 今の所ルビィちゃん要素が0なので、ルビィちゃんっぽくさせたいです。
まとめ
LINE Messaging API
とRuby
を用いて黒澤ルビィを作りました。LINE Botは意外と簡単に作ることができるので、ぜひ作ってみてください。
開発用のアカウントも合わせて作ったりしています。ちなみに画像は友達が描いたやつです。 ↩
以下を参考にしました。Ruby on Rails で Yahoo のテキスト解析 APIを使う-スケ郎のお話 ↩
- 投稿日:2021-01-10T16:00:06+09:00
【Ruby On Rails / HTML】ウェブページ表示時、カーソル(キャレット)を適当な場所へ合わせ表示する方法
備忘録です。
カーソルとキャレットとは
キャレット≒カーソル
マウスカーソルなどと区別したい場合にキャレットという言葉が用いられます。本題
カーソルを適当な場所へフォーカスするには、autofocusを使います。
Rubyでは、次のような書き方をしますautofocus: trueそれでは、Deviseの新規登録画面に"Nickname"という項目を設けた場合で見ていきます。
まずは"Nickname"にautofocusを使わない場合はどのように表示されるでしょうか。①"Nickname"にautofocusなし
new.html.erb<h2>Sign up</h2> <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> <div class="field"> <%= f.label :nickname, "Nickname" %><br /> <%= f.text_field :nickname %> </div> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> (後略)上記の場合、新規登録のウェブページを開いてみると、Nicknameではなく、Emailにカーソルがフォーカスされています。
次に、<%= f.text_field :nickname %>にautofocusを付与して、Nicknameにカーソルの焦点を当てた状態で見ていきます。
②"Nickname"にautofocusあり
new.html.erb<h2>Sign up</h2> <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> <div class="field"> <%= f.label :nickname, "Nickname" %><br /> <%= f.text_field :nickname, autofocus: true %> </div> <div class="field"> <%= f.label :email %><br /> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> </div> (後略)このようにautofocusを"Nickname"に付与してあげることで、自動的に一番最初にカーソルが当てられる場所がNicknameとなりました。
参考記事
https://www.sophia-it.com/content/%E3%82%AD%E3%83%A3%E3%83%AC%E3%83%83%E3%83%88
http://www.htmq.com/html5/input_autofocus.shtml
- 投稿日:2021-01-10T15:32:40+09:00
バックエンドの設計を任されたので、エンドポイント設計をしっかり学んでみる
はじめに
こんにちは、大学を休学してスタートアップでWebエンジニアとして働いてる、おにかんです。
現在、関わっているプロジェクトのエンドポイント設計を任されたので良い機会だと思い、1から勉強して、まとめてみました。何かご指摘等ありましたらコメントしていただけるとありがたいです。
エンドポイント設計を始めよう!
*そもそもエンドポイントとは?
APIにアクセスするためのURIという認識で問題ないかと思います。
基本的な考え方
URI設計は「シンプルでわかりやすい」ものであるべきです。なぜ「シンプルでわかりやすい」URIが良いのでしょうか?主な理由に「開発者のミスを減らすことができる」ということが挙げられます。例えば、下記の二つのURI、どちらがわかりやすいでしょうか?
api/v1/p/capi/v1/posts/comments前者の方は頭文字しかURIに反映されていなく、わかりにくいですよね。一方、後者はある投稿のコメントのリソースなのだな、となんとなく想像がつくかと思います。URIをわかりやすくすることで、開発者のミスを減らすことができ、結果的にサービスの品質が向上します。
「シンプルでわかりやすい」URI設計にするために、以降から具体的なtipsをまとめておきました。
【1】第三者が読んで理解できる
api/v1/p/c上記のようなエンドポイントでは何を示しているのか予想しにくいですよね。上記のような場合では少なくとも下記のように明確にリソースを示してあげた方が親切です。
api/v1/posts/comments【2】基本的には全て小文字を使う
どちらかに統一したほうがわかりやすいのでミスが減ります。
【3】他のエンドポイントと整合性をとる
例えば下記のようなエンドポイントは整合性が取れていません。(少し奇妙ですが)
api/v1/posts/:id api/v1/friends/?id=1上記は極端な例ですが、下記のようにできるかぎり形式を統一させたほうがわかりやすいかと思います。
api/v1/posts/:id api/v1/friends/:id基本的には、この三つが大切です。もっと細かい点で言うと
- 変更しやすいURL
- サーバーのアーキテクチャがわかりずらいURL
といったところでしょうか。
HTTPメソッドとエンドポイントの関係
URIとHTTPメソッドはそれぞれ、下記のような役割を持ちます。
URI:リソース(情報)
HTTPメソッド:動作つまり、URI(情報)をHTTPメソッドで操作することができます。例えば、HTTPメソッドの
GET
は「取得」を表すのでGET api/v1/posts/100とすると、PostのIDが100のデータ(リソース)を取得(動作)することができます
大切なことはURIと、HTTPメソッドは分離しているということです。URIで動作(例えば、取得や削除など)を指定することは推奨されませんし、HTTPメソッドがリソースの領域を侵すこともおすすめできません。
以下から主要なHTTPメソッドについて軽く解説していきます。
GET
GETメソッドは「取得」を示します。URIで指定されたリソースを取得してクライアントに返します。下記は例です。
GET api/v1/posts/100大切なことはGETメソッドで「情報(リソース)」の内容が変化してはいけない、ということです。リソースを作成したい場合は基本的には
Post
、更新はPUT
、またはPATCH
、削除にはDELETE
メソッドを使うべきです。POST
POSTメソッドは「作成」を示します。もっと言うと、「指定したURIに属するリソースを送信する」と言うことです。例を見てみましょう
POST api/v1/postsGETの時にあった、id指定がなくなっているのが確認できるかと思います。つまり、
Posts
に属する形でリソースが作られるということです。基本的に、POSTは「新規作成」に使われるべきであり、既存のリソースに対して何かしらの操作をしたい場合は、PUT
やDELETE
を使うと良いと思います。PUT
PUTメソッドは情報を「更新」される場合に使われます。PUTメソッドはPOSTと違って、更新したいURIを指定します。下記は例です。(実際にはクエリパラメータでデータを指定したりするのですが、今回は割愛)
PUT api/v1/posts/100POSTメソッドと違って、直接指定しているのが確認できると思います。(POSTは従属するリソースを作成する。)
ちなみに指定したリソースが存在しない場合、リソースの作成が行われます。しかし、リソースの作成には基本的にPOSTメソッドを使うべきです。DELETE
DELETEメソッドは指定したURIのリソースの「削除」を行います。
DELETE api/v1/posts/100PATCH
PATCHメソッドは、PUTと同じように「更新」の役割を持ちますが、全ての情報を更新するのではなく、一部の情報を更新します。
HTTPメソッドについては以上です。以降から、URIとHTTPメソッドを組み合わせて、具体的なエンドポイントの設計をしていきたいと思います。
実際にエンドポイントを設計する
基本的なリソースとHTTPメソッドについて見ていきました。ここから実際に二つを組み合わせて見ていきましょう!
今回は
member
というデータモデルに対して、エンドポイントを考えてみます。個別のデータを取得する
GET /members/:id
members
という集合データをid
で特定するというイメージです。基本的にはこの形が一般的です。全体を取得する
GET /members
members
の全ての情報を取得しています。また検索等は、このエンドポイント内のクエリパラメータで制御するイメージです。データの新規作成
POST /members今度は
id
指定されていません。これはPOST
メソッドであるため、members
に従属するデータを新規作成するというところからきています。データの更新
PUT /members/:id更新では、実際に更新する
member
を指定してあげるため、id
情報を与えています。データの削除
DELETE /members/:id削除の場合も同様に
member
を指定してあげるため、id
情報を与えています。基本的な部分は以上です。あとは実戦でフィードバックをもらいながらやっていくのがいいのかなと思います。
ではでは〜
- 投稿日:2021-01-10T14:17:32+09:00
[Ruby] ArgumentError の本質を見る
ArgumentError
Argumentとは"引数"と言う意味です。
ArgumentErrorは「引数の数が合わないよー」というメッセージになります。
様々なケースが考えられますので、
本質的な基礎の部分を例に考えて行こうと思います。
wikiで「Rubyを対話的に実行 (REPL) するためのシェル」と紹介されている
irbを使っていきます。下記の実引数と仮引数を用いたコードを、irbで実行
def test(number) puts number * number end test(5)
testの引数に(5)を設定して仮引数(number)に値を渡すと、
25という結果が出力されました。
エラーメッセージを翻訳するとこうです。
コンピューターさんがこう言ってます
「引数が1つあることを期待してたのに、0だったよ」
引数が一つ足りないんですね。
今度はこう言っていますね
「引数が1つあることを期待してたのに、2つだったよ」
一個多いよと怒っています。実引数(5, 6)を2つ送ろうとしても、受け取る側の仮引数(number)の数が1つだと上手くいかないんですね。
まとめ
ArgumentErrorは「引数の数が合わないよー」というエラーです。
メソッドを定義してる箇所の、実引数・仮引数を確認してみましょう!
- 投稿日:2021-01-10T12:58:15+09:00
[フォームオブジェクト]1つのフォームをPOSTでもPATCH(PUT)でも使えるようにする方法
1つのフォームを複数のHTTPメソッドで使い分ける方法です。
フォームオブジェクトで実装すると難しかったのでメモ。他にもっと良い方法がある場合は遠慮なく教えていただけると嬉しいです
こんな方にオススメ
・フォームオブジェクトでフォームを実装している方。
・フォームで情報を送信する際に、新規作成と編集で同じフォームを使いたい方。やることは2つだけ
(1) フォームを呼び出す側(render)に method: :〇〇を追加。(〇〇はpostやpatchなど)
(2) フォーム側に method: methodを追加。(1) フォームを呼び出す側
example.html.erb<%= render "フォームテンプレートのパス", url: 呼び出したいアクションのpath, method: :〇〇 %>新規作成の場合は〇〇をpostに、編集の場合はpatch(put)にすればOKです。
(2) フォーム側
_example_form.html.erb<%= form_with model: モデルのインスタンス, url: url, method: method do |f| %>普通はここでurlやmethodを直接指定すると思うのですが、あえて変数にしています。
そうすることで、新規作成でも編集でも使えるようにしています。背景
renderでPATCHのパス(url)を定義したはずなのに、実際にはPOSTで送信されていることがありました。原因は下記の記事にあるように、フォームのmodel: に記述したインスタンスが既存であればPATCH, 既存でなければPOSTとなるからだと思われます。フォームオブジェクトを使うとフォーム送信のたびにインスタンスを生成するので、常にPOSTとなり期待した動きをしてくれません。そこで、methodも定義してこの問題を回避しています。
参考にした記事はこちら
環境
ruby: 2.7.1
rails: 6.0.3.3
- 投稿日:2021-01-10T10:50:52+09:00
大貧民(どう書く)
http://nabetani.sakura.ne.jp/hena/ord5dahimi/
トランプゲーム「大貧民」(「大富豪」ともいいます)の場の札と手札が与えられた場合、次に出せるすべての手の組み合わせを出力する問題です。
ジョーカーがワイルドカードになっているので、それをどう処理するかが考えどころになります。ここではジョーカーが手札に含まれている場合の処理を別にしました。
Rubyclass Card Rank = %W(3 4 5 6 7 8 9 T J Q K A 2) def initialize(str) @value = str @rank = (str == "Jo") ? 13 : Rank.index(str[1]) end attr_reader :value, :rank alias to_s value end module Daihinmin module_function def play(input) table, hand = input.split(",") return "-" unless hand hand = hand.scan(/../).map { |c| Card.new(c) } joker = hand.find {|c| c.value == "Jo"} table = table.scan(/../).map { |c| Card.new(c) } t_rank = table.map(&:rank).min t_num = table.size cs = hand.group_by(&:rank).select { |k, v| k > t_rank }.values result = cs.select { |ary| ary.size >= t_num } .flat_map { |ary| ary.combination(t_num).to_a } if joker && t_num >= 2 result += cs.select { |ary| ary.size >= t_num - 1 && ary[0] != joker } .flat_map {|ary| ary.combination(t_num - 1).map { |cards| cards + [joker] } } end result.empty? ? "-" : result.map(&:join).join(",") end end if __FILE__ == $0 [ "DJ,", "H7,HK", "S3,D4D2", "S9,C8H4", "S6,S7STCK", "H4,SAS8CKH6S4", "ST,D6S8JoC7HQHAC2CK", "SA,HAD6S8S6D3C4H2C5D4CKHQS7D5", "S2,D8C9D6HQS7H4C6DTS5S6C7HAD4SQ", "Jo,HAC8DJSJDTH2", "S4Jo,CQS6C9DQH9S2D6S3", "CTDT,S9C2D9D3JoC6DASJS4", "H3D3,DQS2D6H9HAHTD7S6S7Jo", "D5Jo,CQDAH8C6C9DQH7S2SJCKH5", "C7H7,S7CTH8D5HACQS8JoD6SJS5H4", "SAHA,S7SKCTS3H9DJHJH7S5H2DKDQS4", "JoC8,H6D7C5S9CQH9STDTCAD9S5DAS2CT", "HTST,SJHJDJCJJoS3D2", "C7D7,S8D8JoCTDTD4CJ", "DJSJ,DTDKDQHQJoC2", "C3H3D3,CKH2DTD5H6S4CJS5C6H5S9CA", "D8H8S8,CQHJCJJoHQ", "H6D6S6,H8S8D8C8JoD2H2", "JoD4H4,D3H3S3C3CADASAD2", "DJHJSJ,SQDQJoHQCQC2CA", "H3D3Jo,D4SKH6CTS8SAS2CQH4HAC5DADKD9", "C3JoH3D3,S2S3H7HQCACTC2CKC6S7H5C7", "H5C5S5D5,C7S6D6C3H7HAH6H4C6HQC9", "H7S7C7D7,S5SAH5HAD5DAC5CA", "D4H4S4C4,S6SAH6HAD6DAC6CAJo", "DTCTSTHT,S3SQH3HQD3DQC3CQJo", "JoS8D8H8,S9DTH9CTD9STC9CAC2" ].each do |input| puts Daihinmin.play(input) end endカードをどう表現するか迷って、ここではクラス化しました(
Card
クラス)。カードのランクを数値化し、弱い順に 0 からの Integer を与えてあります(Card#rank
)。単独でいちばん強いジョーカーのランクは 13 です。String で表されるカードの表現はCard#value
で取得できます。処理としては、まず場の札を
table
、手札をhand
とします。ジョーカーが存在すればjoker
に入ります(存在しなければnil
)。
手札をランクによってグループ化し、場の札のランク(t_rank
)よりランクの高いものだけを残したのがcs
です。
cs
から、場の札の枚数(t_num
)以上のものを残し、あとは場の札の枚数だけの組み合わせを取ってresult
に格納します。
手札にジョーカーがあり、かつ場の札の枚数(t_num
)が2枚以上の場合は、ジョーカーをワイルドカードとしながらさらに同様のことをします。結果を String で表現する(Array#join を使っています)ため、
Card#to_s
をCard#value
のエイリアスとして設定しています。なお、出力は順序の不定性があるので、テストをサボっています(笑)。
追記
テストも書いてみました。
if __FILE__ == $0 def same?(input, expect) inputs = input.split(",") expects = expect.split(",") return false unless inputs.size == expects.size equal = ->(a, b) { a == b || a.scan(/../).sort == b.scan(/../).sort } is_found = ->(ans) { s = expects.find { |e| equal.(e, ans) } return false unless s expects.delete(s) true } inputs.all?(&is_found) end [ ["DJ,", "-"], ["H7,HK", "HK"], ["S3,D4D2", "D4,D2"], ["S9,C8H4", "-"], ["S6,S7STCK", "CK,ST,S7"], ["H4,SAS8CKH6S4", "S8,CK,H6,SA"], ["ST,D6S8JoC7HQHAC2CK", "Jo,C2,CK,HA,HQ"], ["SA,HAD6S8S6D3C4H2C5D4CKHQS7D5", "H2"], ["S2,D8C9D6HQS7H4C6DTS5S6C7HAD4SQ", "-"], ["Jo,HAC8DJSJDTH2", "-"], ["S4Jo,CQS6C9DQH9S2D6S3", "DQCQ,D6S6,H9C9"], ["CTDT,S9C2D9D3JoC6DASJS4", "JoC2,SJJo,DAJo"], ["H3D3,DQS2D6H9HAHTD7S6S7Jo", "JoHA,JoD6,JoH9,D6S6,D7S7,JoS6,HTJo,JoDQ,S2Jo,JoD7,JoS7"], ["D5Jo,CQDAH8C6C9DQH7S2SJCKH5", "CQDQ"], ["C7H7,S7CTH8D5HACQS8JoD6SJS5H4", "HAJo,JoSJ,H8S8,H8Jo,CQJo,CTJo,JoS8"], ["SAHA,S7SKCTS3H9DJHJH7S5H2DKDQS4", "-"], ["JoC8,H6D7C5S9CQH9STDTCAD9S5DAS2CT", "CTDT,H9D9,S9D9,DACA,CTST,H9S9,DTST"], ["HTST,SJHJDJCJJoS3D2", "DJCJ,SJDJ,JoHJ,CJHJ,SJJo,HJSJ,DJJo,JoCJ,JoD2,SJCJ,DJHJ"], ["C7D7,S8D8JoCTDTD4CJ", "D8S8,JoS8,CTJo,DTJo,JoCJ,CTDT,D8Jo"], ["DJSJ,DTDKDQHQJoC2", "JoDK,HQDQ,DQJo,C2Jo,JoHQ"], ["C3H3D3,CKH2DTD5H6S4CJS5C6H5S9CA", "S5H5D5"], ["D8H8S8,CQHJCJJoHQ", "JoCQHQ,JoHJCJ"], ["H6D6S6,H8S8D8C8JoD2H2", "D2H2Jo,D8JoS8,D8S8C8,C8D8H8,JoC8S8,H8JoC8,S8H8C8,JoS8H8,C8JoD8,D8H8S8,D8JoH8"], ["JoD4H4,D3H3S3C3CADASAD2", "DACASA"], ["DJHJSJ,SQDQJoHQCQC2CA", "SQJoCQ,DQCQJo,JoSQHQ,SQCQHQ,DQHQSQ,HQDQCQ,HQDQJo,SQDQCQ,CQJoHQ,SQJoDQ"], ["H3D3Jo,D4SKH6CTS8SAS2CQH4HAC5DADKD9", "HASADA"], ["C3JoH3D3,S2S3H7HQCACTC2CKC6S7H5C7", "-"], ["H5C5S5D5,C7S6D6C3H7HAH6H4C6HQC9", "C6D6S6H6"], ["H7S7C7D7,S5SAH5HAD5DAC5CA", "SADACAHA"], ["D4H4S4C4,S6SAH6HAD6DAC6CAJo", "C6H6S6D6,SAJoDACA,S6H6C6Jo,SACAJoHA,HADASAJo,HADAJoCA,CADAHASA,D6C6JoH6,S6D6C6Jo,H6JoS6D6"], ["DTCTSTHT,S3SQH3HQD3DQC3CQJo", "HQSQJoDQ,SQCQDQJo,DQCQHQJo,SQHQJoCQ,CQDQHQSQ"], ["JoS8D8H8,S9DTH9CTD9STC9CAC2", "H9C9D9S9"], ].each do |input, expect| p same? Daihinmin.play(input), expect end end
- 投稿日:2021-01-10T09:39:51+09:00
【Ruby】RubyでGmailを操作する基礎
出涸らし情報だけどRuby教えるときに便利なので手順メモ
Gmailのアプリパスワードを取得する
以下作業はこちらの画面で行います。
- Google 二段階認証を有効にする (これやらないとパスワードが取れない!)
- [パスワードとログイン方法] -> [2段階認証プロセス]
- SMSで認証して有効化させる
- アプリパスワードを取得する
- [パスワードとログイン方法] -> [アプリパスワード]
- [アプリを選択]と[デバイスを選択]をそれぞれ入力 (本人が管理できればなんでもいい。。はず)
- アプリパスワードが生成されるので控えておく
gem mail をインストール
$ gem mail installサンプルコードを書く
send_gmail.rbrequire 'mail' from = 'my_gmail_address@gmail.com' password = '16_digit_app_password' to = 'to_address@gmail.com' Mail.defaults do delivery_method :smtp, { address: 'smtp.gmail.com', port: 587, domain: 'example.com', user_name: from, password: password, authentication: :login, enable_starttls_auto: true } end m = Mail.new do from "#{from}" to "#{to}" subject "Great Mail Title" body "Fantastic body blar blar" end m.charset = "UTF-8" m.content_transfer_encoding = "8bit" m.deliver取り敢えずこれで動くはず。
参考情報
Ruby を使って Gmail 経由でメール送信
http://1bed.allright.life/?p=2004
- 投稿日:2021-01-10T09:39:51+09:00
RubyでGmailを送信する基礎
出涸らし情報だけどRuby教えるときに便利なので手順メモ
Gmailのアプリパスワードを取得する
以下作業はこちらの画面で行います。
- Google 二段階認証を有効にする (これやらないとパスワードが取れない!)
- [パスワードとログイン方法] -> [2段階認証プロセス]
- SMSで認証して有効化させる
- アプリパスワードを取得する
- [パスワードとログイン方法] -> [アプリパスワード]
- [アプリを選択]と[デバイスを選択]をそれぞれ入力 (本人が管理できればなんでもいい。。はず)
- アプリパスワードが生成されるので控えておく
gem mail をインストール
$ gem mail installサンプルコードを書く
send_gmail.rbrequire 'mail' from = 'my_gmail_address@gmail.com' password = '16_digit_app_password' to = 'to_address@gmail.com' Mail.defaults do delivery_method :smtp, { address: 'smtp.gmail.com', port: 587, domain: 'example.com', user_name: from, password: password, authentication: :login, enable_starttls_auto: true } end m = Mail.new do from "#{from}" to "#{to}" subject "Great Mail Title" body "Fantastic body blar blar" end m.charset = "UTF-8" m.content_transfer_encoding = "8bit" m.deliver取り敢えずこれで動くはず。
参考情報
Ruby を使って Gmail 経由でメール送信
http://1bed.allright.life/?p=2004
- 投稿日:2021-01-10T06:58:17+09:00
rake routes をしたら、怒られた。yarnのバージョンが低いってばよ
rake routes error Couldn't find an integrity file error Found 1 errors. ======================================== Your Yarn packages are out of date! Please run `yarn install --check-files` to update. ======================================== To disable this check, please change `check_yarn_integrity` to `false` in your webpacker config file (config/webpacker.yml). yarn check v1.22.10 info Visit https://yarnpkg.com/en/docs/cli/check for documentation about this command. koyoishikawa@ishikawyounoAir Ruby_on_rails_task_2 % yarn install --check-files yarn install v1.22.10 [1/4] ? Resolving packages... [2/4] ? Fetching packages... [3/4] ? Linking dependencies... warning " > webpack-dev-server@3.11.0" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". warning "webpack-dev-server > webpack-dev-middleware@3.7.2" has unmet peer dependency "webpack@^4.0.0". [4/4] ? Building fresh packages... ✨ Done in 341.25s.
- 投稿日:2021-01-10T01:31:51+09:00
RSpecの導入&関係の深いgemについて
Ruby on Railsのテスト用のgemであるRSpecの導入と関係するgemについて整理します。
RSpecとは
Ruby on Railsのテストコードを書くために用いられるgemです。
実際のgem名は「rspec-rails」です。ユーザーの新規登録やログイン、メッセージの投稿や編集などの機能をテストするために使用します。
Rubyには標準でmini_testという別のテスト用Gemが導入されているのですが、開発現場ではRSpecが主流だそうです。
RSpecのインストール
Gemfile
に以下のように記述し、ターミナルでbundle install
を入力します。Gemfile#group :development, :testというグループの中に記述する。 group :development, :test do gem 'rspec-rails', '~> 4.0.0' endターミナルbundle installRSpecの設定をする
ターミナルで以下のとおり入力して、ディレクトリとファイルを生成します。
ターミナルrails g rspec:install #上記実行後、下記のディレクトリとファイルが生成される create .rspec create spec create spec/spec_helper.rb create spec/rails_helper.rb
.rspec
ファイルに以下の記述をします。テストコードの実行結果をターミナル上に可視化するために記述します。.rspec--require spec_helper --format documentation #この一文を追加RSpecについてはここまです。
RSpecと関係の深いgem
RSpecとよく一緒に使用するgemとしてFactoryBotとFakerがあります。
FactoryBotとは
インスタンスをまとめることができるgemで、他のファイルであらかじめ各クラスのインスタンスに定める値を設定しておき、各テストコードで使用します。
RSpecと同様にGemfileの
group :development, :test
というグループの中に記述してからインストールします。Gemfilegroup :development, :test do gem 'factory_bot_rails' endターミナルbundle install簡単な紹介になりますが、FactoryBotは以下のように記述して使います。※アプリにUsersテーブルがあると想定
spec/factories/users.rbFactoryBot.define do factory :user do name {"sample"} email {"sample@mail"} password {"sample777"} end endこのように記述することで、テストで使用するユーザーの情報を事前に用意しておくことができます。
Fakerとは
ランダムな値を生成するgemで,メールアドレス、人名、パスワードなどのランダムな値を生成してくれます。
RSpecと同様にGemfileのgroup :development, :test
というグループの中に記述してからインストールします。Gemfilegroup :development, :test do gem 'faker ' endターミナルbundle installFakerはこんな感じでランダムな値を生成します。
spec/factories/users.rbFactoryBot.define do factory :user do name { Faker::Name.initials(number: 5) } email { Faker::Internet.free_email } password { Faker::Internet.password(min_length: 6) } end endFactoryBotとFakerでできること
テストコードを実行するたびにランダムな値でインスタンスを生成することができます。
テストをするアプリにユーザー管理機能がある場合、emailなどのカラムをテーブルに用意されていると思いますが、複数のテストを行う際に、「すでにemailの重複したインスタンスが存在する」といったような意図しない形でテストエラーが出てしまうことを防ぐのに役立ちます。今回はここまでで、次の記事でRSpecを使った単体テストについて取り上げたいと思います。
参考資料
RSpecの公式GitHub
FactoryBot(factory_bot_rails)の公式GitHub
Fakerの公式GitHub