- 投稿日:2019-07-10T23:11:34+09:00
RSpecの導入
ユーザー認証の単体テスト
ユーザーモデルクラスが単体で正常に動作するかテストを行う
RSpecを導入する
Gemfileに gem 'rspec-rails' を追記する
Gemfilegroup :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platform: :mri gem 'capistrano' gem 'capistrano-rbenv' gem 'capistrano-bundler' gem 'capistrano-rails' gem 'capistrano3-unicorn' gem 'rspec-rails' end追記したらbundle intallを行う
RSpec用の設定ファイルを作成する
$ rails g rspec:installターミナルで実行すると、以下のようにファイルが作成される
create .rspec create spec create spec/spec_helper.rb create spec/rails_helper.rb.rspecに追記する
.rspec--format documentationこれで設定ファイルの準備は完了♩
RSpecが正常に利用できるかの確認
$ bundle exec rspecターミナルで上記を実行して、次の通り表示されれば利用できます。
No examples found. Finished in 0.00058 seconds (files took 0.20912 seconds to load) 0 examples, 0 failures
- 投稿日:2019-07-10T23:10:39+09:00
今日学んだ事
7/10(水)
●groupメソッド
・テーブルのレコードを指定したカラムでまとめた状態で取得する。
コード
モデル.group(カラム名)・idが一番小さいコードの1件が表示されるが、裏側ではまとめられた状態で取得されている。
・具体的に何個まとまっているか個数は分からない。●countメソッド
・配列などの要素数を返すメソッド。
・groupメソッドに続けて使うと、まとめられたそれぞれのレコードの数が取得できる。
コードモデル.group(カラム名).count・返り値はハッシュとなる
●keysメソッド
・ハッシュはkeysメソッドを持っている
・ハッシュのキーだけを取り出し、配列として返すメソッド●mapメソッド
・配列の中身を1つずつ取り出してブロックという構文を繰り返し実行する。
・ブロックの返り値を集めた新しい配列を作成する。
コード配列オブジェクト.map{|ele| ブロックの処理}●order('count_カラム名').count(カラム名)
・指定したカラムをグルーピングし、それぞれのレコード数でソートできる
- 投稿日:2019-07-10T22:59:43+09:00
【Rails】ユーザ作成
Railsのユーザ作成について
Railsでログイン機能を実装する場合に、ユーザ作成を行うと思います。
今回は、その、ユーザ作成機能について説明していきます。使用するコントローラ
toppagesコントローラ(サインアップページへ移行するurlがある)
-indexusersコントローラ
-index,show,new,createの二つです。toppages,usersのように、語尾に「s」を付けているのは、あとあと便利になってくるからです。
使用するモデル
Userモデル
-name:string email:string password_digest:stringユーザ名、メールアドレス、パスワードを入力とします。
Gemファイルに
gem 'bcrypt', '~> '
のような記述がありますが、railsに提供されている認証機能です。
この行のコメントアウトを消し、
$ bundle install
を実行し、railsのサーバを再起動させましょう。
また、railsで「bcrypt」を使用する際は、モデル作成時に、
password_digest:string
の記述が必須となります。この記述が無ければ認証ができなくなるので注意しましょう。コントローラ
topppagesコントローラは、ページの表示だけなので、usersコントローラのみを記述します。
users.rbclass UsersController < ApplicationController def index @users = User.all.page(params[:page]) end def show @user = User.find(params[:id]) end def new @user = User.new end def create @user = User.new(user_params) if @user.save flash[:success] = 'ユーザを登録しました。' redirect_to @user else flash.now[:danger] = 'ユーザの登録に失敗しました' render :new end end private def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end end特筆すべきなのはcreateアクションのuser_paramsのところです。
ストロングパラメータの、password_confirmationは、確認用のパスワードのことです。
password_confirmationが記述されることで、パスワードの確認をプログラムがいい感じにやってのけてくれます。モデル
ユーザモデルに、has_secure_passwordと記述することでbcryptの認証機能を呼び出すことが出来ます。
user.rbclass User < ApplicationRecord has_secure_password endユーザ作成画面
CSSも適用してない最低限の画面です。
new.html.erb<h1>Sign up</h1> <p> <%= form_for(@user) do |f| %> <p> <div class="form-group"> <%= f.label :name, 'Name' %> <%= f.text_field :name, class: 'form-control' %> </div> <div class="form-group"> <%= f.label :email, 'Email' %> <%= f.email_field :email, class: 'form-control' %> </div> <div class="form-group"> <%= f.label :password, 'Password' %> <%= f.password_field :password, class: 'form-control' %> </div> <div class="form-group"> <%= f.label :password_confirmation, 'Confirmation' %> <%= f.password_field :password_confirmation, class: 'form-control' %> </div> <P> <%= f.submit 'Sign up', class: 'btn btn-primary btn-block' %> <% end %>show.html.erb<h3 class="panel-title"><%= @user.name %></h3>これでユーザ作成に必要な主要な部分は完成しました!
- 投稿日:2019-07-10T21:39:41+09:00
RailsのログからRubyGemsによるwarningを非表示にする方法
現象
Ruby v2.6とRails5.1系でRubyがRails側のGemに対してものすごい数のwarningを出すようになりました。
具体的には、ActiveRecordの内部でBigDecimal.new
を呼んでいるようで、それに対してwarningが出ています。こんな感じのエラーが出る.../vendor/bundle/ruby/2.6.0/gems/activerecord-5.1.7/lib/active_record/connection_adapters/mysql/database_statements.rb:32: warning: BigDecimal.new is deprecated; use BigDecimal() method instead.Ruby v2.6では明示的にwarningを出すようになったからだそうです。
ref: Ruby 2.6 の変更点 - Numeric, BigDecimal BigDecmial.new が非推奨対処法
対処法としてはJeremy Evans氏作のruby-warning gemを使うと良さげです。
具体的には下記のような処理をconfig/initializers配下に置いておくと、Railsが起動される前に読み込まれて、Gemに起因するwarningがログに出なくなります。*開発環境ではログに出るようにしておくと、「あ、このGemアップデートしなきゃ」などが分かっていいかなと思います。
initializer配下にこんな感じのを置いておくunless Rails.env.development? Gem.path.each do |path| Warning.ignore(//, path) end end他にもっとスマートな方法をご存知の方がいらっしゃいましたら、ご指摘お願いします。
![]()
- 投稿日:2019-07-10T21:35:41+09:00
ほとんどアクセスのない個人開発サービスがAWSに月額いくら払っているか全て公開します
はじめに
「AWSって結局いくらかかるの?」
これが結構見積もりが難しい問題で、ざっくりAWSのようにざっくり見積もれるサービスが登場したのはその見積もりの難しさから来ていると思う。個人的に開発しているwebサービスをAWSで公開してからしばらくたって、月の料金が安定しているので、ここで公開してみる。
しょっぼいwebサービスを公開したいけど、AWSだといくら掛かるのかなー?という方に向けて書いているので、「herokuなら無料だぜ!もしくは7ドルだぜ!」とかいう話ではないです。
サービス概要
公開したサービスはこちら。
https://uwaoe.nethtml5のcanvas機能を利用してブラウザ上でお絵かきすることができて、他の人が描いた絵にうわがき(というか落書き)することができる。
サーバはRuby on Rails、フロントはVue.jsで作った。利用ユーザは2人。
たった2人!!
これはストレージ的にもアクセス数的にも安上がり!!!料金内訳
AWSコンソールのコストエクスプローラから、半年間の支払い金額を取得した。
EC2 ELB EC2 インスタンス EC2 その他 税金 Route 53 S3 CloudFront 合計 2019-01-01 18.08 11.31 3.60 2.68 0.50 0.02 0.01 36.20 2019-02-01 16.33 10.21 3.60 2.46 0.50 0.02 0.02 33.14 2019-03-01 18.08 11.31 3.60 2.68 0.50 0.02 0.01 36.20 2019-04-01 17.50 10.92 3.60 2.60 0.50 0.02 0.01 35.15 2019-05-01 18.08 11.31 3.60 2.68 0.50 0.02 0.01 36.20 2019-06-01 17.50 10.94 3.60 2.61 0.50 0.02 0.01 35.18 ※ 単位は$
※ 見易さのために少数第3位を四捨五入していますEC2 ELB
平均 $17.595(ドル円108円として約1900円)
EC2インスタンスは1台しか使ってないのだけど、ELBで簡単にhttpsを使いたかったので導入。
結構する。httpsにしたいだけなので、Let's Encryptとか使ってEC2に直接証明書をインストールしたほうが安上がりだったかな。
初回12ヶ月間は1台分無料だけど、無料期間は切れているため課金。EC2 インスタンス
平均 $11.000(ドル円108円として約1188円)
インスタンスはt2.microが1台。t3ではない。
microインスタンスには、初回12ヶ月は1台分が無料というキャンペーンがあるんだけど、12ヶ月間の無料期間は過ぎているためお金がかかっている。EC2 その他
平均 $3.600(ドル円108円として約389円)
EBSの料金ぽい。
SSD30Gを使っているので計算は$0.12 * 30
。
空きがめっちゃあるのでもっと少なくてもいけそう。Route 53
平均 $0.500(ドル円108円として約54円)
uwaoe.net
のドメインを登録している。
リクエスト数で料金が上がるらしいが、現状やっすいので、金額的には気にならないレベル。S3
平均 $0.020(ドル円108円として約2円)
おえかきされた絵やアップロードされたユーザのアバターを保存している。
put系の書き込みリクエストが1000件、get系の取得リクエストが45000件、データ送料が 50MB程度なので大したことがない。
rails側で画像のサムネイルを何種類か作成してS3に上げたり、画像アップロード用のgemのshrineがキャッシュをS3に作りまくったりしているけど、軽い。
現状やっすいので、誤差レベル。関係ないけど、gem shrineはBase64エンコードされた画像を簡単に扱えるので、canvasの画像を扱いたい場合におすすめ。
Coundfront
平均 $0.012(ドル円108円として約1円)
t2.microサーバから画像配信するのは不安があったので、画像の配信にはCloudfrontを使用するようにした。
現状やっすいね。RDS
使ってない。
節約のためにEC2インスタンスにmysql-serverを入れちゃったのだけど、メモリが足りなくて辛い。
t2.microってメモリ0.5Gじゃん? mysqldがメモリを160MB使っていて、railsを動かしているpumaサーバが180MB使っている。その他サービスで使われているメモリもありで、デプロイを実行するメモリが足りない。デプロイする時、assets:precompile
のたびにメモリが足りなくてアプリケーションサーバが死ぬというカッコいい状態になっている。CloudWatch
使ってない。
別にサービスが何時間止まろうが困らないし・・。SES
使ってるけど0円。
月62,000件までは0円らしい。合計
平均 $35.345(ドル円108円として約3817円)
おわりに
月3800円。上で書いたようにALBが無駄っぽいので月2000円ぐらいまで節約できると思う。
今の所、広告や課金要素は全く無いので完全赤字になっているが、趣味として見たら安い。AWSには初回12ヶ月無料なことがいっぱいあって、1年間であれば次の構成が無料にできそう。
* EC2 microインスタンス1つ
* ALB 1つ
* RDS microインスタンス1つ新規に個人開発のサービス公開を目論んでいる方は、AWSもインフラの候補にしてみてはどうだろうか。
- 投稿日:2019-07-10T21:17:46+09:00
BootstrapVueをRailsに導入してみる
初投稿です
RailsでBootstrapとVue.jsを使う方法を調べると、
Vue.jsをrails new project --webpack=vue
で入れてきて、
BootstrapはGemfileにgem 'bootstrap'
を書いてbundle installしてjsやscssをいじって、、、
というのがオーソドックスなやり方のようちょっと面倒なのと、なぜかvueファイルのtemplateに書いたtooltipがちゃんと効いてくれなかったので、Bootstrapをgemで入れないようにして、yarnでBootstrapVueを入れるようにしてみた
BootstrapVue
おなじみBootstrapとVue.jsが合体したもの
公式サイトやったこと
プロジェクト作成(webpackでvueもインストール)
$ rails new bootstrapvue_rails --webpack=vueyarnでBootstrapVueをインストール
$ cd bootstrapvue_rails $ yarn add bootstrap-vue画面を用意して、ルーティングしてあげる
$ rails g controller Home index
config/routes.rbRails.application.routes.draw do root to: 'home#index' # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end画面のjsファイルを作る
app/javascript/packs/home.jsimport Vue from 'vue/dist/vue.esm' import BootstrapVue from 'bootstrap-vue' import App from '../app.vue' import 'bootstrap/dist/css/bootstrap.css' import 'bootstrap-vue/dist/bootstrap-vue.css' Vue.use(BootstrapVue) document.addEventListener('DOMContentLoaded', () => { const app = new Vue({ el: '#hello', data: { message: "Can you say hello?" }, components: { App } }) })vueファイルを作る
app/javascript/app.vue<template> <div id="app"> <p>{{ message }}</p> <div class="text-center my-3"> <b-button v-b-tooltip.hover title="Tooltip content">Hover Me</b-button> </div> </div> </template> <script> export default { data: function () { return { message: "Hello Vue!" } } } </script> <style scoped> p { font-size: 2em; text-align: center; } </style>viewで読み込む
app/views/home/index.html.erb<h1>Home#index</h1> <p>Find me in app/views/home/index.html.erb</p> <div id='hello'> {{message}} <app></app> </div> <%= javascript_pack_tag 'home' %>サーバーを立ち上げたらtooltipが効いてくれてる
$ ./bin/webpack-dev-server $ rails s
- 投稿日:2019-07-10T21:11:25+09:00
TECH ~Day15~
中間試験
これまで2週間学習をしてきた知識を活かしてこの日は中間試験を行いました。
現時点で自分がどれだけ知識を覚えられているのかというのがよくわかりました。ちなみに結果としては百点満点中の7点でした。。。。。
正直この点数も実際かなり個人的に甘くつけた点数なので正直かなりショックは大きかったです。
しかし後からメンターの方から聞いた話だと、この中間試験の今までの平均点は0〜14点という話でした。これを聞いた時は最初のショックも少しは無くなりました。現時点ではまだまだ社会で通用する力はかけらも備わっていないということがわかりました。
これからもさらに気を緩めずに学習に力を入れていかなければいけないというように改めて思いました。
- 投稿日:2019-07-10T20:50:03+09:00
あなたはRailsチュートリアルで一体なにを学んだというのか【5章】
注意:プログラミング歴29日の初心者が書いています
注意:間違っていたら優しく教えてください(喜びます)
「Ruby on Rails チュートリアル実例を使ってRailsを学ぼう」
https://railstutorial.jp/素晴らしいチュートリアルに感謝します。
5.1.1 ナビゲーション
link_to
について
link_to
はRailsのヘルパー(viewsで使える関数)です。
最終的には<a>タグが生成されます。
第1引数はリンクテキスト、第2引数はURLです。link_to "sample app", '#', id:"logo"カッコが省略されています。関数です。
link_to("sample app", '#', id:"logo" )
image_tag
について
image_tag
もRailsのヘルパー(viewsで使える関数)です。
最終的には<img>タグが生成されます。
第1引数は画像のsrc、第2引数はここではalt属性です。image_tag("rails.png", alt: "Rails logo")第一引数として、単に画像ファイル名のみを指定した場合は、
asset
ディレクトリ内のimages
ディレクトリから自動で画像を引っ張ってきてくれます。5.1.2 BootstrapとカスタムCSS
アセットパイプラインについて
↓がわかりやすい
「railsのアセットパイプラインについて解説する」@hogehoge1234
https://qiita.com/hogehoge1234/items/9a94ebc93c5f937502cdアセットパイプラインとは、htmlファイルと、css,javascript, imgファイルを自動で統合できるようにする仕組みです。
そもそも、webサイトの表示は、主に以下の3つをブラウザが読み込むことで実現される。
htmlファイル
cssファイル
JavaScriptファイル
*imgファイル
これらを一つのファイルで実現することは可能だが、わかりやすいように通常は別々のファイルで作って、最後にそれぞれをhtmlファイルにリンクさせる。
Railsにおいては、
htmlファイルに相当するhtml.erbファイルはviewsディレクトリに保存します。
cssとJavascriptとimgファイルはassetディレクトリ内部にある、それぞれのディレクトリに保存します。
さらに言うと、cssファイルではなくsassというcssの便利バージョンになっています。sassファイルからcssファイルに変換(コンパイル)しないとブラウザが読み込めないのですが、アセットパイプラインにはコンパイラも含まれています。
つまり、assetディレクトリに入っているファイルたちが、あたかもパイプの中を通りながら1つのファイルに統合されて出てくるようなイメージです。
Railsサーバーの再起動が必要なタイミング
Rubyのバージョンを変更したり、
Gemfileを変更したり、
Railsの内部クラスから何かを変更した場合は、
再起動する必要があります。
5.1.3 パーシャル (partial)
render
についてrenderはヘルパー(viewsに使える関数)の呼び出しをします。
テンプレートを呼び出して表示させるためによく使われます。テンプレート(要は繰り返し使うhtml部分など)は、partial(パーシャル)という仕組みを使って、コードを一つのファイルにまとめておきます。
その際、パーシャルのファイル名は、
_(アンダースコア)
で始まるファイル名にします。render 'layouts/shim'これは、
/_shim.html.erb
というファイルを探してその内容をレンダリング(表示)します。
先頭の_(アンダースコア)
とhtml.erb
などの余分な内容は省略して記述します。もちろん、パーシャルにするコードは別ディレクトリに用意しておく必要があります。
5.2.1 アセットパイプライン
アセットディレクトリについて
assets
ディレクトリは、その内容によって、以下3つのディレクトリに含まれています。
app/assets
: 現在のアプリケーション固有のアセット
lib/assets
: あなたの開発チームによって作成されたライブラリ用のアセット
vendor/assets
: サードパーティのアセットそれぞれの
assets
ディレクトリの内部には、CSS、JavaScript、Imagesのディレクトリが存在します。マニフェストファイルについて
統合させたり読み込ませるCSSやJavaScriptを指定したり設定したりするファイルです。
プリプロセッサエンジンについて
.erb
や.scss
など、拡張子を読み取って、.html
や.css
にコンパイルできるように加工してくれます。その他の加工について
ファイルすべてに対して 不要な空白やインデントを取り除く処理を行い、ファイルサイズを最小化してくれます。結果として、読み込みが早くなります。
5.3 レイアウトのリンク
名前付きルート
root_path -> '/' root_url -> 'http://www.example.com/'例えば、ルートに関してはすでに
root
という名前付きルートが定義されています。
ここに_path
メソッドや_url
メソッドを使用することで、名前付きルートの中身を見てみることができます。get 'static_pages/help'上記を、以下の名前付きルートに変換します。
get '/help', to: 'static_pages#help'読み方は、
『GETリクエスト(ページを取得しろ)が/help
に送信されたとき、
StaticPagesコントローラーのhelpアクションを呼び出してくれ』です。test "should get help" do get help_path #これ assert_response :success assert_select "title", "Help | Ruby on Rails Tutorial Sample App" endテストコードの修正をします。
これは、help
という名前付きルートに対して、_path
メソッドを使用し、
/static_pages/help
というパスを取得しています。5.3.4 リンクのテスト
統合テスト
統合テストは、複数のコントローラの動きをチェックするテストのことです。
assert_select "a[href=?]", about_path
?
の中身は、第2引数のabout_path
になります。
つまり、<a href="/about">...</a>
というaboutページへのパスを含む<a>タグがあるかどうかのチェックです。$ rails test:integration上記コマンドで動かします。
5.4.1 Usersコントローラ
Usersコントローラの生成 (newアクションを追加)
「newアクション」とは、Railsの7アクションの1つです。何かを新規作成する際のアクションです。
get '/signup', to: 'users#new'ルーティングに
/signup
を追加したことによって、signup_path
でページへのパスを表現できるようになりました。
- 投稿日:2019-07-10T20:50:03+09:00
わたしがRailsチュートリアルで学んだこと【5章】
注意:プログラミング歴29日の初心者が書いています
注意:間違っていたら優しく教えてください(喜びます)
「Ruby on Rails チュートリアル実例を使ってRailsを学ぼう」
https://railstutorial.jp/素晴らしいチュートリアルに感謝します。
5.1.1 ナビゲーション
link_to
について
link_to
はRailsのヘルパー(viewsで使える関数)です。
最終的には<a>タグが生成されます。
第1引数はリンクテキスト、第2引数はURLです。link_to "sample app", '#', id:"logo"カッコが省略されています。関数です。
link_to("sample app", '#', id:"logo" )
image_tag
について
image_tag
もRailsのヘルパー(viewsで使える関数)です。
最終的には<img>タグが生成されます。
第1引数は画像のsrc、第2引数はここではalt属性です。image_tag("rails.png", alt: "Rails logo")第一引数として、単に画像ファイル名のみを指定した場合は、
asset
ディレクトリ内のimages
ディレクトリから自動で画像を引っ張ってきてくれます。5.1.2 BootstrapとカスタムCSS
アセットパイプラインについて
↓がわかりやすい
「railsのアセットパイプラインについて解説する」@hogehoge1234
https://qiita.com/hogehoge1234/items/9a94ebc93c5f937502cdアセットパイプラインとは、htmlファイルと、css,javascript, imgファイルを自動で統合できるようにする仕組みです。
そもそも、webサイトの表示は、主に以下の3つをブラウザが読み込むことで実現される。
htmlファイル
cssファイル
JavaScriptファイル
*imgファイル
これらを一つのファイルで実現することは可能だが、わかりやすいように通常は別々のファイルで作って、最後にそれぞれをhtmlファイルにリンクさせる。
Railsにおいては、
htmlファイルに相当するhtml.erbファイルはviewsディレクトリに保存します。
cssとJavascriptとimgファイルはassetディレクトリ内部にある、それぞれのディレクトリに保存します。
さらに言うと、cssファイルではなくsassというcssの便利バージョンになっています。sassファイルからcssファイルに変換(コンパイル)しないとブラウザが読み込めないのですが、アセットパイプラインにはコンパイラも含まれています。
つまり、assetディレクトリに入っているファイルたちが、あたかもパイプの中を通りながら1つのファイルに統合されて出てくるようなイメージです。
Railsサーバーの再起動が必要なタイミング
Rubyのバージョンを変更したり、
Gemfileを変更したり、
Railsの内部クラスから何かを変更した場合は、
再起動する必要があります。
5.1.3 パーシャル (partial)
render
についてrenderはヘルパー(viewsに使える関数)の呼び出しをします。
テンプレートを呼び出して表示させるためによく使われます。テンプレート(要は繰り返し使うhtml部分など)は、partial(パーシャル)という仕組みを使って、コードを一つのファイルにまとめておきます。
その際、パーシャルのファイル名は、
_(アンダースコア)
で始まるファイル名にします。render 'layouts/shim'これは、
/_shim.html.erb
というファイルを探してその内容をレンダリング(表示)します。
先頭の_(アンダースコア)
とhtml.erb
などの余分な内容は省略して記述します。もちろん、パーシャルにするコードは別ディレクトリに用意しておく必要があります。
5.2.1 アセットパイプライン
アセットディレクトリについて
assets
ディレクトリは、その内容によって、以下3つのディレクトリに含まれています。
app/assets
: 現在のアプリケーション固有のアセット
lib/assets
: あなたの開発チームによって作成されたライブラリ用のアセット
vendor/assets
: サードパーティのアセットそれぞれの
assets
ディレクトリの内部には、CSS、JavaScript、Imagesのディレクトリが存在します。マニフェストファイルについて
統合させたり読み込ませるCSSやJavaScriptを指定したり設定したりするファイルです。
プリプロセッサエンジンについて
.erb
や.scss
など、拡張子を読み取って、.html
や.css
にコンパイルできるように加工してくれます。その他の加工について
ファイルすべてに対して 不要な空白やインデントを取り除く処理を行い、ファイルサイズを最小化してくれます。結果として、読み込みが早くなります。
5.3 レイアウトのリンク
名前付きルート
root_path -> '/' root_url -> 'http://www.example.com/'例えば、ルートに関してはすでに
root
という名前付きルートが定義されています。
ここに_path
メソッドや_url
メソッドを使用することで、名前付きルートの中身を見てみることができます。get 'static_pages/help'上記を、以下の名前付きルートに変換します。
get '/help', to: 'static_pages#help'読み方は、
『GETリクエスト(ページを取得しろ)が/help
に送信されたとき、
StaticPagesコントローラーのhelpアクションを呼び出してくれ』です。test "should get help" do get help_path #これ assert_response :success assert_select "title", "Help | Ruby on Rails Tutorial Sample App" endテストコードの修正をします。
これは、help
という名前付きルートに対して、_path
メソッドを使用し、
/static_pages/help
というパスを取得しています。5.3.4 リンクのテスト
統合テスト
統合テストは、複数のコントローラの動きをチェックするテストのことです。
assert_select "a[href=?]", about_path
?
の中身は、第2引数のabout_path
になります。
つまり、<a href="/about">...</a>
というaboutページへのパスを含む<a>タグがあるかどうかのチェックです。$ rails test:integration上記コマンドで動かします。
5.4.1 Usersコントローラ
Usersコントローラの生成 (newアクションを追加)
「newアクション」とは、Railsの7アクションの1つです。何かを新規作成する際のアクションです。
get '/signup', to: 'users#new'ルーティングに
/signup
を追加したことによって、signup_path
でページへのパスを表現できるようになりました。
- 投稿日:2019-07-10T20:31:18+09:00
[メモ]Windows上のVagrantでRails環境構築する際の共有フォルダの注意点
gemを共有フォルダ以下に置くとエラーになる
解決策:gemを共有フォルダ以外にインストールする。
> bundle install --path 共有フォルダ以外へのpathsqlite3のデータベースファイルを共有フォルダ以下に置くとエラーになる
解決策1:マイグレーションについては以下のように対処できる。
config/database.yml... test: <<: *default database: db/test.sqlite3 # ←pathを共有フォルダ以外に変更 production: <<: *default database: db/production.sqlite3 # ←pathを共有フォルダ以外に変更解決策2:PostgreSQL, MySQLなどの他のDBを使う。
- 投稿日:2019-07-10T20:31:18+09:00
Windows上のVagrantでRails環境構築する際の共有フォルダの注意点【メモ】
gemを共有フォルダ以下にインストールするとエラーになる
解決策:gemを共有フォルダ以外にインストールする。
> bundle install --path 共有フォルダ以外へのpathsqlite3のデータベースファイルを共有フォルダ以下に置くとエラーになる
解決策1:マイグレーションについては以下のように対処できる。
config/database.yml... test: <<: *default database: db/test.sqlite3 # ←pathを共有フォルダ以外に変更 production: <<: *default database: db/production.sqlite3 # ←pathを共有フォルダ以外に変更解決策2:PostgreSQL, MySQLなどの他のDBを使う。
筆者の環境
Host OS: Windows 10 Home (バージョン 1809(OSビルド 17763.557))
Vagrant 2.2.4
Virtual Box 6.0.8
Vagrant Box(Guest OS): CentOS/7
- 投稿日:2019-07-10T17:58:41+09:00
rails runner で Please specify a valid ruby command or the path of a script to run.
問題:lib以下のディレクトリを読み込んでくれない
スクリプトはこんな感じ
#lib/batch/push.rb class Test def self.push require 'json' result = TalkHistory.where(call_status: 'skyway_ringing').where(call_duration: nil).where('talked_at>?',Time.zone.now - 1.days).count("id") result_hash = {"count"=> result} File.open("test.json","w") do |file| JSON.dump(result_hash,file) end #jsonファイルのアップロード require 'aws-sdk' s3 = Aws::S3::Resource.new( :region => 'ap-northeast-1', :access_key_id => ENV['ACCESS_KEY_ID'], :secret_access_key => ENV['SECRET_ACCESS_KEY'] ) bucket = s3.bucket('testbucket0709') bucket.object('test').upload_file("test.json") puts bucket.object('test').exists? puts bucket.object('test').get.body.read end end実行すると...
rails ruuner 'Test.push' => Please specify a valid ruby command or the path of a script to run. Run 'bin/rails runner -h' for help. uninitialized constant Testautoload_pathsを確認
$ bin/rails r 'puts ActiveSupport::Dependencies.autoload_paths' /Users/satou/projects/koetomosql/lib /Users/satou/projects/koetomosql/lib/ /Users/satou/projects/koetomosql/lib/tasks/ /Users/satou/projects/koetomosql/lib/batch/ /Users/satou/projects/koetomosql/lib/assets/ /Users/satou/projects/koetomosql/app/assets /Users/satou/projects/koetomosql/app/channels /Users/satou/projects/koetomosql/app/controllers /Users/satou/projects/koetomosql/app/controllers/concerns /Users/satou/projects/koetomosql/app/helpers /Users/satou/projects/koetomosql/app/jobs /Users/satou/projects/koetomosql/app/mailers /Users/satou/projects/koetomosql/app/models /Users/satou/projects/koetomosql/app/models/concerns /Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/assets /Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/controllers /Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/controllers/concerns /Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/javascript /Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/jobs /Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/models /Users/satou/projects/koetomosql/test/mailers/previews問題なさそう
でもコンソールで確認するとクラスを読み込めてない...Loading development environment (Rails 5.2.3) irb(main):001:0> Test Traceback (most recent call last): 1: from (irb):1 NameError (uninitialized constant Test)解決
ディレクトリ名とファイル名をクラス名と合わせる必要があるらしい!!
以下の記事の最後のほう!!
あーむかついた!
Rails Runnerを使ってみる
- 投稿日:2019-07-10T14:32:02+09:00
【Rails】sendを使ってメタプロっぽい書き方をしたので記しておく
タイトル通り、sendメソッドを使ってメタプロっぽい書き方をやってみたので書き残しておく。
説明
deviseで
client
とcreator
という2つのモデルを用意している。
それぞれ、nameが登録されているか/されていないかによって、ログイン後の繊維ページが異なるが、
clientとcreator間での法則性は同一である。
↓こんな感じ
name登録済み name未登録 client client_mypage_path edit_client_path(current_client) creator creator_mypage_path edit_creator_path(current_creator) send使ってafter_sign_in_path_for
application_controller.rbclass ApplicationController < ActionController::Base helper_method :current_resource, :current_resource_model, :other_side_model, :registered_name? def current_resource if client_signed_in? current_client elsif creator_signed_in? current_creator end end def current_resource_model return unless current_resource current_resource.class.to_s.downcase end # ログイン後に遷移するpathを設定 def after_sign_in_path_for(resource) return unless current_resource resource_mypage_path = send(current_resource_model + "_mypage_path") edit_resource_path = send("edit_" + current_resource_model + "_path", current_resource) registered_name? ? resource_mypage_path : edit_resource_path end def registered_name? current_resource&.name.present? endこのように、複数のdeviseモデルでの法則的なコードを1つにまとめて記述する時に役に立ちそう。
- 投稿日:2019-07-10T13:11:49+09:00
あなたはRailsチュートリアルで一体なにを学んだというのか【4章】
注意:プログラミング歴29日の初心者が書いています
注意:間違っていたら優しく教えてください(喜びます)
「Ruby on Rails チュートリアル実例を使ってRailsを学ぼう」
https://railstutorial.jp/素晴らしいチュートリアルに感謝します。
4.1.1 組み込みヘルパー
組み込み関数ってなんですか
組み込み関数とは、プログラミング言語がもともと用意してくれている関数のことです。
ビルトイン関数とも言います。ヘルパーってなんですか
viewで使える関数のことをrailsではヘルパーと呼んでいます。
つまり、
「組み込みヘルパー」とは
「railsがもともと用意してくれている」
「viewで使える関数」
のことです。
4.1.2 カスタムヘルパー
カスタムヘルパーってなんですか
「自分でカスタムした(自分で作る)」
「viewで使える関数」
ということになります。
リスト 4.2: full_titleヘルパーを定義する
「Home」ページにアクセスした際に、
Home | Ruby on Rails Tutorial Sample App
ではなく、Ruby on Rails Tutorial Sample App
のみを表示させたい。
しかし、現状のコードのまま実装を進めると、|(縦棒)
が残ってしまいます。「full_title」関数(ヘルパー)を作って、
|(縦棒)
が残らないようにしましょう。viewで使いたい関数はhelperディレクトリ内のファイルに記述する
これです。ここで言いたいのは多分これです。
「viewで使いたい関数はhelperディレクトリ内のファイルに記述すること」ヘルパーの中身
module ApplicationHelper # ページごとの完全なタイトルを返します。 def full_title(page_title = '') #1 base_title = "Ruby on Rails Tutorial Sample App" #2 if page_title.empty? #3 base_title #4 else page_title + " | " + base_title #5 end end end#1: full_title関数の定義・引数
page_title = ''
は、『引数としてpage_title
をとる。引数の指定がない場合は' '
を引数とする』という意味です。#2: 変数
base_title
に"Ruby on Rails Tutorial Sample App"
を代入。#3:
page_title
に対して.empty?
メソッドを用いて、変数内に値が存在するかどうかで条件分岐させます。#4:
.empty?
メソッドは、変数が空ならTrue
を返します。page_title
が空のとき、base_titile
のみを返します。
(ちなみに、Rubyではメソッドがtrueまたはfalseを返す場合、メソッド名に?がついています。)#5: 変数内に値が存在する場合、
page_title
と|(縦棒)
とbase_title
を返します。
application_helper.rb
に書き込まれた上記の内容は、railsの力によって、自動的にapplication.html.erb
で使用可能になります。apprication.html.erbの中身
<title><%= full_title(yield(:title)) %></title>タイトルタグのコードです。
ヘルパーで定義した、「full_title」関数を呼び出しています。引数には、yieldメソッドでページごとにprovideで設定してあるタイトルを呼び出しています。
Homeページから「Home | 」を取り除く
まずはテストから作り初めて、それからテストを通す実装をします。
test "should get home" do get static_pages_home_url assert_response :success assert_select "title", "Ruby on Rails Tutorial Sample App"#←ココ endhome_urlのgetリクエストに対して、
titleは"Ruby on Rails Tutorial Sample App"
を表示
というテストです。
rails test
すると当然失敗します。
なぜなら、home.html.erb
でprovide
メソッドがタイトルとして"Home"を指定しているからです。テストを通すためには、
home.html.erb
から、provide
メソッドの行を取り除きます。4.3.2 ブロック
ブロックは、メソッドの引数として渡すことのできる処理のかたまりです。
{}波括弧
やdo ... end
の部分がブロックです。test "should get home" do get static_pages_home_url assert_response :success assert_select "title", "Ruby on Rails Tutorial Sample App" endテスト文も、じつは
test
メソッドが、引数としてブロックをとっています。
do ... end
で挟まれた処理がtest
メソッドの引数になっています。4.4.5 ユーザークラス
class User attr_accessor :name, :email #アクセサメソッド def initialize(attributes = {}) #initializeメソッド @name = attributes[:name] @email = attributes[:email] end def formatted_email #インスタンスメソッドの定義 "#{@name} <#{@email}>" end end#アクセサメソッド
インスタンス変数に、クラス外からアクセスできるようになります。#initializeメソッド
User.newを実行すると自動的に呼び出されるメソッドです。
.newと同時に実行されます。#インスタンスメソッドの定義
メソッドを呼び出すことで、
"ユーザー名 <メールアドレス>"という文字列を返すメソッドです。
特に意味はないです。user = User.new(name: "Michael Hartl", email: "mhartl@example.com")上記のように使えます。
- 投稿日:2019-07-10T12:49:15+09:00
[Rails]既存のデータベースにRailsで接続してActiveRecordでレコードを抽出する方法
やりたいこと
[Rails]gem"whenever"を使って定期的にタスクを実行するの続きです
今回は その2:既存のデータベースにRailsで接続してActiveRecordでレコードを抽出する をやりますconfig/database.ymlの中身を変更
development: adapter: mysql2 database: データベース名 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: ユーザ名 password: パスワード host: ホスト port: ポート番号既存のデータベースのスキーマ情報を新規Railsプロジェクトにコピーする
参考記事
Rails - schema.rb(既存DBを使ったアプリ作成)
既存DBを使ってRails以下のコマンドでスキーマ情報がdb/schema.rbに書き込まれる
rake environment -t RAILS_ENV=development db:schema:dump空のマイグレーションファイルを生成して中身を先ほどコピーしてきたschema.rbに置き換えてマイグレートする
rails g migration create_table 中身を書き換えてから rails db:migrateモデルを生成する
テーブルの数だけ作るらしいです(正直まだ理解できてません)
でも作らないとエラー吐かれるので作りました...
オプション指定するとマイグレーションファイル生成するのを防ぐことができます
rails g model モデル名 --migration false
ここまで設定したらActiveRecord使えるようになりました!
lib/tasks/testsql.rb
namespace :testsql do desc "sqlの定期送信" task sql: :environment do require 'json' result = TalkHistory.where(call_status: 'skyway_ringing').where(call_duration: nil).where('talked_at>?',Time.zone.now - 1.days).count("id") result_hash = {"count"=> result} result_json = JSON.generate(result_hash) File.open("test2.json","w") do |file| file.puts result_json end end end
- 投稿日:2019-07-10T12:24:03+09:00
Rails6 のちょい足しな新機能を試す50(scaffold 編)
はじめに
Rails 6 に追加されそうな新機能を試す第50段。 今回は、
scaffold
編です。
Rails 6 では、 belongs_to な関係のあるモデルがあるアプリを scaffold で作った場合に、 belongs_to で指定される親モデルの表示のされ方が変わりました。
...ってなんだか良くわかりませんね。実際にやってみた方がわかりやすいです。
Ruby 2.6.3, Rails 6.0.0.rc1, Rails 5.2.3 で確認しました。Rails 6.0.0.rc1 は
gem install rails --prerelease
でインストールできます。$ rails --version Rails 6.0.0.rc1rails プロジェクトを作る
$ rails new rails6_0_0rc1 $ cd rails6_0_0rc1scaffold を使う
scaffold で Author と Book の CRUD を作成します。Book は、 Author に属します。
$ bin/rails g scaffold Author name $ bin/rails g scaffold Book title author:referencesseed データを作る
Author と Book のデータを1つずつ作成します。
db/seeds.rbauthor = Author.create(name: 'Dave Thomas') Book.create(title: 'Programming Ruby', author: author)データベースを作る
データベースを作って seed データを登録します。
$ bin/rails db:create db:migrate db:seed
rails server を実行して Book のデータを表示する
rails server を実行します。
$ bin/rails s
http://localhost:3000/books と http://localhost:3000/books/1 で一覧画面と詳細画面を表示します。
Rails 5 では
一覧画面でも詳細画面でも、Author はAuthorオブジェクト(
Author#to_s
)を表示します。一覧画面
詳細画面
Rails 6 では
一覧画面でも詳細画面でも、Author は ID (
Author#id
) の 1 を表示します。一覧画面
詳細画面
試したソース
試したソースは以下にあります。
https://github.com/suketa/rails6_0_0rc1/tree/try050_scaffold参考情報
- 投稿日:2019-07-10T12:13:58+09:00
[Rails]gem"whenever"を使って定期的にタスクを実行する
やりたいこと
その1:定期的にSQLを発行して返ってきたデータをjson形式でファイル出力する
その2:既存のDBにRailsで接続してActiveRecordでレコードを抽出する
その3:AWSのS3ストレージにjsonファイルをアップロードする
この記事ではその1だけgem"whenever"を利用した定刻処理の実装
この記事の通りにやりました。記事書いてくれた人ありがとうございます。
参考記事
[初学者]whenever を使って定期的にバッチ処理を行う(公開設定編)コードの全体像
namespace :testsql do desc "sqlの定期送信" task sql: :environment do #SQLの接続 require "mysql2" require 'json' client = Mysql2::Client.new(host: '******', username: ENV["DB_USERNAME"], password: '******', database: ENV["DATABASE"]) result = client.query("select count(id) from talk_histories where call_status = 'skyway_ringing' and call_duration is NULL and talked_at > (now() - interval 1 day)") puts result #=> <Mysql::Result>オブジェクトが返ってくる result.each do |r| puts r #=> {"count(id)"=>85} puts r["count(id)"] #=> 85 $count = {count: r["count(id)"]} #グローバル変数$countにハッシュ形式で格納 end #ファイル作成 File.open("test.json","w") do |text| text.puts $count end #jsonファイルのアップロード require 'aws-sdk' s3 = Aws::S3::Resource.new( #S3リソースの作成 :region => 'ap-northeast-1', :access_key_id => '******', :secret_access_key => '******', ) bucket = s3.bucket('testbucket0709') #バケットの作成 bucket.object('test2').upload_file("test2.json") #.objectの引数がキーになる puts bucket.object('test2').exists? #"test2"のキーを持つオブジェクトがバケットにあるか確認 puts bucket.object('test2').get.body.read #オブジェクトの読み込み end end問題:出力したファイルがJSON形式になっていなかった
json形式になっているかどうかの確認はこちらでやりました
JSONLint参考記事
RubyでのJSONの書き込み
RubyでJSONを扱うときに便利な関数まとめ僕はハッシュなら全部JSONなんじゃないのとか思ってましたがよく見ると全然違いますね
ハッシュ
{"json"=>"12345"}
JSON
'{"rails": {"json": "12345"}}'
どうやらRubyのライブラリを使うそうです
JSON.generate(配列)とするとjson形式のファイルができるっぽい
- 投稿日:2019-07-10T12:00:52+09:00
Rails console でも FactoryBot のメソッド呼び出しを簡単にする
Ruby on Rails + FactoryBot で開発をおこなっていると、Rails console を使ってサクッとデータを作成して REPL で検証したくなることがあります。この時
FactoryBot.create()
やFactoryBot.build()
と書かなければならず、普段テストで書いているcreate()
やbuild()
に比べると若干の面倒さが目立ってしまいます。僕は怠惰なので以下のような hook を
.pryrc
に書いてこの問題を解決してみました。# -*- mode: ruby -*- Pry.hooks.add_hook(:before_session, "use FactoryBot shorthand") do |output, binding, pry| Object.include FactoryBot::Syntax::Methods endこれでいつでも
create(:user)
やbuild(:user)
でユーザーを作成することができます。なお、みなさんご想像の通りトップレベルに世界の開発者が想像もしないようなメソッドを生やすので世界が壊れるかもしれません
![]()
- 投稿日:2019-07-10T11:49:41+09:00
form_tagをform_forに書き換える
初めまして!
Rails初学者が初めてQiitaで書きます!form_forってどうやって書いたらいいの?
アプリを作成する際に苦戦したので備忘録として記事を残しておきます。
form_for基本形<%= form_for (modelobject, option) do |f| %> フォームコントロールの設定 <% end %>これ書いたらformが作成されると思っていましたが、うまくいきません。
まずはビューの部分を記述する
new.html.erb<div class="contents row"> <%= form_for @post do |form| %> //@postにフォームコントロール内で入力する値を入れる// <h5>タイトル</h5> <%= form.text_field :content, placeholder: 'content' %> //ブログのタイトルを入力する為のtext_field <h5>本文</h5> <%= form.text_field :content, placeholder: 'content' %> //ブログの本文を入力する為のtext_filed <%= form.submit "SENT" %> //送信ボタン <% end %> </div>次にcontrollerを編集する
posts_controller.rbclass PostsController < ApplicationController before_action :move_to_index, except: [:index, :show] def new @post = Post.new //新規作成された値は@postに入れる end //~省略~これでform_for内で入力した値は@postに渡されます!
新規作成のフォームは完成したので次は編集する時のフォームの書き方。編集のビュー部分の作成
edit.html.erb<div class="contents row"> <%=form_for @post, url => {action: 'update'} do |form|%> //form_forのupdateアクションを明示する為にaction:を指定 <h5>タイトル</h5> <%= form.text_field :title, placeholder: 'title:最大文字数20文字まで' %> <h5>本文</H5> <%= form_text_field :content. placeholder 'content'%> <%= form.submit "SENT" %> <% end %> </div>次にcontrollerを編集する
posts_controller.rbclass PostsController < ApplicationController before_action :set_post, only: [:edit, :show] //共通のアクションはcallbackする為、before_action内に設定 〜省略〜 def show end def edit end private def set_post @post = Post.find(params[:id]) end def post_params params.require(:post).permit(:content, :title) end end以上でform_forでフォームの新規作成と編集ができるようになりました!
最後に
筆者について
TEXH::EXPERT渋谷校の夜間クラスで4月からRuby・Railsの学習をしています。
記載内容に不備・不足があればご指摘いただけると幸いです。
至らぬ点ばかりですので、改善点がありましたらどんどんご指摘下さい!
- 投稿日:2019-07-10T10:44:22+09:00
rails投稿機能の追加方法 ※自分メモ用
2019/7/10
自動生成されるカラム確認
◎idカラムについて
idカラムには、データベースに保存される時に数字が自動で入る。
idは1から順に入っていき、データ毎に重複しないようになっている。◎created_atカラムとupdated_atカラムについて
created_atカラムとupdated_atカラムには、
データベースに保存された時刻が自動で入るようになっている。
updated_atはデータ更新時にも時刻が更新される。find_byメソッドで投稿を取得する
特定のidの投稿を取得するためには、find_byメソッドを用いる。
find_byメソッドは、ある条件に合致するデータを取得することができます。
図のように、「モデル名.find_by(カラム名: 値)」とすることで、その値を持ったデータをデータベースから取得することができる。今回は↓↓↓
post = Post.find_by(id:3)
投稿詳細ページを作成
ルーティング・アクション・ビューの思考が必要。
投稿詳細ページのURLに表示したい投稿のidを入れる必要がある。
そしてそのidを持つ投稿データを表示する。①投稿詳細ページのルーティング
・showアクションを作る
・URLにidを含める
→ルーティングのURLの部分に「:」を用いて"posts/:id"と指定して
「posts/1」「posts/2」でもshowアクションにいくようになる。②URLからidの取得
変数params
Controllerの場所で..↓↓↓
@id = params[:id]
③投稿詳細ページ完成
〜Controllerタブ〜
showアクションで変数@postを定義してidカラムの値が
params[:id]と等しい投稿をデータベースから取得して代入します。
@postをshow.html.erbで表示することで、
各URLに対応した投稿のデータが表示されるようにしましょう!④仕上げ
詳細画面へのリンクを作成する。
投稿一覧ページに、各投稿の詳細ページへのリンクを作成しましょう。
各投稿の内容の部分をクリックすると詳細ページに移動できるように、
link_to(post.content, "/posts/#{post.id}")
とします。新規投稿ページの作成
・新規投稿ページ準備
新規投稿ページは、「localhost:3000/posts/new」というURLでアクセスできるようにしましょう。
そのためにルーティング、アクション、ビューを追加しましょう。
アクションは、newアクションとしましょう。・入力フォームの作成
HTML & CSSのレッスンで学習した
<textarea>
タグや<input>
タグを用いることで入力フォームを作成することができます。
送信ボタンにはtype="submit"と、value="
投稿"を指定することに気をつけましょう。・投稿を保存する準備
・投稿を保存するまでの流れ
フォームの投稿ボタンを押すと、Rails側に投稿データが送信されます。
今回はcreateアクションを用意して、受け取った投稿データをデータベースに保存するようにします。
createアクションのURLは「/posts/create」
としましょう。
- 投稿日:2019-07-10T10:12:27+09:00
#Ruby / #Rails - FactoryBot でエイリアスを呼び出すみたいに、元の定義をコピー・継承して別名を作る
Ruby / # Rails-Copy and inherit the original definition to create an alias, just like calling an alias in FactoryBot
Factoryの中にFactoryを書くだけで良いらしい。こいつは使える!
factory :user do name { 'SomeName' } factory :alice do name { 'Alice' } end factory :bob do name { 'Bob' } end endFactoryBot.create :user FactoryBot.create :alice FactoryBot.create :bobOriginal by Github issue
- 投稿日:2019-07-10T10:00:40+09:00
nested attributes 使用時に毎回新規登録が行われてしまう
概要
accepts_nested_attributes_for を使って、とあるレコードの編集時に、関連レコードの新規作成/更新 を行うようにしたつもりだったのですが、なぜか常に新規登録扱いになってしまい、SQL発行時に Duplicate entry でエラーになる、という事象がおこっていました。
原因は大したことなかったのですが、これにハマったのが2度目だったので自戒のため記事に残しておくことにした次第です。よろしければお付き合いください。
環境
- Ruby 2.5.1
- Rails 5.2.2.1
結論
先に結論を書いておきます。
id
を permit メソッド内で許可していなかったから。 です。ハマるときに限って、意外と原因は大したことなかったりします。
舞台設定
順に説明していきます。まず今回の Model と Controller について記載します。
Model
Parent
が親で、Child
が関連モデルです。名前がいまいちですがご容赦くださいparent.rbclass Parent < ApplicationRecord has_one :child accepts_nested_attributes_for :child, allow_destroy: true endchild.rbclass Child < ApplicationRecord belongs_to :parent self.primary_key = :parent_id endController
問題の原因はここにあります。ここではあえて問題が再現する状態のままにしています。
child_controller.rbclass ChildController def update if @parent.update(child_params) # リダイレクト先は適当に書いたただの例なので気にしないでください redirect_to detail_page_path(@parent) else render :edit end end def child_params params.require(:parent).permit( # parent側もいろいろ指定がありますがここでは省略してます child_attributes: %i[title _destroy] ) end end問題の解消方法
前述コントローラの
child_params
メソッド内を下記のように変更すると解消します。結論で書いたとおりですが、id
を permit メソッド内で許可するキーに追加しています。- child_attributes: %i[title _destroy] + child_attributes: %i[id title _destroy]そもそもこの
id
って?まずはこちらをご覧ください。これは child_controller に対応したビューの一部です。このようなフォームを作成しています。
child.html.erb<%= form_with(model: @parent, local: true) do |form_parent| %> <!-- parent のフォームは省略 --> <%= form_parent.fields_for :child, @parent.child.build do |form_child|%> <%= form_child.text_field :title, placeholder: 'なんか入力してくれ' %> <%end%> <%end%>そして、実際に生成される child 分のフォームは以下のような html になります。
item.html<input placeholder="なんか入力してくれ" type="text" value="" name="parent[child_attributes][title]" id="parent_child_attributes_title"> <input type="hidden" value="2" name="parent[child_attributes][id]" id="parent_child_attributes_id">おや?
parent[child_attributes][id]
という、自分では作成した覚えのない input hidden のフォームが生成されています。これがid
パラメータの正体のようです。value 属性に入っているのはchilds
の主キーであるparent_id
の値でした。どうやらこの値を見て、新規登録か、既存レコードの更新かを区別しているようです。新規登録の際は value に何も入っていません。そのため、コントローラ側の処理で
id
を permit メソッド内で許可しておかないと、常に新規登録として扱われてしまう、ということです。ここで注意が必要なのが、主キーのカラム名は parent_id であるにも関わらず、input タグの name 属性には必ず id という名前が使用される という点です。DBのカラム名でそのまま考えると permit には
parent_id
を書いてしまいがちなんですが、主キーが送信されているパラメータの名前は常にid
という名前であるため間違えないように気をつけましょう。でないと僕の二の舞になります。こんなミスする人は僕だけかもしれませんが参考
余談
とはいえ、Rails はほんとにDB保存系の処理を書くのが楽ですね。そもそも最近の ORM ってみんなこんなかんじなんでしょうか?Laravel の ORM とかどうなんだろう、ということをふと考えました。
- 投稿日:2019-07-10T08:39:05+09:00
railsの基礎知識② ※自分メモ用
- 投稿日:2019-07-10T08:21:59+09:00
shields.ioを使って技術系アイコンを量産した
概要
shields.ioを用いて技術系アイコンを量産しました。
とりあえず完成したのがこちらです。
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
これでスキルマップを作ってみたらいい感じになりました。
shields.ioについて
GitHubのREADMEでよく見かけるアレです。
shields.ioはSVG形式のバッジサービスです。カスタムバッジを作る
特徴的な機能の1つとして
URLのパターンでカスタムバッジを作ることができます。https://img.shields.io/badge/${subject}-${status}-${color}.svgsubject : バッジの左側に入る文言
status : バッジの右側に入る文言
color : 色Color
以下のようなものが用意されています。
16進数形式で指定することも可能です。
カスタムスタイル
いくつかのスタイルが用意されています。
?style=plastic&logo=appveyor
?style=flat&logo=appveyor
?style=flat-square&logo=appveyor
?style=for-the-badge&logo=appveyor
?style=popout&logo=appveyor
?style=popout-square&logo=appveyor
?style=social&logo=appveyor
simpleicons
バッジではいくつかのアイコンが使えます。
これについてはsimpleiconsを参考になります。そして一例がこれです。
全部で数えたら648ありました。
おすすめアイコンを作った
おすすめしたいアイコンを作りました。
言語系
ライブラリ・フレームワーク
OS
ミドルウェア
エディタ・IDE
クラウド・他
参考
付録 : アイコンのURL
各アイコンのURLです。1
### 言語系 <img src="https://img.shields.io/badge/PHP-ccc.svg?logo=php&style=flat"> <img src="https://img.shields.io/badge/Javascript-276DC3.svg?logo=javascript&style=flat"> <img src="https://img.shields.io/badge/-TypeScript-007ACC.svg?logo=typescript&style=flat"> <img src="https://img.shields.io/badge/-Python-F9DC3E.svg?logo=python&style=flat"> <img src="https://img.shields.io/badge/-CSS3-1572B6.svg?logo=css3&style=flat"> <img src="https://img.shields.io/badge/-HTML5-333.svg?logo=html5&style=flat"> ### ライブラリ・フレームワーク <img src="https://img.shields.io/badge/-CakePHP-D3DC43.svg?logo=cakephp&style=flat"> <img src="https://img.shields.io/badge/-Rails-CC0000.svg?logo=rails&style=flat"> <img src="https://img.shields.io/badge/-Django-092E20.svg?logo=django&style=flat"> <img src="https://img.shields.io/badge/-Flask-000000.svg?logo=flask&style=flat"> <img src="https://img.shields.io/badge/-Bootstrap-563D7C.svg?logo=bootstrap&style=flat"> <img src="https://img.shields.io/badge/-React-555.svg?logo=react&style=flat"> <img src="https://img.shields.io/badge/-jQuery-0769AD.svg?logo=jquery&style=flat"> ### OS <img src="https://img.shields.io/badge/-Linux-6C6694.svg?logo=linux&style=flat"> <img src="https://img.shields.io/badge/-Ubuntu-6F52B5.svg?logo=ubuntu&style=flat"> <img src="https://img.shields.io/badge/-Windows-0078D6.svg?logo=windows&style=flat"> <img src="https://img.shields.io/badge/-RedHat-EE0000.svg?logo=red-hat&style=flat"> <img src="https://img.shields.io/badge/-Debian-A81D33.svg?logo=debian&style=flat"> <img src="https://img.shields.io/badge/-Raspberry%20Pi-C51A4A.svg?logo=raspberry-pi&style=flat"> <img src="https://img.shields.io/badge/-Arch%20Linux-EEE.svg?logo=arch-linux&style=flat"> ### ミドルウェア <img src="https://img.shields.io/badge/-Apache-D22128.svg?logo=apache&style=flat"> <img src="https://img.shields.io/badge/-Nginx-bfcfcf.svg?logo=nginx&style=flat"> <img src="https://img.shields.io/badge/-Oracle-f80000.svg?logo=oracle&style=flat"> <img src="https://img.shields.io/badge/-Redis-D82C20.svg?logo=redis&style=flat"> <img src="https://img.shields.io/badge/-Elasticsearch-005571.svg?logo=elasticsearch&style=flat"> <img src="https://img.shields.io/badge/-PostgreSQL-336791.svg?logo=postgresql&style=flat"> ### エディタ・IDE <img src="https://img.shields.io/badge/-Visual%20Studio%20Code-007ACC.svg?logo=visual-studio-code&style=flat"> <img src="https://img.shields.io/badge/-Vim-019733.svg?logo=vim&style=flat"> <img src="https://img.shields.io/badge/-Emacs-EEE.svg?logo=spacemacs&style=flat"> <img src="https://img.shields.io/badge/-Atom-66595C.svg?logo=atom&style=flat"> <img src="https://img.shields.io/badge/-Xcode-EEE.svg?logo=xcode&style=flat"> <img src="https://img.shields.io/badge/-intellij%20IDEA-000.svg?logo=intellij-idea&style=flat"> ### クラウド・他 <img src="https://img.shields.io/badge/-Amazon%20AWS-232F3E.svg?logo=amazon-aws&style=flat"> <img src="https://img.shields.io/badge/-Google%20Cloud-EEE.svg?logo=google-cloud&style=flat"> <img src="https://img.shields.io/badge/-Ansible-EE0000.svg?logo=ansible&style=flat"> <img src="https://img.shields.io/badge/-GitHub-181717.svg?logo=github&style=flat"> <img src="https://img.shields.io/badge/-Docker-EEE.svg?logo=docker&style=flat">
- 投稿日:2019-07-10T02:28:20+09:00
【Rails】Slimで入れ子になっている要素の親タグのみを分岐させる
Slimで、入れ子になっている子タグはそのままで、親タグのみ切り替えたいケースの書き方でハマったのでメモ。
具体的にはこんな感じのHTMLを出力したいときです。
求めるHTML<div class="User__list"> <!-- 選択中ユーザの場合、親タグをaタグではなくdivタグにしたい --> <div class="User__listSection--selected"> <div>[ユーザ名]</div> <div>[メールアドレス]</div> </div> <a class="User__listSection"> <!-- hrefは割愛 --> <div>[ユーザ名]</div> <div>[メールアドレス]</div> </a> <a class="User__listSection"> <div>[ユーザ名]</div> <div>[メールアドレス]</div> </a> ... </div>ダメな例
直感的にはこう書きたいところですが、slimには
end
が無いのでこれだとエラーになってしまいます。slim.User__list - users.each do |user| - if current_user == user .User__listSection--selected - else a.User__listSection - end / slimに end は無いのでエラー! div #{user.name} div #{user.email}実現できるけど微妙な例
一番素朴にやるとこうなると思います。
slim.User__list - users.each do |user| - if current_user == user / 選択中ユーザの場合、親タグをaタグではなくdivタグにする .User__listSection--selected div #{user.name} div #{user.email} - else a.User__listSection div #{user.name} div #{user.email}これは入れ子のタグを2回書いていて冗長なのであまり好ましくないですね。メンテナンス性も極めて悪いです。
動的タグを使ってちょっぴりスマートに書いた例
動的タグを使うと入れ子のタグは一度だけ書けば済むようになります。
slimruby: def user_list_section_tag(current_user, user) if current_user == user # 選択中ユーザの場合、親タグをaタグではなくdivタグにする { tag: 'div', class: 'User__listSection--selected' } else { tag: 'a', class: 'User__listSection' } end end .User__list - users.each do |user| *user_list_section_tag(current_user, user) div #{user.name} div #{user.email}複雑な分岐がある場合は動的タグを使うと良さそうですが、slimの中に急にrubyが出てくるのはちょっと気持ち悪い気がします。
content_tagを使って書いた例
content_tagでタグを生成するようにすれば、slim内にrubyを書かずに済みます。
slim.User__list - users.each do |user| - user_list_section_attrs = current_user == user \ ? { class: "User__listSection--selected" } \ : { class: "User__listSection" } / 選択中ユーザの場合、親タグをaタグではなくdivタグにする = content_tag(current_user == user ? :div : :a, '', user_list_section_attrs) div #{user.name} div #{user.email}
content_tag
を使えば確かにRubyを書かずに済みますが、current_user == user
が2回出てきたりして、むしろこっちの方が分かりづらいのでは?という気もします。
が、純粋にslimだけで書けるのでこちらの方が僕は良いと感じています。もっとスマートな方法があればどなたか教えて欲しいです!
![]()
追記:tagを使ってもっとスマートに書いた例
@eRy-sk さんに コメント でより良い書き方を教えていただきました!ありがとうございます!
tag に
send
で生成したいタグ名を分岐して渡します。slim.User__list - users.each do |user| - selected = current_user == user / 選択中ユーザの場合、親タグをaタグではなくdivタグにする = tag.send(selected ? 'div' : 'a', class: "User__listSection#{'--selected' if selected}") div = user.name div = user.email
content_tag
だと第二引数が悲しいことになりますし、このtag
を使う書き方が良さそうですね!さらに追記: content_tagでもっとスマートに書いた例
@scivola さんに コメント でもっとスマートな書き方を教えていただきました!ありがとうございます!!!
content_tag
に渡す引数として、タグ名も含めた配列を分岐して定義しておいて、それを渡すようにします。slim.User__list - users.each do |user| / 選択中ユーザの場合、親タグをaタグではなくdivタグにする - if current_user == user - args = [:div, class: "User__listSection--selected"] - else - args = [:a, class: "User__listSection"] = content_tag(*args) div = user.name div = user.email
send
を使わなくてよくなりますし、これが現状一番スマートな書き方、というところでしょうか。
- 投稿日:2019-07-10T01:03:08+09:00
railsのcontrollerからjavascriptに対して変数を渡す
About
railsからjavascriptに対して変数を渡す方法の一つについて記載しています。
html.erbファイル内にscriptタグでjavascriptを書いた場合に変数を渡せる方法です。Environment
この記事ではmacbook(unix)にインストールしたruby 2.5.1p57, Rails 5.2.3を使用しています。
変数の渡し方
controller内での変数の定義
まずは変数をcontroller内で定義します。
今回は配列を渡してみます。sleeps_controller.rbclass UsersController < ApplicationController def show @user = User.find(params[:id]) @sleeps = @user.sleeps.order('date DESC').includes(:user).limit(14).reverse end endhtml.erbで変数を受け取る
ここからは力技です。参考までにamchartsのスクリプトを拝借しています。
他に良い方法があると思いますので、最終手段くらいに思っていただければと思います。
また、良い方法がある方、コメントいただけると幸いです。show.html.erb<!-- Chart code --> <script> //略 // Add data var sleepings = '<%= @sleeps %>' // 以下略 </script>この様にすることで、javascriptの変数として、文字列を渡すことができます。
ただし、ここで注意しなくてはいけないのが、あくまで javascript側には文字列が渡されるだけ、ということです。そのため、以下の様に文字列を分解して、配列に変換しています。
文字列の[]をそれぞれ置換の要領で削除し、カンマでsplitし、配列化します。show.html.erb<!-- Chart code --> <script> //略 // Add data var sleepings = '<%= @sleeps %>'.replace(/\[/g, "").replace(/\]/g, "").split(','); // 以下略 </script>これでjavascriptにrailsのcontrollerから値を渡す事ができます。
...ゴリ押し感が否めないですが。最後に
ここまでゴリ押し感が強いものを共有するべきか悩みましたが、同じ様な悩みを抱えている方が少しでもいらっしゃれば、その方の助けになるかもと思い書きました。
さらに良い方法がありましたら、是非教えてください!筆者について
TECH::EXPERTにて4月よりruby, railsを学習している未経験エンジニアです。
記載内容に不備・不足があればご指摘いただけると幸いです。
至らぬ点ばかりですので、改善点がありましたらどんどんご指摘下さい!