- 投稿日:2021-01-20T23:29:52+09:00
rails test がデータベースの参照エラーで失敗する
経緯
Docker の中で Rails と MySQL を立て、 rails test でテストを実行しようとしたところ、エラーとなりました。
docker-compose.ymlservices: mysql_test: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: aaa MYSQL_USER: user MYSQL_PASSWORD: password TZ: 'Asia/Tokyo' command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci$ rails test test/integration/aaa_test.rb Error: AaaTest#aaa: ActiveRecord::ConnectionNotEstablished: Access denied for user 'user'@'%' to database 'aaa-1'エラー内容を見ると
aaa-1
を参照しており、そのデータベースはないのでエラーとなっています。解決策
test_helper.rb にある
parallelize(workers: :number_of_processors)
の影響なので、 PARALLEL_WORKERS を変更して suffix がつかないようにします。$ PARALLEL_WORKERS=1 rails test test/integration/aaa_test.rbこれで動作します。
- 投稿日:2021-01-20T22:30:38+09:00
【Bootstrap】いきなりログアウトできなくなった〜なんでや?CSRF問題らしい〜
解決したいこと
Bootstrapを導入してからログアウトができなくなってしまった。
発生している問題・エラー
ログイン後、ヘッダー部分にあるログアウトボタンを押すとエラーメッセージが出て、一生ログアウトできない。
該当するソースコード
application.html.erb<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="description" content=""> <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors"> <meta name="generator" content="Jekyll v4.0.1"> <title>Party Freak</title> <%= stylesheet_link_tag 'application', media: 'all'%> 〜以下略〜以前のソースコード
application.html.erb<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <title>Party Freak</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> 〜以下略〜自分で試したこと
<html>
の<head>
部分の記述を導入前に戻すと、ログアウトができるようになる。
最終的には<head>
から下を入れ替えることでエラーが出ず、以前のようにログアウトができるようになった。
なお、ログインと新規投稿については問題のあったソースコードでもできていた。
部分的に入れ替えてみたり色々試してみて数十分、記述を追加するとログアウトできるようになるものを発見。application.html.erb<%= csrf_meta_tags %> <%= csp_meta_tag %>この二つでした。
調べてみるとクロスサイトリクエストフォージュリに関する記述。
Railsがセキュリティ的に危ないからやめときなさい!と注意をしてくれているということでした。
ありがとうRailsさん、いつもエラーで怒ってごめんね。エラーが出なくなったソースコード(head以下を変更しました
application.html.erb<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="description" content=""> <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors"> <meta name="generator" content="Jekyll v4.0.1"> <title>Party Freak</title> <%= csrf_meta_tags %> ⬅️追加 <%= csp_meta_tag %> ⬅️追加 <%= stylesheet_link_tag 'application', media: 'all'%> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> ⬅️なぜかこれも追加 〜以下略〜一番下のJSを入れないとログアウトできなかったのが謎です。
何度やってもこれがないとダメなようですが理由がわかりません。
どなたか理由がわかる方がいらっしゃれば教えていただければ幸いです。
- 投稿日:2021-01-20T21:49:17+09:00
画像のプレビュー機能
はじめに
画像投稿時に、画像ファイルの名前だけが表示されるだけで、きちんと出来ている分かりづらいと感じたので、プレビュー機能を実装しました。
1.準備
1. プレビュー機能を実装させるためのjsファイルを作成する。app/javascript/packsにpreview.jsを作成
→ app / javascript / packs / preview.js2.preview.jsを読み込めるようapplication.jsを編集する。
app/javascript/packs/application.jsrequire("@rails/ujs").start() require("@rails/activestorage").start() require("channels") require('./preview') # 追記する3.viewファイルに画像が表示される場所を指定する。
views/ideas/new.html.erb<div class="img-upload"> <div class="left-img-upload"> <div class="weight-bold-text"> 関連画像(関連する画像があれば添付してください) </div> <div class="click-upload"> <p>クリックしてファイルをアップロード</p> <%= f.file_field :image, id:"idea-image" %> </div> </div> <div class="right-img-upload"> <div id="image"></div> <!--追記する--> </div> </div>2.プレビュー機能実装
1 で作成したpreview.jsにプレビュー機能のコードを記述する。
app/javascript/packs/preview.jsif (document.URL.match( /new/ ) || document.URL.match( /edit/ )) { document.addEventListener('DOMContentLoaded', function(){ const ImageList = document.getElementById('image'); const createImageHTML = (blob) => { // 画像を表示するためのdiv要素を生成 const imageElement = document.createElement('div'); // 表示する画像を生成 const blobImage = document.createElement('img'); blobImage.className="preview"; //←createElementで生成したimgにクラス名を付けている blobImage.setAttribute('src', blob); // 生成したHTMLの要素をブラウザに表示させる imageElement.appendChild(blobImage); ImageList.appendChild(imageElement); }; document.getElementById('idea-image').addEventListener('change', function(e){ // 画像が表示されている場合のみ、すでに存在している画像を削除する const imageContent = document.querySelector('img'); if (imageContent){ imageContent.remove(); } const file = e.target.files[0]; const blob = window.URL.createObjectURL(file); createImageHTML(blob); }); }); }
最後にCSSで画像のサイズを指定する。.preview { height: 250px; width: 250px; object-fit: contain; }実装完了
画像が表示されるようになったおかげで、自分が選択した画像が分かりやすくなりました。
最後に
javascriptを用いた実装はあまり行っていなかったため、いい復習となりました。
また、createElementで生成した要素にクラス名をつける方法など学ぶことができ、勉強になりました。
- 投稿日:2021-01-20T18:15:29+09:00
[個人開発]使い捨てチャットアプリ作ってみた
初めに
今回はweb上で動くチャットアプリ 「スコーチチャット」を作りました。
アカウント登録不要
ダウンロード不要
で使い捨てで使われることを想定してます。URL
https://scorch-chat.herokuapp.com/開発環境
rails6
ruby2.7
windows10
heroku
postgresql
ActionCablegem 'ridgepole'
gem 'slim-rails'
gem 'html2slim'
gem 'pry-rails'
gem 'bcrypt'
gem 'activeadmin'
gem 'devise'
gem 'rack-attack'いつもと同じです。
開発期間
5日くらいです。
webアプリは当たる確率が6%程で質より量を打ったほうがいいといわれたのでなるべく早く作りました。チャット画面
[自分流]新しい技術の勉強法
結論から言うと、元あるコードを改造することです。
初めて使う技術のコードを一気に書くのは難しいです。
なので作りたいアプリになるべく似たコードを
githubなどで落としてきてそれで開発を進めるんです。
するとインプットとアウトプットを実践でできるので
いい勉強法になると思ってます。今回はじめてActionCableを使ったのですが最初は全く分かりませんでしたがもう
何となくわかるようになりました終わりに
ここまで読んでくれてありがとうございました。
スコーチチャットをぜひ使ってみてください!
URL
https://scorch-chat.herokuapp.com/
- 投稿日:2021-01-20T18:15:29+09:00
使い捨てのチャットを作成できるサービス「Scorch Chat」をリリースした!
初めに
今回はweb上で動くチャットアプリ 「スコーチチャット」を作りました。
アカウント登録不要
ダウンロード不要
で使い捨てで使われることを想定してます。URL
https://scorch-chat.herokuapp.com/開発環境
rails6
ruby2.7
heroku
postgresql
ActionCable
slimいつもと同じです。
開発期間
5日くらいです。
webアプリは当たる確率が6%程で質より量を打ったほうがいいといわれたのでなるべく早く作りました。チャット画面
[自分流]新しい技術の勉強法
結論から言うと、元あるコードを改造することです。
初めて使う技術のコードを一気に書くのは難しいです。
なので作りたいアプリになるべく似たコードを
githubなどで落としてきてそれで開発を進めます。
するとインプットとアウトプットを実践でできるので
いい勉強法になると思ってます。今回はじめてActionCableを使ったのですが最初は全く分かりませんでしたがもう
何となくわかるようになりましたRailsはオワコンか?
ほかの記事で話題になっていたので取り上げます。
僕はrailsはオワコンではないと思います。
結構昔から言われ続けてますが、まだオワコンにはなってないでしょう?
それが答えな気がします。railsを圧倒するようなフレームワークが出ない限りオワコンにはならない気がします。
終わりに
ここまで読んでくれてありがとうございました。
スコーチチャットをぜひ使ってみてください!
URL
https://scorch-chat.herokuapp.com/
- 投稿日:2021-01-20T18:15:29+09:00
手軽にチャットを作成できるサービスをリリースした!
初めに
今回はweb上で動くチャットアプリ 「スコーチチャット」を作りました。
アカウント登録不要
ダウンロード不要
で使い捨てで使われることを想定してます。URL
https://scorch-chat.herokuapp.com/開発環境
rails6
ruby2.7
heroku
postgresql
ActionCable
slimいつもと同じです。
開発期間
5日くらいです。
webアプリは当たる確率が6%程で質より量を打ったほうがいいといわれたのでなるべく早く作りました。チャット画面
[自分流]新しい技術の勉強法
結論から言うと、元あるコードを改造することです。
初めて使う技術のコードを一気に書くのは難しいです。
なので作りたいアプリになるべく似たコードを
githubなどで落としてきてそれで開発を進めます。
するとインプットとアウトプットを実践でできるので
いい勉強法になると思ってます。今回はじめてActionCableを使ったのですが最初は全く分かりませんでしたがもう
何となくわかるようになりましたRailsはオワコンか?
ほかの記事で話題になっていたので取り上げます。
僕はrailsはオワコンではないと思います。
結構昔から言われ続けてますが、まだオワコンにはなってないでしょう?
それが答えな気がします。railsを圧倒するようなフレームワークが出ない限りオワコンにはならない気がします。
終わりに
ここまで読んでくれてありがとうございました。
スコーチチャットをぜひ使ってみてください!
URL
https://scorch-chat.herokuapp.com/
- 投稿日:2021-01-20T17:30:12+09:00
active_hashを使って都道府県のセレクトバーを作成
今回はよく見かける都道府県のセレクトバーを作成していきたいと思います
① active_hash導入
gem 'active_hash'$ bundle install② 関連するモデルにprefecture_id :integerを追加する
私の場合はpetモデルに追加します。
dbprefecture_id :integer③ prefectureモデルを手動で作る
modelのなかにprefecture.rbファイルを直接作成し、中身を記述。
prefecture.rbclass Prefecture < ActiveHash::Base self.data = [ {id: 1, name: '北海道'}, {id: 2, name: '青森県'}, {id: 3, name: '岩手県'}, {id: 4, name: '宮城県'}, {id: 5, name: '秋田県'}, {id: 6, name: '山形県'}, {id: 7, name: '福島県'}, {id: 8, name: '茨城県'}, {id: 9, name: '栃木県'}, {id: 10, name: '群馬県'}, {id: 11, name: '埼玉県'}, {id: 12, name: '千葉県'}, {id: 13, name: '東京都'}, {id: 14, name: '神奈川県'}, {id: 15, name: '新潟県'}, {id: 16, name: '富山県'}, {id: 17, name: '石川県'}, {id: 18, name: '福井県'}, {id: 19, name: '山梨県'}, {id: 20, name: '長野県'}, {id: 21, name: '岐阜県'}, {id: 22, name: '静岡県'}, {id: 23, name: '愛知県'}, {id: 24, name: '三重県'}, {id: 25, name: '滋賀県'}, {id: 26, name: '京都府'}, {id: 27, name: '大阪府'}, {id: 28, name: '兵庫県'}, {id: 29, name: '奈良県'}, {id: 30, name: '和歌山県'}, {id: 31, name: '鳥取県'}, {id: 32, name: '島根県'}, {id: 33, name: '岡山県'}, {id: 34, name: '広島県'}, {id: 35, name: '山口県'}, {id: 36, name: '徳島県'}, {id: 37, name: '香川県'}, {id: 38, name: '愛媛県'}, {id: 39, name: '高知県'}, {id: 40, name: '福岡県'}, {id: 41, name: '佐賀県'}, {id: 42, name: '長崎県'}, {id: 43, name: '熊本県'}, {id: 44, name: '大分県'}, {id: 45, name: '宮崎県'}, {id: 46, name: '鹿児島県'}, {id: 47, name: '沖縄県'} ] include ActiveHash::Associations has_many :pets endpetモデルにもリレーション追加
pet.rbclass Pet < ApplicationRecord extend ActiveHash::Associations::ActiveRecordExtensions belongs_to_active_hash :prefecture end④ パラメーターに :prefecture_idを追加
pets.controller.rbprivate def pet_params params.require(:pet).permit(:name, :prefecture_id) end end⑤ viewを追加
<%= form_with model: @pet, url: pets_path, method: :post, local: true do |f| %> <%= f.label :"都道府県" %> <%= f.collection_select :prefecture_id, Prefecture.all, :id, :name, prompt: "-- 選択してください--" %> <%= end %>完成です!!
- 投稿日:2021-01-20T17:23:36+09:00
Githubにpushするまで
GitHubへPushするまでにかなり手こずったので
また同じようなことにならない為に記録しときたいと思います。環境
- macOS Big Sur (11.1)
- エディター VSCode
- GitHubアカウントは登録済み
- 管理しているプロジェクトはrailsで実装済み
1.リポジトリの作成
- GitHubでRepositoriesの
New
をクリックRepository name
で好きな名前(作っているアプリの名前)を入力Public(公開)
Private(非公開)
はお好きに決めてくださいcreate Repository
でリポジトリの作成完了2.VSCodeでinitからcommitまで
- フォルダを開くをクリックしてpushしたいプロジェクトを開き、下のコードを入力
ターミナル$ git init $ git add -A $ git commit -m "コメント"
add -A
で現在のディレクトリ以下の全ファイルを選択
commit -m
でコミットメッセージを残すこれでpushする準備が完了!
3. push
ターミナル$ git remote add origin https://github.com/ユーザー名/リポジトリ名_app.git $ git push -u origin master最後
これでpushが出来ました。
またこれで出来なくなったら編集し直そうと思います。
何か他にアドバイス、ご指摘あればお願い致します。
- 投稿日:2021-01-20T17:04:52+09:00
Chart.jsで円グラフを書く
chart.jsでデータベースの値から簡単な円グラフを作成
スポーツの大会でよくある勝敗確率のグラフ(最高100%という設定)
データベース
forecastsテーブル
numはwin_schoolの勝利確率
win_schoolは勝利予想されているチーム
lose_schoolは負け予想されているチーム
id num user_id win_school lose_school 1 60 1 A学園 B学園 コントローラー
idが1のデータを取ってこれる設定
def show @forecast = Forecast.find(params[:id]) endhtmlファイル
<div class="win"><%= @forecast.win_school %></div><!-- A学園 --> <div class="lose"><%= @forecast.lose_school %></div><!-- B学園 --> <div class="win-rate"><%= @forecast.num %></div><!-- 60 --> <div class="pie"><!-- グラフ描画部分 --> <div style="width:60%; height:60%";><canvas id="PieChart"></canvas></div> </div> <%= javascript_pack_tag 'forecast' %> <!-- js読み込み -->非表示にさせたい場合はhiddenを使うと良いでしょう
<div hidden class="win">jsファイル
app > javascript > packs > forecast.js
var ctx = document.getElementById("PieChart"); var win = document.getElementsByClassName("win").textContent //クラス名winから値を取得(A学園) var lose = document.getElementsByClassName("lose").textContent //クラス名loseから値を取得(B学園) var winnum = document.getElementsByClassName("win-rate").textContent //クラス名win-rateから値を取得(60) var PieChart = new Chart(ctx, { type: 'pie', //グラフのタイプは円グラフです、という意味 data: { labels: [win,lose], //円グラフのラベル(円グラフのA学園,B学園と表示されている箇所) datasets: [{ backgroundColor: [ //円グラフの色 "#FF0000", //1つめの色(ラベルwin)は赤 "#33CCFF", //2つめの色(ラベルlose)は水色 ], data: [winnum,100-winnum] //グラフの値 下記参照 }] }, options: { //オプションでカスタマイズ? title: { display: true, text: '勝利確率'//グラフのタイトル } } });data:でグラフに値を挿入しています
変数winnumには60が入っているので60,2つめは100-60で40が入るので
A学園の勝率60%,B学園の勝率40%ということになりますdata: [winnum,100-winnum]今回はhtmlファイルから値を取得しました
コントローラーから取得したい場合は、gonを使えば良いと思います
- 投稿日:2021-01-20T15:36:04+09:00
Railsのコントローラでparamをhashに変換する方法(随時更新)
params[:some_key]がStringだったり、ActionController::Parametersだったりしてややこしいので。
class MyController < ApplicatinoController def my_action # hash_of(params[:some_key]) # 呼び出し # head: :no_content end private def hash_of(param) case param when Hash # 本当にhashがあり得るのかは調べてない。 param when String JSON.parse(param) # JSON stringじゃなかったらエラーを吐く when ApplicationController::Parameters param.to_unsafe_h end end end参考
- 投稿日:2021-01-20T14:03:28+09:00
rails 学習 ActiveModelを用いた検索機能の実装方法
form_withを使って検索機能を追加する
admin/article/index.html.slimli = form_with model: @search_articles_form, scope: :q, url: admin_articles_path, method: :get, html: { class: 'form-inline' } do |f| => f.select :category_id, Category.pluck(:name, :id) , { include_blank: true }, class: 'form-control' .input-group = f.search_field :title, placeholder: "タイトル", class: 'form-control' span.input-group-btn = f.submit '検索', class: %w[btn btn-default btn-flat]今回検索用にform_withを使い検索機能を実装する。
今回はここに著者、タグ、本文の検索機能を追加する。まず著者、タグ、本文を記入できるようにform_with内に記入していく
admin/article/index.html.slimli = form_with model: @search_articles_form, scope: :q, url: admin_articles_path, method: :get, html: { class: 'form-inline' } do |f| => f.select :category_id, Category.pluck(:name, :id) , { include_blank: true }, class: 'form-control' => f.select :author_id, Author.pluck(:name, :id) , { include_blank: true }, class: 'form-control' => f.select :tag_id, Tag.pluck(:name, :id) , { include_blank: true }, class: 'form-control' .input-group = f.search_field :title, placeholder: "タイトル", class: 'form-control' .input-group = f.search_field :body, placeholder: "本文", class: 'form-control' span.input-group-btn = f.submit '検索', class: %w[btn btn-default btn-flat]form_witn内の
model: @search_articles_formの部分でSearchArticleFormクラスに以下の情報(category_id,title)を入れてインスタンスを作成するという処理になっていることがわかる。
しかしSearchArticleFormはDBに保存する必要のないクラスのなのでActiveRecordは使うことができない。つまり
$ article.titleなどのメソッドは使えなくなる
ActiveRecordの復習
ActiveRecordとは簡単に言えばRubyとDBの翻訳機みたいなものである。
RubyとDBはそれぞれ言語の種類が違うがActiveRecordを使うとその二つをつなぐ役割になる
例えば$ article.titleとするとActiveRecordによりDBのなかのarticleのtitleが選ばれることになる。
今回はDBが必要ない、つまりActiveRecordが使えず、article.titleなどの便利なメソッドを使うことができない。
ActiveModel
ActiveRecordを使えない(DBを使って処理を行わない)時、便利になるのがActiveModelである。DBを使っていないクラスに
ActiveModel::Model
をincludeすることでActiveRecordと同じようにコードをかけるというもの。つまりarticle.titleのように便利なメソッドを使うことができる。ActiveModelの使い方
class SearchArticleForm include ActiveModel::Model endこれで
article.title
などを使える準備は整った。(まだ使えるわけではない)さらにここから
article.title
のようなコードのtitle
の部分に何を使えるようにするかを決める今回の場合だとカテゴリー、著者、タグ、タイトル、本文の5つの検索機能が必要なので
SearchArticleFrom
クラスの「カテゴリー、著者、タグ、タイトル、本文」の5つの属性が必要になる。class SearchArticleForm include ActiveModel::Model attr_accessor :category_id, :integer attr_accessor :author_id, :integer attr_accessor :tag_id, :integer attr_accessor :title, :string attr_accessor :body, :string #body自体はtextだがbodyを探す場合の文字の種類はstringになる endattr_accessorを使うことでDBを使わないRubyの属性作ることができる
しかしattr_accessorもActiveModelで書き直すことができるclass SearchArticlesForm include ActiveModel::Model include ActiveModel::Attributes attribute :category_id, :integer attribute :author_id, :integer attribute :tag_id, :integer attribute :title, :string attribute :body, :string endActiveModel::Attributesと記入することでActiveRecordで記入している形式と全く同じ形で書くことができる。
これで
$ SearchArticlesForm.category_id $ SearchArticlesForm.author_id $ SearchArticlesForm.tag_id $ SearchArticlesForm.title $ SearchArticlesForm.bodyといった形でメソッドが使えるようになる
search機能の追加
ActiveModelを使うことができるようになったので、次に
category_id
author_id
tag_id
title
body
の検索機能を上記のメソッドたちを使ってsearchメソッドを作っていく。class SearchArticlesForm def search relation = Article.distinct relation = relation.by_category(category_id) if category_id.present?#categoryの検索機能 relation = relation.by_author(author_id) if author_id.present? #authorの検索機能 relation = relation.by_tag(tag_id) if tag_id.present? #tagの検索機能 title_words.each do |word| relation = relation.title_contain(word) #titleの検索機能 end body_words.each do |word| relation = relation.body_contain(word) #bodyの検索機能 end relation end private def title_words title.present? ? title.split(nil) : [] end def body_words body.present? ? body.split('') : [] end end解説① distinct
relation = Article.distinctdiscountを使うと重複するArticleを1つにまとめることができる
解説② by_category
relation = relation.by_category(category_id) if category_id.present?省略せずに記入すると
relation = Article.distinct.by_category(category_id) if category_id.present?となる
distinctで重複を調べるための範囲をby_category(category_id)で指定している
範囲の指定なのでby_category(category_id)はscopeでの範囲指定であるということがわかるscopeが書いてあるarticle.rbを見てみるとarticle.rbscope :by_category, ->(category_id) { where(category_id: category_id) } scope :title_contain, ->(word) { where('title LIKE ?', "%#{word}%") }となっている。
上記のcategoryのスコープは「category_idの範囲」を指定している。
titleのスコープは「wordに入った文字がtitleに含まれている範囲」を指定している。
著者、タグ、本文のスコープも付けないといけないのでつけるarticle.rbscope :by_category, ->(category_id) { where(category_id: category_id) } scope :by_author, ->(author_id) { where(author_id: author_id) } scope :by_tag, ->(tag_id) { joins(:tags).where(article_tags: { tag_id: tag_id }) } scope :title_contain, ->(word) { where('title LIKE ?', "%#{word}%") scope :body_contain, ->(word) { joins(:sentences).merge(where('sentences.body LIKE ?', "%#{word}%")) }by_tagとbody_containの書き方だけ違う。
それはArticle自信が持っている属性(メソッド)によるものである。
Articleはcategoryとauthor、titlesの属性は持っているが、tagとbodyの属性は持っていない。つまりArticle.tagやArticle.bodyはできない。Articleとtagに関しては多対多の関係なのでarticle_tagを介して、bodyはsentenceを介している。
そのためその2つに関してはjoinsを使いscopeをかけるようにしている。解説③ title_words
title_words.each do |word| relation = relation.title_contain(word) #titleの検索機能 end private def title_words title.present? ? title.split(nil) : [] endtitle_words以下の文は三項演算子であり、このように置き換えられる
def title_words if title.present? title.split(nil) else [] end endsplit(nil)で半角スペースのある単語は分割して調べることができる
- 投稿日:2021-01-20T13:48:27+09:00
Rails バリデーション書き方
アウトプットでRailsでのバリデーションの書き方を載せます。
データが正しいかどうかを検証するのがバリデーションになります。
まずモデルにて
user.rbclass User < ApplicationRecord validates :nickname, presence: true :nickname #カラム名 presence: true #空でない事次にコントローラ
user_controller.rbclass UsersController < ApplicationController def new @user = User.new end def create @user = User.new(user_params) if @user.valid? #ここ!!ここ!!! @user.save redirect_to root_path else render 'new' end end private def user_params params.require(:item).permit( :nickname end endvalid?メソッドでバリデーションが実行。バリデーションが通ればtrueを返します。
流れとしてはnewアクションで生成したものをcreateアクションで保存する時に値が入ってるのかをバリデーションで確認します。
if文を使い入っていれば@user.saveで保存。空ならrender 'new'でアラートを出す。
,
,user.html.haml= f.text_field :nickname, class: "nickname" .error-messages = @user.errors.full_messages_for(:nickname)[0]ビューには、保存するnicknameと、エラー文の表示の = @user.errors.full_messages_for(:nickname)[0]書けば完成。
- 投稿日:2021-01-20T12:28:15+09:00
【読書感想】アプリケーションコンフィグの設定パターン 銀座Rails #27
こちらを読んだ感想。
https://speakerdeck.com/morimorihoge/apurikesiyonkonhuigufalseshe-ding-patan-yin-zuo-rails-number-27詳細
"12 Factor App"
コンテナ化されたモダンなインフラ環境でまさに参考にできることが多い
これは普段から実感することが本当に多い。12 Factorから外れてるRailsアプリは、コンテナ化がしんどいとも言える。
環境変数
便利だけど、数増えてくると辛い。サービスを分ける指標にもできそう。
デフォルト値問題
いい感じに開発環境のデフォルトを設定できていると、皆幸せ。
まとめ
"設定変更方法による違い"を見るとどれを選択すべきかわかりやすい。
頻繁に変わったり、環境ごとに変わるものは構成管理からは外すの良いと思う。
- 投稿日:2021-01-20T09:23:20+09:00
Rails がオワコンwww
はじめに
※ この文章はベータ版です。
Yahoo!知恵袋にあった間違いだらけのベストアンサーがあまりにも...だった
ので書いています。
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10236599945このベストアンサーの問題点
著者が、よく知りもしない情報について、きちんと調べもせず、以前、聞き齧ったorどこかで
読んだような気がする、うろ覚えの情報をベースに、回答しているようにしか見えない。自分がうろ覚えの情報で回答することで、ネット上に誤情報をばら撒く可能性を考えていない
時点で、自分はこの著者が技術屋or技術屋を目指す人間なら、アウトと評価します。(この著者、「はず」「と思う」を多用することで、うろ覚えの情報で回答していますよアピールを
している気が、、、うろ覚えの情報で回答していることに、何ら問題を感じていないようにみえます、
自分のうろ覚えの情報が間違っていた時のための予防線を張っているようにも。。。「はず」「と思う」が多用されていても、質問者や読者が正しい情報と誤認識する可能性があります、
「はず」「と思う」を付けたからと誤情報かもしれない、うろ覚えの情報で書いてもいい、と考える
のは間違いです。この質問の質問者は、うろ覚えで書かれた誤情報を正しい情報と、誤認識してしまっている気がします。)
ネット上で書く以上、うろ覚えの情報で書くのではなく、自分のうろ覚えの情報が正しいか、
ネット上で最新情報をキャッチアップし、その情報と照らし合わせて検証してから、正しい情報
をベースに書くべきです、エンジニアなら尚更。Qiita etcに投稿する際も同様です。(この質問、2021/01/01 に投稿され、その日のうちに締め切られいて、
間違いだらけのベストアンサーを別の回答で正すこともできない状態に
なっています。うがった見方をすれば、質問の投稿者とベストアンサーの著者が同じ人間で、
わざと間違った情報をネット上に意図的に晒している、とも受け取れます。)Ruby自体、時代にあわせた変化や進化はもうない(と思います)
Ruby3.0.0で、
型チェック用基盤の RBS/TypeProfと、
並行・並列処理の Ractor & Fiber Scheduler
が入ってますけど。。。まだ実験的機能ではあるものの、Ruby2.6からJITが入り、Ruby3.0でも
改良が続けられてますが、、、時代の要請に合わせた新機能ですよね、、、
言語仕様ではなく実行環境の新機能ですけど。。。
(3.0.0でも、Railsとの組み合わせでパフォーマンスがおちる場合がまだ
多々あり、実戦投入できるレベルには達していないという判断?でデフォルト
ではoffになっています。)Ruby3.0.0、他にも新機能あります。
https://techlife.cookpad.com/entry/2020/12/25/155741「Ruby 新機能」でググれば、すぐにキャッチアップできる情報。。。
Ruby原作者のMatz氏が発言していたのは、構文の大きな変更はしない、
であって、、、言語の大きな変更はしない、ではない、です。Matz氏は、公式に、Rubyを時代にあわせて変化・進化させていくニュアンスの
発言をしています。(Rubyは、1.8→1.9→2.0(8年近く前の2013/02にリリース)、で、かなり大きな
痛みを伴う変更が入って、実行環境の実装もそれまでのインタープリタから
バイトコード・インタープリタに置き換えられています。2.xへの移行は、Railsが
割と短期間で2.xに対応したこともあり、わりと短期間(数年?)で完了したように
感じています。Pythonは 2.x→3.x で、多岐に渡る、かなり大きな?変更が入って、
3.0が12年ちょい前の2008/12にリリースされましたが、2.7が2020/01に
EOF(End Of Life)になったにもかかわらず広く利用されていて、
3.xへの移行は完了していません。例えば、Google Chromeのビルドツールであるgnは未だに2.7?で
書かれたままで、3.xに移行する気配はないようです。Perlは5.x→6.0で大きすぎる痛みを伴う変更が計画?されましたが、
6.0の開発は何年も停滞して、ある程度、実装が進んだ頃に、結局、
Perl6.0→Rakuとリネームされ、別の言語になりました。言語仕様への大きな変更は、大きな痛みを伴う(ユーザーに大きな痛みを
強いる)ので、ユーザーの要望に応える形での変更でもない限り、
ユーザーに痛み以上のメリットを提示できないと、移行が進まないよう
です、ので、仕様の策定者は実施前に熟考に熟考を重ねる、と共に
ユーザーの声を聞く必要があるようです。)「Railsはオワコン」の問題点
上記のベストアンサーのように、聞き齧った、どこかで読んだ気がする、うろ覚えの情報
を基に「Railsはオワコン」と、書かれたり、言われたり、していることが多い気がします。Ruby / Rails はオワコンなのか?
Rubyでは、Rails登場以前に、これといったウェブ・アプリケーション・フレームワーク(WAF)
がなく、Rails登場 により、はじめて、RubyがWEBアプリ開発の選択肢の一つになりました。Railsの完成度が初期から割と高く、時代の変化に対応しながらバージョンアップしてきたこと
もあり、Rails以外のWAFが登場しても、Railsを超えるorRailsと並ぶ完成度のモノはなかった
ので、RailsがRubyのWAFのデファクトであり続けてきました。デファクトであるRailsによるエコシステムが醸成され、WAFの再発明をしたり、他のWAF用の
ライブラリを開発するよりも、Rails用のライブラリを開発したほうが世の中で広く使われる
状況になっているので、今もRails用のライブラリが多数開発され続けています。PHPやPythonのように同じような完成度のWAFが多数あると、同じ用途用のライブラリが
WAF毎に存在し、GitHubでのプロジェクトの数も必然的に多くなります。Rubyの場合、WAFの開発まわりがほぼRailsに集約されているので、同じ用途のRails用
ライブラリが複数あっても、PHPやPythonに比べてWAF関連のGitHubプロジェクト数は
少なくなっています。なので、Ruby / Rails のGithubでのプロジェクト数が PHP / Python と比べて少ない
ことを「Ruby / Railsはオワコン」の根拠の一つに挙げるのはナンセンスですね。ちなみに、みんな大好き?GitHub、Rails (Ruby) で構築されています。
https://www.publickey1.jp/blog/19/githubrails_69.html昨日(2021/01/19)、Google Cloud FunctionsでのRubyのサポートが発表されています。
https://www.publickey1.jp/blog/21/google_cloud_functionsruby.htmlつづく&推敲中...
Rails のフロントエンドまわり
Railsのフロントエンドまわりがレガシーにみえることが「Ruby / Rails オワコン」
の根拠の一つになっている気がするので、書いてみます。今でも偶に、remote: true とjs.erbの組み合わせでAJAX化するコードを、
Qiita etcの新しい記事で見かけますが、昔、書かれたコードをメンテナンス
している人でもない限り、Railsのプロジェクトで見掛けることは、ほとんど、
なくなっています。Railsに含まれている機能のみ?でフロントエンドを構築するのは、最早、最適解
ではなく、レガシーなスタイルになっています。Webpacker経由で、Vue.js、React、etcのクライアントサイドJSフレームワーク
と組み合わせて、フロントエンドを構築することが主流になっています。DHHは先月、Turbolinksの発展系Turbo(JS)、クライアントJSフレームワーク
Stimulus2.0、とRailsを組み合わせた、新たな仕組み、Hotwire を発表しました。
現在はベータ版です。Hotwire
https://hotwire.dev
速報: Basecampがリリースした「Hotwire」の概要
https://techracho.bpsinc.jp/hachi8833/2020_12_24/102368HowireがRailsの1機能になるのか、Railsとは別に提供されるのか、は現在不明です。
たぶん、Railsとは別に提供されます。
(Turbo、TurbolinksがTurboの発表にあわせメンテナンス・モードに入ったため、
既存のTurbolinksを利用したRailsアプリのためにTurbo Drive(Turbolinksに相当)が
Railsに含まれる必要があるので、Railsに含まれるようになるはずです。)Railsに含まれている機能のみ?で構築されたレガシーなフロントエンドを低コストで
モダンにできることを売り?にしているようです。Railsしか触ったことのないエンジニアの多いプロジェクトで、Hotwire、流行る、
と思います。推敲中&つづく...
- 投稿日:2021-01-20T03:10:00+09:00
M1のmacに変えたらbundle installできなくなった件
先日、M1のmacbook proが届いて「さぁこれでairにイライラする生活ともおさらばだ!」とウキウキで環境構築していたらbundle installの段階で謎のerrorが出て余計にイライラすることになりました。
「新年早々...」と思いつつ色々調べた結果、なんと解決できたのでメモ程度に共有させていただきます。
エラーについて
※すぐにエラー内容が開けなかったため概要だけにさせてください。覚えていたら追記します。
エラーで詰まるまで以下の手順を踏みました。
・githubからrailsプロジェクトをローカルにclone
・bundle install
そして、エラーを起こしたgemは私が確認した限りでは以下のものでした。- ffi - sassc解決方法
私の環境では以下の手順で解決しました。
Finder>アプリケーション>ターミナル(右クリック)>情報を見る>「Rosettaを使用して開く」にチェック
まとめ
これは他の調べものをしていた際にたまたま見つけた解決方法でした。
一応、以下に本件に関連のありそうなappleのサポートページを載せておきます。
Mac に Rosetta をインストールする必要がある場合
- 投稿日:2021-01-20T00:02:24+09:00
【Rails】フォームの追加・削除(cocoon)
RailsでWebアプリケーションを作成するとき、入力フォームの追加を行いたかったので、以下に手順をまとめてみました。
「cocoon」というgemを使用すると、簡単に作成可能ですので、今回はそちらの方法で進めていきます。ゴールのイメージ
ますは、今回のゴールのイメージを見てみましょう。
アジェンダ
- テーブル設計
- cocoon導入
- モデル作成
- コントローラー作成
- ビュー作成
テーブル設計
「Recipe」を親テーブルとし、その子テーブルとして「RecipeIngredient」と「HowToMake」を用意する。
ここでの親テーブルと子テーブルは1対多の関係。
cocoon導入
cocoonを導入するためには、jQueryが導入されている必要がある。
Gemfilegem 'cocoon' gem "jquery-rails"$ bundle installapplication.js//= require jquery //= require rails-ujs //= require turbolinks //= require_tree . //= require cocoon
//= require jquery
と//= require cocoon
を追記。
上記の順番も大事らしい。モデル作成
$ rails g model Recipe user:references title:string catchcopy:text no_of_dish:string image:string$ rails g model RecipeIngredient recipe:references ing_name:string quantity:string$ rails g model HowToMake recipe:references explanation:text process_image:string order_no:integerマイグレーションの実行
$ rails db:migraterecipe.rbclass Recipe < ApplicationRecord belongs_to :user has_many :recipe_ingredients, dependent: :destroy has_many :how_to_makes, dependent: :destroy accepts_nested_attributes_for :recipe_ingredients, :how_to_makes, allow_destroy: true endrecipe_ingredient.rbclass RecipeIngredient < ApplicationRecord belongs_to :recipe endhow_to_make.rbclass HowToMake < ApplicationRecord belongs_to :recipe end「recipe」と「recipe_ingredients」「how_to_makes」は一対多の関係なので、
has_many
を使用accepts_nested_attributes_for
accepts_nested_attributes_for
を使用することで、指定したモデルのデータを配列としてパラメーターに含めることができる。(以下でも説明します。)
つまり、「recipe」と「recipe_ingredients」「how_to_makes」モデルのデータをまとめて保存できるようになる。参考:https://qiita.com/seimiyajun/items/dff057b3eb40434d5c27
dependent: :destroy
dependent: :destroy
を指定したクラスが削除された場合、dependent: :destroy
を設定したモデルのインスタンスも削除される。今回の場合、
Recipe
が削除された場合、RecipeIngredients
とHowToMake
のインスタンスも削除される。参考:https://qiita.com/eitches/items/1ad419dc705f807735e0
コントローラー作成
$ rails g controller recipesコントローラー内編集
recipes_controller.rbclass RecipesController < ApplicationController def new @recipe = Recipe.new @recipe_ingredients = @recipe.recipe_ingredients.build ##親モデル.子モデル.buildで子モデルのインスタンス作成 @how_to_makes = @recipe.how_to_makes.build end def create @recipe = Recipe.new(recipe_params) if @recipe.save redirect_to root_path else render :new end end private def recipe_params params.require(:recipe).permit(:title, :catchcopy, :no_of_dish, :image, recipe_ingredients_attributes:[:ing_name, :quantity, :_destroy], how_to_makes_attributes:[:explanation, :process_image, :order_no, :_destroy]) end end
accepts_nested_attributes_for
で指定したrecipe_ingredientsモデルを
recipe_ingredients_attributes: []
として一緒に追加して送ることができる。
how_to_makes_attributes: []
も同様。
_destroy
を入力することで、削除用のパラメータを受け入れられるようにする。ビュー作成
長くなるため今回のフォームに関係ない部分は省いております。
recipes/new.html.erb<div class="recipe-post"> <%= form_with(model: @recipe, local: true) do |f| %> <div class="recipe-ingredients"> <div class="mx-auto"> <%= f.fields_for :recipe_ingredients do |t| %> <%= render "recipes/recipe_ingredient_fields", f: t %> <% end %> </div> <div id="detail-association-insertion-point"></div> <div class="col-10 mx-auto mt-2"> <%= link_to_add_association "+フォームを追加", f, :recipe_ingredients, class: "btn btn-secondary btn-block", data: { association_insertion_node: '#detail-association-insertion-point', association_insertion_method: 'after' }%> </div> </div> <% end %> </div>それでは、以下で説明していきます。
<%= f.fields_for :recipe_ingredients do |t| %> <%= render "recipes/recipe_ingredient_fields", f: t %> <% end %>
fields_for
によってform_with
内で異なるモデル(今回はRecipeIngredient)を編集することができるようになる。
render
でrecipe_ingredient_fields(ファイル名)
に飛び、ここで動的に追加するフォームの中身を記載する。(以下で説明します。)<%= link_to_add_association "+フォームを追加", f, :recipe_ingredients, class: "btn btn-secondary btn-block", data: { association_insertion_node: '#detail-association-insertion-point', association_insertion_method: 'after' }%>
link_to_add_association
によってフォームが追加される。
association_insertion_node: '#detail-association-insertion-point'
association_insertion_method: 'after'
によってフォームの表示位置を指定。
<div id="detail-association-insertion-point"></div>
に代入されます。_recipe_ingredient_fields.html.erb<div class="nested-fields"> <div class="row mx-auto"> <div class="col-5"><%= f.text_field :ing_name, class: "form-control", placeholder: "材料" %></div> <div class="offset-1 col-2"><%= f.text_field :quantity, class: "form-control", placeholder: "分量" %></div> <div class="offset-1 col-1 px-0 w-auto"> <%= link_to_remove_association "削除", f, class: "btn btn-secondary btn-block" %> </div> </div> </div>ファイル名は
_モデル名_fields.html.erb
で固定。
このパーシャルにnested_fields
というクラスを設定してフォーム内容を囲む必要あり。
link_to_remove_association
によってフォームの削除ができる。参考:
https://qiita.com/matata0623/items/8868a7fcb6ec0817d064
https://qiita.com/obmshk/items/0e942177d8a44091bf09補足や修正点などありましたら、是非コメントお願いします!!