KATUUUNs blog

プログラミング学習で得た知識をアウトプットするためのブログです

学習51日目 リロードしないとPOSTできなくて3時間立ち止まった話

こんにちはKATUUUNです。オリジナルアプリも佳境に差し掛かってきました。

今日はタイトルにある通り「リロードしないとPOSTできなくて3時間立ち止まった話
についてアウトプットします。f:id:KT34309349:20210803214942j:plain

<%= form_with model:[@room, @message], url: room_messages_path(@room.id), method: :post, id: "form" do |form| %>

上記が訂正前の記述です。railsでコメントの投稿を試みたのに、何度やっても、リロードした後表示される状態でした。

訂正後はこちら

<%= form_with model:[@room, @message], url: room_messages_path(@room.id), method: :post, id: "form", local: true do |form| %>

当たり前につけていたlocal: trueを忘れていました。
form_withの中のlocalオプションです。trueにすることでリモート送信を無効にできます。

これのつけ忘れで3時間足止めを食らいました。

以上です。ありがとうございました。

学習48日目 RailsといくつかのGemを用いて音声投稿機能を実装する流れ

こんにちは。KATUUUNです。引き続きオリジナルアプリを作成しています。
作成にあたって、音声投稿機能を実装したくなったため、その手順を忘れないためにアウトプットしておきます。

  • 背景
  • 前提
  • 手順
  • 背景 

現在オリジナルアプリ作成中です。その中でプログラミング学習に特化した単語帳アプリを作成中です。自分だけの単語帳を作るために、投稿機能を実装しました。そこで単語(keyword)とともに自分が録音した音声も投稿できたら、学習の質が上がるのではないかと思いました。

  • 前提

バージョン:Rails 6.0.0
*今回は録音機能ではなく、音声投稿機能を実装する。録音アプリとMP3への変換アプリはAppStoreからインストールしました。
*単語帳アプリ作成にあたり、ユーザー管理機能、単語投稿機能(keywordsテーブル)は実装済みです。

  • 手順


カラムの追加

rails generate migration AddAudioToKeywords audio:string

その後いつものrails db:migrateを実行する。
これでkeywordsテーブルにstring型のaudioカラムが作成されました。
※ここで保存されるのは音声ファイルのURLです。音声自体は別の場所に保存されます。


ファイルをアップロードするビューファイル作成

app>views>keywords>_form.html.erb

# 途中省略
<%# 音声 %>
      <div class="audio-upload">
        <div class="form-title">
          音声ファイル
        </div>
        <div class="audio-form">
          <%= f.file_field :audio %>
        </div>
      </div>

<%= f.file_field :audio %>と記述しました。<%= f.label :audio %>を追加してもいいと思います


コントローラー追加
audioカラムを追加します。

keywords_contoroller.rb

private
  def keyword_params
    params.require(:keyword).permit(:word, :genre_id, :instruction, :audio).merge(user_id: current_user.id)
  end

私はprivateメソッド内のストロングパラメータ内に書きました。

また、私の場合、modelファイルにバリデーションはかけていません。


表示させるビューファイル作成

app>views>keywords>show

# 途中省略
<% @keywords.each do |keyword| %>

#省略
      <td>
        <% if keyword.audio.present? && keyword.user_id == current_user.id %> 
          <%= audio_tag keyword.audio_url, :controls => true %>
        <% end %>  
      </td>

私の場合はtableタグの中に書きました。audio_tag keyword.audio_urlが最低限必要。
:controls => trueはオプションの一つで、再生ボタンが表示できる。他にも自動再生とかループ再生とかいろんなオプションがあります。


こっからややこしいところ

gemの追加

gem 'carrierwave'
gem 'cloudinary'

その後いつものbundle install


carrierwaveでアップロード機能が実装できる
cloudinaryは本番環境で音声を保存できる

アップローダー作成

rails g uploader Audio

ターミナルに打ち込みます


保存先変更
モデルファイルにて保存先をAudioUploaderに変更

app>models>keyword.rb

# 途中省略 
mount_uploader :audio, AudioUploader

保存場所を指定するアップローダの設定

app/uploaders/image_uploader.rbの6~8行目の変更

変更前

app/uploaders/audio_uploader.rb
  # Choose what kind of storage to use for this uploader:
  storage :file
  # storage :fog

変更後

app/uploader/audio_uploader.rb
  # Choose what kind of storage to use for this uploader:
  if Rails.env.production?
    include Cloudinary::CarrierWave
    CarrierWave.configure do |config|
      config.cache_storage = :file
    end
  else
    storage :file
  end
  # storage :fog

デプロイ後、本番環境ではcloudinaryに保存され、
開発環境(ローカル)では自分のpublicフォルダー内に保存されます


非公開APIの設定
以下からアカウントを作成しましょう
https://cloudinary.com/console/welcome

https://i.gyazo.com/d063e63798c1335b17e7fa1a43676918.jpg

dashboardにあるCloud name、API Key、API Secretを控えておきます。


セキュリティを強化
Cloudinaryのアカウントを外部に漏らさないためにdotenv-railsというgemを使います

gem 'dotenv-rails'

毎度お馴染み bundle installします



envファイル作成
アプリケーションディレクトリ(appやdbやGemfileがあるディレクトリ)に自分で作成します。
https://i.gyazo.com/dbcf3455ea083b863ff663f4c656a474.png
上のようにファイルを作ります



.envファイル入力

.env
CLOUD_NAME=*************
CLOUDINARY_API_KEY=**********
CLOUDINARY_API_SECRET=***********

先ほどのCloudinaryのマイページで取得したキー「=」の後のそれぞれの値にします



隠しておきたい.envファイルを公開しないようにする。

.gitignoreに下記を追加

.gitignore
# 省略

/.env


APIキーの利用
まずはconfigフォルダにcloudinary.ymlファイルを作成します。ルーティングファイル等と同じ階層です。

中身は以下の通りです

config/cloudinary.yml

development:
  cloud_name: <%= ENV['CLOUD_NAME'] %>
  api_key: <%= ENV['CLOUDINARY_API_KEY'] %>
  api_secret: <%= ENV['CLOUDINARY_API_SECRET'] %>
  enhance_image_tag: true
  static_file_support: false
production:
  cloud_name: <%= ENV['CLOUD_NAME'] %>
  api_key: <%= ENV['CLOUDINARY_API_KEY'] %>
  api_secret: <%= ENV['CLOUDINARY_API_SECRET'] %>
  enhance_image_tag: true
  static_file_support: false
test:
  cloud_name: <%= ENV['CLOUD_NAME'] %>
  api_key: <%= ENV['CLOUDINARY_API_KEY'] %>
  api_secret: <%= ENV['CLOUDINARY_API_SECRET'] %>
  enhance_image_tag: true
  static_file_support: false

これでAPIキーを非公開にしたまま利用することができます。

これで音声投稿機能が実装できます。

学習47日目 ActiveRecord::StatementInvalid: Mysql2::Error: Cannot delete or update a parent row: a foreign key constraint failsのエラーの対処

こんにちはKATUUUNです
現在オリジナルアプリ作成中です。
そこで遭遇したエラーについて共有します。

  • エラー内容

タイトルの通り、ActiveRecord::StatementInvalid: Mysql2::Error: Cannot delete or update a parent row: a foreign key constraint failsが表示されたf:id:KT34309349:20210819145512p:plain

  • 前提

英単語帳のような単語投稿アプリを作成中
テーブルは以下の3種類
・usersテーブル
・keywordsテーブル(単語帳投稿関連)
・testsテーブル(上2つの中間テーブル)

  • 背景

投稿した単語を削除しようとしたら上記のエラーが表示された。

  • 原因

dependentディペンデントオプションが設定できていなかった

dependentディペンデントオプションとは
親モデルを削除した時に、親モデルと関連している子モデルに対する挙動を指定するオプションです。
たとえば、dependentオプションに:destroyを指定したときは、親モデルが削除されたとき、それに紐付ている子モデルも一緒に削除されます。

  • 対処

各モデルファイルを以下のように修正しました

修正前

user.rb
has_many :keywords
has_many :tests
keyword.rb
has_many :tests
test.rb
belongs_to :user
belongs_to :keyword

修正後

user.rb
has_many :keywords
has_many :tests, dependent: :destroy
keyword.rb
belongs_to :user
has_many :tests, dependent: :destroy
test.rb
belongs_to :user
belongs_to :keyword

以上です!

学習46日目 本日の積み上げ

こんにちはKATUUUNです。
時間がない時は本日の作業内容を報告したいと思います。f:id:KT34309349:20210818213336j:plain

現在はオリジナルアプリを開発中です。

  • 投稿内容の編集機能実装

 フリマアプリ、prototype、chatappなど何回も実施してきているため、何も見ずに実装できるようになりました。

  • 同様に削除機能

 こちらも呼吸をするように実装できるようになりました。

今日もお疲れ様でした。

学習44日目 railsでマークダウン表示を実装する

こんにちは、KATUUUNです。ここ最近天気があまり良くないですが、私の心はいつも晴れマークです!(恥)

久しぶりの投稿となりました。今日はオリジナルアプリを通じて学習したマークダウン方式についてアウトプットします。

投稿した内容をマークダウン方式で表示させる方法

ちなみにオリジナルアプリとは、プログラミングに特化した単語帳アプリを開発中です


1 gemの導入
必要なgemをgemfileに記述します

1.1 redcarpet: マークダウンで記入した内容をHTML化してくれるgemです

1.2 coderay: redcarpetだけだと味気ないため、シンタックスハイライトするgemです。
*そもそもシンタックスハイライトとは、コードの内容へ独自のCSSを適用し、コードを分かりやすく色分けしてくれることを指します。

gem 'redcarpet'
gem 'coderay'

いつも通りbundle install


2 helperファイルにマークダウンの記述をする
*そもそもhelperとは、viewをシンプルにする為に、viewと別の場所(helper)で定義しておいたメソッドをviewから呼び出すことができるファイルです。

今回、マイページに表示させたかったため、app>helpers>user_helper.rbに記述しました。大元のapplication_helper.rbでも問題なし。

module UsersHelper
  require 'redcarpet'
  require 'coderay'

  class HTMLwithCoderay < Redcarpet::Render::HTML
    def block_code(code, language)
      language = language.split(':')[0]

      case language.to_s
        when 'rb'
          lang = 'ruby'
        when 'yml'
          lang = 'yaml'
        when 'css'
          lang = 'css'
        when 'html'
          lang = 'html'
        when ''
          lang = 'md'
        else
          lang = language
      end

      CodeRay.scan(code, lang).div
    end
  end

   def markdown(text)
    html_render = HTMLwithCoderay.new( with_toc_data: true)

    option = {
        autolink: true,
        space_after_headers: true,
        fenced_code_blocks: true,
        tables: true,
        hard_wrap: true,
        lax_html_blocks: true,
        strikethrough: true,
        filter_html:     true,
        with_toc_data: true,
        no_intra_emphasis:  true,
        no_styles: true
    }

    markdown = Redcarpet::Markdown.new(html_render, option)
    markdown.render(text).html_safe
  end
end

ここで記述内容の説明

2.1

case language.to_s
        when 'rb'
          lang = 'ruby'
        when 'yml'
          lang = 'yaml'
        when 'css'
          lang = 'css'
        when 'html'
          lang = 'html'
        when ''
          lang = 'md'
        else
          lang = language

コードの言語の指定方法をカスタマイズすることができる。例え```rubyとしなくても```rbで色付けできる。また言語を指定しなかった時エラーが出ないように'md'を設ける

2.2

 option = {    
        autolink:            true,
        space_after_headers: true,
        fenced_code_blocks:  true,
        tables:              true,
        hard_wrap:           true,
        lax_html_blocks:     true,
        strikethrough:       true,
        filter_html:         true,
        with_toc_data:       true,
        no_intra_emphasis:   true,
        no_styles:           true
    }

オプションの付与
こんなにいらないと思うけど、心配性なので一応。
中身はここから
github.com

2.3

markdown.render(text).html_safe

このメソッドで、渡した Markdown 文字列をシンタックスハイライト用のマークアップを行った HTML に変換できます。

3. viewファイル記述
私の場合はviews>users>showファイルに記載しました。

<%= markdown(keyword.instruction) %>

f:id:KT34309349:20210816123625p:plain
うまくいきました!

学習40日目 cssから学んだこと

こんにちはKATUUUNです。
本日もオリジナルアプリの開発を続けていました。
新規投稿画面を作成した時、気づいた箇所をアウトプットします

本番環境で背景画像が表示されない

cssで見た目を整えて、さあデプロイするぞ!意気込んだ後、

f:id:KT34309349:20210812215533p:plain

背景画像が消えていました。

  • 原因

Asset Pipelinという仕組みが関係しているとわかりました。

webブラウザで処理できるリクエスト数には限りがあるため、javascriptcssのアセット(railsでapp配下にあるやつ)を最小化または連結するためにAsset Pipelinというフレームワークが働いているらしい。

その「最小化または連結」するときに画像のファイル名に拡張子が追加され、ファイル名が変わるらしい。

  • 対策

cssファイルをscssファイルにしてimage-urlメソッドを使いました。

変更前

background-image: url('try.png');

変更後

background-image: image-url('try.png');

これで本番環境で背景画像が表示されました。f:id:KT34309349:20210812220925j:plain

学習39日目 本日の積み上げ

こんにちはKATUUUNです。本日の作業内容を共有します。

f:id:KT34309349:20210811220216j:plain

  • トップページ作成。

 とても時間がかかりました。とりあえず一旦終了。深追いするといつまでもフロント実装はできますね。また後日時間がある時に取り組みます。

  • 新規登録ページ作成。

 基本はフリマアプリの影響を受けた仕様になっています。しかしユーザー情報に写真を必須にしたかったため、ActiveHashで実装しました。

  • ユーザー管理機能実装

 トップページ→新規登録→トップページの流れまで作ることができました。

今日もお疲れ様でした。