20210415のRubyに関する記事は11件です。

createアクションが動かない!【Ruby on rails】

はじめに Ruby on Rails チュートリアル(以下:レイチュー)をなんとか2周し終え、意気揚々とオリジナルサイトを作り始めましたが、序盤も序盤createアクションを押しても、ページに何も変化がないという状況になりました。 qiitaに投稿したことがなかったので投稿の仕方を確認する意味合いも込めて解決までの道のりを記していく。 環境 Rails6.0.3, macOS Catalina 10.15.7 何が起きた? ユーザー登録機能を実装しようとform_withで雛形を作りいざ登録ボタンを押しても画面に何も変化が起きませんでした。 new.html.erb <div class="row"> <div class="col-md-6 col-md-offset-3"> <%= form_with model: @user, url: sign_in_path, do |f| %> <%= f.label :name %> <%= f.text_field :name %> <%= f.label :email %> <%= f.email_field :email %> <%= f.label :password %> <%= f.password_field :password %> <%= f.label :password_confirmation, "Confirmation" %> <%= f.password_field :password_confirmation %> <%= f.submit "Create my account", class: "btn btn-primary" %> <% end %> </div> </div> コントローラルートなどを確認したが問題はなさそう。(いつものやつ) users.controller.rb class UsersController < ApplicationController def new @user = User.new end def create @user = User.new(user_params) if @user.save # 保存の成功をここで扱う。 redirect_to @user else render 'new' end end def show @user = User.find(params[:id]) end private def user_params params.require(:user).permit(:name, :email, :password, :password_confimation) end end 何があかんのや。。。 解決 そもそも登録ボタンを押した時にエラーすら出ず、ページにも変化がない為form_withに何か問題があるのではと仮定。 レイチューの登録の章を見ると 「local: true 」がform_withの中に入っていることを確認。 これを入れるとうまく反応するようになりました。 学び local: trueはなぜ入れるのか 結論から言うとform_withではデフォルトでAjax通信をしているので非同期通信になるとのこと。 この状態だと必要な箇所だけが更新されて、そうでないところはそのままの状態になってしまう。 ここにlocal: trueと引数を渡す事によって、通常のHTTPリクエストになり、ページ全体が返ってきてページがリロードされるのでうまく動いたと言うことです。 最後に レイチューをやっているだけでは躓かなかった箇所で躓いたのでやはり自分で作ってみると言うのは大事だと身をもって実感した。 qiitaの投稿は書いていく内に自分の考えを整理でき、何が分かっていないのかを浮き彫りにすることができるので、自分の勉強のためにも非常に良い。 人の役に立つような発信ができるよう精進していく。 参考 @kakudaisuke https://qiita.com/kakudaisuke/items/e032c7705db00e8081dc?utm_campaign=popular_items&utm_medium=feed&utm_source=popular_items 記事の書き方なども含めて参考にさせていただきました。 引用する時本人の許可いるのかしら? qiitaの使い方も勉強します。。。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Bootstrap4 カルーセル (Carousel) が上手く動かない

背景 : Bootstrapマニュアルによると、以下をコピペすれば動くとのことだが、上手くいかない。 ruby:html.erb <div id="carouselExampleControls" class="carousel slide" data-ride="carousel"> <div class="carousel-inner"> <div class="carousel-item active"> <img class="d-block w-100" src=".../800x400?auto=yes&bg=777&fg=555&text=First slide" alt="First slide"> </div> <div class="carousel-item"> <img class="d-block w-100" src=".../800x400?auto=yes&bg=666&fg=444&text=Second slide" alt="Second slide"> </div> <div class="carousel-item"> <img class="d-block w-100" src=".../800x400?auto=yes&bg=555&fg=333&text=Third slide" alt="Third slide"> </div> </div> <a class="carousel-control-prev" href="#carouselExampleControls" role="button" data-slide="prev"> <span class="carousel-control-prev-icon" aria-hidden="true"></span> <span class="sr-only">Previous</span> </a> <a class="carousel-control-next" href="#carouselExampleControls" role="button" data-slide="next"> <span class="carousel-control-next-icon" aria-hidden="true"></span> <span class="sr-only">Next</span> </a> </div> 解法 : 以下を先頭に足すと解決した <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby基礎(競技プログラミング過去問より)

概要 どうも、島生まれの地元が好きすぎて名前が島んちゅぬ宝をなんとなく英語っぽくしてみたIslanders-Treasure0969です。 私は現在常用雇用型派遣でとある業務アプリケーションを開発する企業の導入/開発エンジニアとして勤務しています。 そんな中、Web系の可能性に魅力を感じて現在転職活動のための勉強&ポートフォリオ作りの真っ最中です。 転職活動の勉強とポートフォリオをしている側、ふとしたきっかけで最近競技プログラミングを始めてみました。 理由としては以下のとおりです。 ①生のRubyをたくさん触って慣れたい ②フレームワークに頼らない低レイヤーの実装力も鍛えたい そこで、競技プログラミングでコンテストに出たり、過去問を解いていく上で、ヒントになったことや考え方をQiitaにまとめようと思いました。 尚、ここで取り上げる過去問は以下に表示している@drkenさんさんの記事の中で取り組んでおいた方がいい 過去問が厳選されておりましたので、そちらを解いていき、随時更新する形になります。 また、リンクの記事の順番で解いていくわけではないので、ご了承ください。 当方Ruby歴3ヶ月程度の、業務でRubyを使ったことのない、所謂ペーペーなので実装上変なところとか、クソコードが散見されると思うので、見つけたらどしどしマサカリお願いします!! 記載方法 内容は以下のように記載していきます。 コンテスト番号 ①問題の難易度-タイトル ②回答 ③実装上で悩んだこと・Tips ④参考URL ⑤(あれば)所感 ABC-198 B-Palindrome with leading zeros 回答 sample.rb str = gets.chomp.to_s def prefixzerotrim(s) s_index = s.length - 1 news = "" s.chars.to_a.each_with_index do | n, i | if n != "0" return news = s[i..s_index].to_s else end end return s end s1 = prefixzerotrim(prefixzerotrim(str).reverse) s2 = s1.reverse s1 == s2 ? puts('Yes') : puts('No') 実装上で悩んだこと・Tips ①問題の意図を理解するのに時間がかかった。 以下問題文抜粋 整数N を標準入力として与えた時にN を十進法で表した文字列の先頭に 0 個以上の 0 をつけることで、回文にすることはできますか? 最初は回文にするのに、文字列の後ろの0と数を合わせないといけないのかと思っていた。 結果的なアプローチとしては以下のようになった ・0を先頭につけて回文になるということは、先頭と末尾の連続した0を除外することでも回文となることを理解する ・先頭と末尾の0をトリムして文字列比較する ②関数で0を除いた文字列を返す方法 ・文字列を先頭から走査して、0以外の文字列が出てきたところでその位置から後を新しい 文字列として返すように実装した ・また、DRY原則にならって末尾の0については戻り値の文字列を反転させて再度関数に投げるようにした 2021/4/17 ③配列のインデックス指定、関数の戻り値 @superrino130 さんのコメントを受けての気づきです、ありがとうございます。 配列のインデックスにはマイナスでの指定も可能なようです! return news = s[i..-1] #=> 一番最後の要素までを指定 後、rubyには関数の戻り値を指定する必要はなく、returnで返す値がそのまま返るということでした! 参考URL ↓↓↓↓↓↓↓ あなたの記事の内容 each_with_indexの使い方(るびま) 配列 負のインデックス操作 ─────── each_with_indexの使い方(るびま) ↑↑↑↑↑↑↑ 編集リクエストの内容 所感 2021/4/15現在で初受験のABCテストで、実装力なさすぎて解けなかった問題です。。。 よくよく考えたら、そんなに難しい問題じゃなかったですね。 初心者の自分には文字列とかその他言語に慣れるためにちょうどいい難易度だと思いました! そして最初から冒頭のURL以外の問題を解くという。。。 まー緩く楽しくやれればいいか。 ABC-082 B-Two Anagrams 回答 sample.rb s1 = gets.chomp.chars.sort.join t1 = gets.chomp.chars.sort.reverse.join s1 < t1 ? puts('Yes') : puts('No') 実装上で悩んだこと・Tips ①配列→文字列変換でだいぶ悩んだ 以下実験内容 sample.rb s = gets.chomp.chars.sort.to_s t = gets.chomp.chars.sort.reverse.to_s puts("#{s} #{s.class}") puts("#{t} #{t.class}") s < t ? puts('Yes') : puts('No') s1 = gets.chomp.chars.sort.join t1 = gets.chomp.chars.sort.reverse.join puts("#{s1} #{s1.class}") puts("#{t1} #{t1.class}") s1 < t1 ? puts('Yes') : puts('No') #入力 #adebc #a #adebc #a #出力 #["a", "b", "c", "d", "e"] String #["a"] String #Yes #abcde String #a String #No 文字列をソートして比較するときに、sortメソッドが返す値を気にしておらず、このように記載してしまった 変数sに格納されているのは、["a","b","c","d","e"]という文字列になる lengthで長さを出力するとわかるが、25と出る。 最初この挙動に少し悩んでしまった。 だが、るりまにも書いてあるとおり、 配列の内容をソートします。要素同士の比較は <=> 演算子を使って行います。sort はソートされた配列を生成して返します。 とのことなので、返ってくる値は配列であり、これをto_sで文字列にしても上記のようになる。 そこで、結果としてはjoinを使用してソートした結果の配列を文字列に結合する必要がある。 joinについてのるりまの説明は以下。 要素がまた配列であれば再帰的に (同じ sep を利用して) join した文字列を連結します。 また、joinメソッドは引数にとった文字列を配列間に挿入して返すこともできるらしい。 sample.rb s1 = gets.chomp.chars.sort.join('&') puts("#{s1} #{s1.class}") #a&b&c&d&e String 参考URL join(るりま) sort(るりま) 所感 配列と文字列の関係が少しだけわかった気がした。 配列と文字列と少しだけ仲良くなれた。 発展的な内容として、文字列は結果的にバイトで比較するようなので、最初からバイトで比較すれば実行結果もまだ早くなる? なんか他の人のソースみたときに受けた値をバイトに直して比較しているのがあったので、実行結果を考えるならそっちの方がいいと思った(ソースとしては長くなるけど) こんなんとか ソース書いてる人 随時更新予定!! 2021/04/15 とりま、茶コーダーなるために3完目指します!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rbenvの簡単な備忘録

rbenvとは 複数のRubyのバージョンを管理し、プロジェクトごとにRubyのバージョンを指定して使うことを可能としてくれるツールです。 引用:rbenvでRubyを管理し、Rails開発環境を構築する つまりrbenvをインストールしていれば自分のPCのRubyのバージョンを簡単に切り替えることが出来るようになります。 1つだけ注意 互換性に関する注意:rbenvはRVMと互換性がありません。rbenvをインストールする前に、必ずRVMを完全にアンインストールし、シェル初期化ファイルからRVMへの参照を削除してください とのことです。(GitHub公式より引用) GitHub公式 各コマンド一覧 macOSを使用している場合はHomebrewを使用したインストールがオススメです。 ・rbenvのインストール brew install rbenv ・バージョンの確認 rbenv -v ・インストール可能な最新の安定バージョンだけを表示 rbenv install -l ・インストール可能なすべてのローカルバージョンを表示 rbenv install -L ・Rubyバージョンを指定してインストール rbenv install x.x.x(バージョンの番号を指定) ・現在設定中のバージョンの確認 rbenv version ・rbenvで管理しているインストール済みのRubyのバージョンを表示 rbenv versions ・デフォルトのRubyのバージョンを指定 rbenv global x.x.x(バージョンの番号を指定) ・そのディレクトリ以下で適用されるRubyのローカルバージョンを指定(グローバルより優先) rbenv local x.x.x(バージョンの番号を指定) ・ローカルバージョンの解除 rbenv local --unset ・新しいバージョンのRubyをインストールした後、またはコマンドを提供するgemをインストールした後に実行するコマンド rbenv rehash rbenv rehashについての詳細は以下の参考ページにて 【参考リンク】 ・rbenv rehashをちゃんと理解する ・rbenv rehashは何をやっているのか? ・rbenvの使い方と仕組みについて 参考サイト ・rbenvでRubyを管理し、Rails開発環境を構築する ・rbenvの使い方と仕組みについて
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

# エラー : [Autoprefixer doesn’t support Node v8.10.0. Update it.] が表示される.

背景 「Railsチュートリアル」ではBootstrap3を利用しているが、これをBootstrap4に変更したところ、上記のエラーが発生した。 原因 AutoprefixerというGemがNode.jsのversion 8.10.0を受け付けていないため、アップデートが必要とのこと。 解法 [mini-racer]というGemを追加する。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【RSpec】Active Hashを用いたカテゴリーでテストをパスする方法

https://teratail.com/questions/275207 結論この記事 今回は、active hashを用いたカテゴリーの際に、テストがパスしずらい問題を解決していきます 詳しくいうと、 コントローラーの単体テストで、 it 'showアクションにリクエストすると,そのコーヒーの産地が表示' do get drink_path(@drink) expect(response.body).to include('マルチリージョン') end このようなテストがパスできなかったです。 期待する動作としては、 この画像の右部分に, 「産地 マルチリージョン」 とあるので、上記のようなテストを書きましたが、 drinks/show.html.erb <% if @drink.region %> <th class="region-title">産地 </th> <td class="region-name"><%= @drink.region.name%> </td> <% end %> @drinks.region.name には、「マルチリージョン」という文字が入って欲しかったのですが、 上記のテストを実行した結果、 Drinks GET #show showアクションにリクエストすると,そのコーヒーの産地が表示 Failure/Error: expect(response.body).to include('マルチリージョン') expected "\n<!DOCTYPE html>\n<html>\n <head>\n <title>Details | Coffee Passport</title>\n \n \n\n ...script src=\"/packs-test/js/footer-c1b52f0e268f9a453b2e.js\"></script>\n \n </body>\n</html>\n\n" to include "マルチリージョン" Diff: 中略 + <tr class="item-region"> + <th class="region-title">産地 </th> + <td class="region-name"> </td> + </tr> このようなHTMLが返され、 <td class="region-name"> </td> ここに @drink.region.nameが入るはずですが、 何も入ってなかったので、色々試しました。 色々試した結果は、「teratailに質問しようとした文」の部分に色々書いてあります。 該当のコード drinks/show.html.erb <% if @drink.region %> <th class="region-title">産地 </th> <td class="region-name"><%= @drink.region.name%> </td> <% end %> models/region.rb class Region < ActiveHash::Base self.data = [ { id: 1, name: '---'}, { id: 2, name: 'マルチリージョン' }, { id: 3, name: 'ラテンアメリカ' }, { id: 4, name: 'アフリカ' }, { id: 5, name: 'アジア、太平洋' } ] end factories/drinks.rb FactoryBot.define do factory :drink do name {"TOKYOロースト"} price {350} explain {"これはコーヒーの説明です"} region_id {2} このようなactive hashを用いた構成の場合に、しっかり<%= @drink.region.name%> が表示されてるか確かめたいので、 spec/requests/drinks_spec.rb it 'showアクションにリクエストすると,そのコーヒーの産地が表示' do get drink_path(@drink) expect(response.body).to include('マルチリージョン') end と、テストを書いた。 しかし、これだと、先ほど説明した通りに上手くいかない spec/requests/drinks_spec.rb require 'rails_helper' # bundle exec rspec spec/requests/tweets_spec.rb RSpec.describe "Drinks", type: :request do before do @user = FactoryBot.create(:user) region_id = Region.find_by(name: 'マルチリージョン').id body_id = Body.find_by(name: "LIGHT(軽い)").id acidity_id = Acidity.find_by(name: "LOW(少ない)").id processing_id = Processing.find_by(name: "WASHED(水洗式)").id @drink = FactoryBot.create(:drink, name: "TOKYOロースト", price: 350, explain: "これはコーヒーの説明です", region_id: region_id, body_id: body_id, acidity_id: acidity_id, processing_id: processing_id) 結論このように書けば上手くいく models/region.rb class Region < ActiveHash::Base self.data = [ { id: 1, name: '---'}, { id: 2, name: 'マルチリージョン' }, { id: 3, name: 'ラテンアメリカ' }, { id: 4, name: 'アフリカ' }, { id: 5, name: 'アジア、太平洋' } ] end spec/requests/drinks_spec.rb region_id = Region.find_by(name: 'マルチリージョン').id @drink = FactoryBot.create(:drink, name: "TOKYOロースト", price: 350, explain: "これはコーヒーの説明です", region_id: region_id, これで、うまいこと取得できて、テストをパスできる 多分これは冗長で、ベストプラクティスではないような気がするので、プロのRubistの皆さんにご意見をお伺いしたいと思うので、それを追記していきます。 teratailに質問しようとした文 このアプリのgithub 起きてる問題点はこれに近いです 発生している問題・エラーメッセージ Drinks GET #show showアクションにリクエストすると,そのコーヒーの産地が表示 Failure/Error: expect(response.body).to include('マルチリージョン') expected "\n<!DOCTYPE html>\n<html>\n <head>\n <title>Details | Coffee Passport</title>\n \n \n\n ...script src=\"/packs-test/js/footer-c1b52f0e268f9a453b2e.js\"></script>\n \n </body>\n</html>\n\n" to include "マルチリージョン" Diff: 中略 + <tr class="item-region"> + <th class="region-title">産地 </th> + <td class="region-name"> </td> + </tr> <td class="region-name"> </td> ここに、コーヒーの産地が表示されるはずですが、テストで返されたHTMLには表示されてないので、テストがパスできません。 原因は、 この画像の、この投稿の産地の部分の「マルチリージョン」とか 、コクの「LIGHT(軽い)」の部分とかが、上手く表示されてないです。 該当のソースコード drinks/show.html <% if @drink.region %> <th class="region-title">産地 </th> <td class="region-name"><%= @drink.region.name%> </td> <% end %> と、こんな感じで、drinks/showでは、 その投稿の産地の名前が表示される仕様になっています region.rb class Region < ActiveHash::Base self.data = [ { id: 1, name: '---'}, { id: 2, name: 'マルチリージョン' }, { id: 3, name: 'ラテンアメリカ' }, { id: 4, name: 'アフリカ' }, { id: 5, name: 'アジア、太平洋' } ] end ここで、Active Hashを用いてることが原因となっております drinks_spec.rb it 'showアクションにリクエストすると,そのコーヒーの産地が表示' do get drink_path(@drink) expect(response.body).to include('マルチリージョン') end spec/factories/drinks.rb FactoryBot.define do factory :drink do name {"TOKYOロースト"} price {350} explain {"これはコーヒーの説明です"} region_id {Region.all.sample} body_id {Body.all.sample} acidity_id {Acidity.all.sample} processing_id {Processing.all.sample} likes_count {2} association :user association :region association :body association :acidity association :processing after(:build) do |drink| drink.image.attach(io: File.open('app/assets/images/ethiopia.jpg'), filename: 'ethiopia.jpg') end end end spec/factories/regions.rb FactoryBot.define do factory :region do end end 試したこと この二つの記事を参考にして、 まず、factorybot同士でアソシエーションを組んでないから、@drink.region.nameが表示されないと思って、 spec/factories/regions.rb FactoryBot.define do factory :region do association :drink end end と記述したら 死ぬほど長いエラーが表示され、SystemStackError stack level too deep こんな感じのエラーが出ました。 次に app/models/region.rb class Region < ActiveHash::Base self.data = [ { id: 1, name: '---'}, { id: 2, name: 'マルチリージョン' }, { id: 3, name: 'ラテンアメリカ' }, { id: 4, name: 'アフリカ' }, { id: 5, name: 'アジア、太平洋' } ] + include ActiveHash::Associations + has_many :drink end このように記述しました 一番最初のエラーと変わりませんでした。 factories/region.rb FactoryBot.define do factory :region do 2 {'マルチリージョン'} end end このように記述したら SyntaxError: /coffee_passport/spec/factories/regions.rb:3: syntax error, unexpected '{', expecting end 2 {'マルチリージョン'} ^ このようなエラーになりました。 factores/drinks.rb に region_id {Region.second} このように記述しなおしたら Failure/Error: region_id {Region.second} NoMethodError: undefined method `second' for Region:Class Did you mean? send とエラーが表示されました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RSpec単体テストコードのexpected [] to includeの解決方法

RSpec単体テストコードのときたまにこのようなエラーを起こしてしまうことがある。 ターミナル Failures: 1) ShippingAddress 配送先の情報として、郵便番号が必須であること Failure/Error: expect(@userpurchases.errors.full_messages). to include ("Post code can't be blank") expected [] to include "Post code can't be blank" # ./spec/models/shipping_address_spec.rb:12:in `block (2 levels) in <top (required)>' 2) ShippingAddress 配送先の情報として、都道府県が必須であること Failure/Error: expect(@userpurchases.errors.full_messages). to include ("Prefecture_id can't be blank") expected [] to include "Prefecture_id can't be blank" # ./spec/models/shipping_address_spec.rb:18:in `block (2 levels) in <top (required)>' 3) ShippingAddress 配送先の情報として、市区町村が必須であること Failure/Error: expect(@userpurchases.errors.full_messages). to include ("Municipality can't be blank") expected [] to include "Municipality can't be blank" # ./spec/models/shipping_address_spec.rb:23:in `block (2 levels) in <top (required)>' 4) ShippingAddress 配送先の情報として、番地が必須であること Failure/Error: expect(@userpurchases.errors.full_messages). to include ("Address can't be blank") expected [] to include "Address can't be blank" # ./spec/models/shipping_address_spec.rb:28:in `block (2 levels) in <top (required)>' 5) ShippingAddress 配送先の情報として、電話番号が必須であること Failure/Error: expect(@userpurchases.errors.full_messages). to include ("Phone_number can't be blank") expected [] to include "Phone_number can't be blank" # ./spec/models/shipping_address_spec.rb:33:in `block (2 levels) in <top (required)>' expected[]to includeというエラーが出ており要するにうまくデータを持ってこれていない。 原因としてはdescribeの記述や各exampleのモデル名が間違っている可能性がある。 単体テストコードはモデルファイルのバリデーションがうまく機能しているかどうかのテストなのでモデルファイルと同じ記述にする必要がある。 RSpec.describe UserPurchases, type: :model do before do @user_purchases = FactoryBot.build(:user_purchases) end it '配送先の情報として、郵便番号が必須であること' do @user_purchases.post_code = nil @user_purchases.valid? expect(@user_purchases.errors.full_messages). to include ("Post code can't be blank") end it '配送先の情報として、都道府県が必須であること' do @user_purchases.prefecture_id = 0 @user_purchases.valid? expect(@user_purchases.errors.full_messages). to include ("Address is invalid. Include hyphen(-)") end it '配送先の情報として、市区町村が必須であること' do @user_purchases.municipality = nil @user_purchases.valid? expect(@user_purchases.errors.full_messages). to include ("Municipality can't be blank") end it '配送先の情報として、番地が必須であること' do @user_purchases.address = nil @user_purchases.valid? expect(@user_purchases.errors.full_messages). to include ("Address can't be blank") end it '配送先の情報として、電話番号が必須であること' do @user_purchases.phone_number = nil @user_purchases.valid? expect(@user_purchases.errors.full_messages). to include ( "Phone number can't be blank") この場合テストしたいモデルファイル名はuser_purchases.rbなので RSpec.describe UserPurchasesとし、 モデル名を@user_purchasesに変更した。 データを取れていない場合は大抵このような理由が多いようだ。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

herokuエラー H12:Request timeout

開発途中でHerokuでデプロイしたwebアプリを確認中に出てきたエラーに関してです。 画像つきで投稿機能があるアプリで、画像一覧が表記されずにこのエラーが発生しました。WiFiの調子が悪かったりなどもあり、はっきりとした原因はわかりませんでしたが、解決しました。 結果 AWSのS3を利用して画像を管理することで解決しました。 画像1つは1MB程度ですが、一覧で十数枚が一度に出てくる画面だったので、WiFiの環境も影響してリクエストタイムアウトが出たものと思います。 S3の設定方法に関しては公式ページ(下記参照)をご確認ください。※後日まとめてアップ予定です 何が起きたのか デプロイ済の対象ページへ遷移しようとした際になかなか繋がらず、 Application error An error occurred in the application and your page could not be served. If you are the application owner, check your logs for details. You can do this from the Heroku CLI with the command と表記が出てきました。 確かに長いこと読み込んでいたので、おかしいとは思いましたが、、 ここで指示にある[check your logs for details]通りに、herokuのエラーログを確認しました。 エラーログの確認はアプリのターミナルで heroku logs --tail を実行し確認したところ、長いエラー文の中より heroku[router]: at=error code=H12 desc="Request timeout" という文を見つけました。 パっと見た感じでも、どうやら時間がオーバーの様子。 Herokuのエラーコード(下記参照)にて確認してみると 30秒を超えると強制終了されるそう。 Heroku によって処理される Web リクエストは、いくつかの Heroku ルーター を経由して dyno に転送されます。これらのリクエストは、アプリケーションですぐに処理されることになっています。ベストプラクティスは、Web アプリケーションの応答時間を 500 ミリ秒未満にすることで、これによりアプリケーションが解放されてさらに多くのリクエストを受けられるようになり、訪問者に対して高品質のユーザーエクスペリエンスを提供できます。たまに Web リクエストが異常停止したり、アプリケーションによる処理に非常に時間がかかったりすることがあります。このような場合、完了までにかかる時間が 30 秒を超えると、ルーターはリクエストを強制終了します。 また、サイズの大きいファイルはアップロードが原因である可能性が書かれていましたので、下記の通りS3を利用しました。 多くの Web アプリケーションではユーザーがファイルをアップロードできます。これらのファイルのサイズが大きかったり、ユーザーのインターネット接続が遅い場合、アップロードにかかる時間が 30 秒を超えることがあります。リクエストをブロックする一部の種類の Web アプリケーションでは、これにより H12 リクエストタイムアウトが発生することがあります。これについては、 S3 に直接アップロードする ことをお勧めします。 サイズの大きいファイルとは4MBを超える可能性のあるアップロードだそうです。今回はそこまで大きくないはずですが、トータルの大きさでしょうか(知識不足すみません。。) 直接アップロードでは、ファイルは最初にアプリを経由せずに、ユーザーのブラウザーからS3バケットにアップロードされます。この方法は、サイズが4MBを超える可能性のあるユーザーのアップロードに推奨されます。 上記により問題なく表示はされるようになりました。 が、時々遅いことがあるので少し不安はありますが。。 何かわかれば追記させていただきます。 参照リンク AWS公式リンク https://aws.amazon.com/jp/ エラーコード一覧 https://devcenter.heroku.com/ja/articles/error-codes リクエストタイムアウト詳細 https://devcenter.heroku.com/ja/articles/request-timeout AWSS3を使用して静的アセットとファイルアップロードを保存する https://devcenter.heroku.com/articles/s3#direct-upload
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubyで土日(週末)を判定するプログラム 〜いかに初心者な書き方から脱するか〜

やりたいこと どうも、初心者Ruby書きです。 先日、モジモジしながら社内で 「土日を判定するRubyのメソッドを書いたのですが、どうも初心者臭さが抜けなくて...」 と、投げかけたところ、鬼殺隊の柱のような先輩たちが優しく教えてくれて、そのSlackのやりとりが超楽しかったのでメモ。 僕のような未経験者であっても基本的人権を尊重してくれて、楽しく教えてくれる会社、それが株式会社Fusicです。 実装! 初心者(出発点) 私が違和感を感じながらも提示したコードがこちらです。 やりたいことはできるけど、絶対にダサい!でも、どう改善したらいいかわからない! def weekend? today = Time.now if today.saturday? true elsif today.sunday? true else false end end こんなコード晒すのが恥ずかしいですが... これからこれを一歩ずついい感じにしていきます。 とりま初心者から一歩抜け出す ひとまず、あっという間に8行が3行になります... def weekend? today = Time.now return true if today.saturday? || today.sunday? false end 学ぶべきこと ifの条件文はOR(||)文で書けるので一行でイケる if文はネストしやすいのでreturn if 条件の形が見やすくなって善い 知っていたのに、ここでの使い方が思いつかなかったです。悔しい!恥ずかしい! 初心者から二歩抜け出す もう一行減らせます。 def weekend? today = Time.now today.saturday? || today.sunday? end 学ぶべきこと Rubyのメソッドはreturnを付けなくともその値を返すので、return trueとかfalseとか書かなくて良い プロを目指す人のためのRuby入門の一節も復習↓ Rubyは最後に評価された式がメソッドの戻り値になるのが特徴です。returnのようなキーワードは不要です。(中略)Rubyではreturnを使わない書き方の方が主流です。 「プロを目指す人のためのRuby入門」伊藤淳一著p37 さらにもう一歩。オープンクラス! class Time def weekend? saturday? || sunday? end end 学ぶべきこと 既存のクラスに独自のメソッドを追加してしまう!(今回だとTimeクラス) 「オブジェクト指向的にもこれが一番綺麗」らしい。 これをメタプログラミングと呼ぶらしい。 ダメ押しの一歩。祝日対応。 今回の要件とは少し外れますが、祝日まで判定したい場合はRailsにはこんなgemがあるそうな。 最後に 何かご指摘などあればぜひよろしくお願いします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[個人開発]SNSを公開して起こった3つの事件

初めに 一週間前にrailsで作ったSNSを公開しました。そこで起こったことを書いていこうと思います。 作ったアプリ AmmotというSNSでコンセプトは「制限の少ない自由な投稿を」です。 文字数制限が6000字まで、画像・動画・PDF・音声は同時に10個まで投稿可能なブログに近いSNSです。今はマークダウンにも対応しています。 以前にもqiitaで宣伝させていただきました。 【個人開発】制限のない自由なSNS作ってみた! 事件1 XSS攻撃大量発生 ※一部です まぁ公開したてのwebアプリあるあるだと思いますが、Qiitaで宣伝して「いっぱい人来るかなー?」なんてワクワクしてたらXSSを狙う投稿が大量発生してちょっと萎えました(普通に使ってくれる人ももちろんいました)。 事件1の対策 = sanitize markdown(g.content) html_safeを消してsanitizeを追加するだけ。 こんな記事もあるがtagsやattributesを設定しなくてもsanitize だけで十分対策になる。 逆にtagsなどを書くとシンタックスハイライトができなくなったので注意です。 てかhtml_safeってなんでこんな使われてるんでしょうか?名前に反して結構危険なメソッドなのに...。 事件2 速度おっそ!! ログなどは取り忘れましたがログイン後のトップページを開くのに10秒くらいかかってました。 SNSに速度はかなり重要なのに...。 開発環境では結構いいPCを使っているのでパフォーマンスとか全く気にせず作っていました。 事件2の対策 countメソッドを徹底的に消す。 //悪い例 = g.comments.count = g.likes.count こういう文よく見ますよね。ただまじでこれはやめたほうがいいです。自分の場合、countメソッドからlengthメソッドに変えただけで速度が倍くらいになった。countメソッド怖ええ.. //良い例 = g.comments.pluck(:id).length = g.likes.pluck(:id).length 動作は全く変わりません。 キャッシュに対応する キャッシュに対応するだけでActiveRecordが3分の1くらいになります。 ただこれが3つ目の事件となります。 事件3 キャッシュ 自分はキャッシュに触れるのが初めてだったので???って状態でした。やっとキャッシュに対応したと思いリリースしたらバグの連続。 ・無限スクロールが動かない ・違うユーザーの投稿が自分の投稿一覧に現れる ・てかそもそも全然早くないしむしろ遅くなった気がする などなど この時に修正しようと何度も連続でアプデしたのでサーバーが重くなりどんどん動作が遅くなり...利用者が減ったのかなと考えています。 一回すべて取っ払いシンプルにコレクションキャッシュで実装したらうまくいきました。 def dashboard #フォローしてるユーザーと自分の投稿を取得 @posts = Post.where(user_id: [current_user.id, *current_user.following_ids]).where(public: true).order(created_at: :desc).page(params[:page]).without_count.per(20) end dashboard h1 dashboard = render "datas", posts: @posts _datas.html.slim .jscroll //投稿かいいねかリツイートされたらキャッシュキーが更新される = render partial: 'data', collection: posts, as: "g", cached: -> (g) { [g, g.likes.ids, g.reports.ids] } .none = link_to_prev_page posts, '前のページ', class: "prev" = link_to_next_page posts, '次のページ', class: "next" javascript: $('.jscroll').jscroll({ contentSelector: '.jscroll', nextSelector: 'a.next', loadingHtml: '読み込み中' }); _data.html.slim = g.content こんな感じでうまくいきました。 番外編 windows redisの入れ方 最初キャッシュで困ったのがwindowsでredisをダウンロードする記事が見当たらないこと。 なので自分が忘れないためにもここに書いておきます。 1: https://github.com/microsoftarchive/redis/releases/tag/win-3.2.100 にアクセスして一番上の.msiをダウンロード。すこし更新日が古いですがこれが最新のようです。 2: 出来たらダウンロードしたものを起動してNEXT連打。最後のfinishまで変更する場所は特にありません。 3: 動作確認 redis-server ターミナルで実行 まとめ ・html_safeとcountには気を付けろ ・キャッシュはしっかり動作確認をしよう ・XSS攻撃はやめてくれ ・Qiitaのトップページをトレンドに戻してくれ ・Ammot使ってみてくれ ↓Ammot URL https://ammot.net/ ↓僕のAmmotのアカウント https://ammot.net/user/yamada(%E9%96%8B%E7%99%BA%E8%80%85) ↓僕のツイッターのアカウント https://twitter.com/yamada1531
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsでruby組み込みライブラリを拡張する

任意のフォルダに拡張ファイルを配置 lib/core_ext/string.rb class String def hoge self+" fuga" end end 'config/initializers'配下に以下のようなファイルを配置 config/initializers/core_ext.rb Dir.glob(File.join(Rails.root, 'lib', '*_ext', '*.rb')) do |file| load file end これで Strinig.hoge が使えるようになった。 以下がとても参考になった https://dev.classmethod.jp/articles/ruby-object-to-boolean/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む