- 投稿日:2019-10-09T23:56:45+09:00
【Rails/javascript(jQuery)】非同期での投稿削除機能
前回、編集機能の非同期化について記載させていただきましたが、今回は削除機能の非同期化について記事を書かせていただきます。
Deleteボタンを押すと、削除するかどうかの確認のアラートが出て、さらにアラートのOKボタンを押すと、きちんと削除処理がされていることが確認できますね。(正確にはこの動画だとちゃんと非同期になっているかわからないと思いますが、、)
削除処理の非同期化については、編集処理の非同期化に比べると、記述量も少なく、HTMLを入れ込む必要もないので楽でしたが、いくつか個人的にポイントだと思った箇所がありましたので記載します。
<削除機能実装におけるポイント>
①削除機能の場合、jbilderのファイルやコントローラへのjson.formatの記載は不要
②削除ボタンを押した際のアラートをどのようなビューにするか①については、当たり前といえば当たり前ですが、これまでの非同期化では、jbuilderとjson.formatをセットで使用していたので、自分は勢いでふたつとも作成してしまいました、、。
ただ、冷静に考えれば、削除処理の場合、動的な情報が入ったHTMLを新たに作成するわけではありませんし、DBから返してもらうデータはないのでいずれも必要ありませんね。
また、削除処理については、基本的に警告表示は必要だと思いますが、アラートをどのようなビューにするのかによってサイトの印象が変わってしまうので、今回は一番簡単なalertメソッドをそのまま使用しましたが、サイトの印象を重視するなら非同期でHTMLを作成するのもありかもしれません。ということで、以下コードを記載しますので、皆さまの何かのお役に立てば幸いです。
blog_destroy.js$(function() { $(document).on("click", ".delete_id", function (e) { e.preventDefault(); var deleteMessage = confirm('削除してよろしいでしょうか?'); if(deleteMessage == true) { var blog_element = $(this).parents('.content'); var blog_id = blog_element.attr("data-blog-id"); var url = location.href + "/" + blog_id; $.ajax({ url: url, type: "POST", data: {'id': blog_id, '_method': 'DELETE'} , dataType: 'json' }) .done(function(data) { blog_element.remove(); }) .fail(function() { alert('blog destroy error'); }) } }); });index.html.haml= render partial: 'devise/shared/header' .contents -@blogs.each do|blog| .content{"data-blog-id": "#{blog.id}"} .content__messages .content__message .content__message__box{"data-edit-id": "#{blog.id}"} - if blog.content.present? %p.lower-message__content = blog.content .content__message__info %p.message__upper-info__talker ユーザ: = blog.user.name %p.message__upper-info__date 投稿日時: = blog.created_at.strftime("%Y/%m/%d %H:%M") .content__message__edit-and-delete-btn %p.edit_id Edit %p.delete_id Delete .pict =image_tag blog.image.url, class: 'pict__img' if blog.image.present? = render partial: 'devise/shared/footer'
- 投稿日:2019-10-09T23:52:45+09:00
【50日目】コメントの削除機能、多対多のアソシエーションの設定
コメントの削除機能
destroyアクションの作成
コメントコントローラーにdestroyアクションを記載していきます。
comments_controller.rbdef destroy comment = Comment.find(params[:id]) comment.delete redirect_to comment.board, flash: {notice: 'コメントが削除されました' } endコメント削除ボタンの作成
コントローラーでアクションを定義したら、viewを作成します。
link_toの第二引数に渡すパスを調べるために、http://localhost:3000/rails/info/routesを確認しますと、
deleteアクションのパスはcomment_pathとなっています。
よって下記のようにリンクを作成します。_comments.html.erb<span><%= link_to '削除', comment, method: :delete, data: { confirm: '削除してもよろしいでしょうか?'} %></span> # 「link_to 'リンク名', リンク先へのURL又はパス, method: :メソッド名」で指定したメソッドの指定したパスに飛べる'リンク'を作成します。 # methodオプションを指定しない場合、第二引数のパスはGETメソッドのものを参照します。 # data-confirm属性を設定すると、リンクを踏んだ際に確認のダイアログボックスを表示させます。編集機能にもエラーメッセージを表示する。
まず前提として、updateアクションには下記のとおりフィルタリングされています
boards_controller.rbbefore_action :set_target_board, only: %i[show edit update destroy] # 中略 private def set_target_board @board = Board.find(params[:id]) endこれによって、@boardには該当のidのパラメータが渡されております。
その上でupdateアクションを下記のようにします。
boards_controller.rbdef update if @board.update(board_params) flash[:notice] = "「#{@board.title}」の掲示板を編集しました。" redirect_to @board else redirect_to edit_board_path, flash: { board: @board, error_messages: @board.errors.full_messages } end endこれによって、パラメータが保存できた場合は編集したことを示すメッセージが表示されて、掲示板のshowにリダイレクトします。
バリデーションエラーでboardが保存できなかった場合は、編集画面にリダイレクトしてエラーメッセージのリストを表示します。
又この時、リダイレクト後も掲示板のフォームには編集時に入力したパラメータは保持されます。多対多のリレーションの考え方
例えば掲示板にタグをつけることを考えます。
ここでは簡略化するため、各テーブルはidとnameのカラムのみを持ちます。boardsテーブル
id name 1 1日目 2 2日目 3 3日目 tagsテーブル
id name 1 ruby 2 SQL 3 初心者 このとき、例えば
1日目はruby, 初心者
2日目はSQL
3日目はruby, SQL, 初心者
とタグ付けしたかったりした場合、この関係を表そうとすると下記のようになります。
id board tag tag tag 1 1日目 ruby 初心者 2 2日目 SQL 3 3日目 ruby SQL 初心者 でもこれではカラムの数が事前に定められない他、カラムに空白が生まれてしまいます。
そこで「中間テーブル」を用いて、各id同士を繋げて表します。
board_id tag_id 1 1 1 3 2 2 3 1 3 2 3 3 このように表現することで、例えば
board_id = 1 である「1日目」には、
tag_id = 1 である「ruby」と
tag_id = 2 である「初心者」がタグづけされていることがわかります。では以下でこのアソシエーションをどのように実装するかを見ていきます。
多対多アソシエーションの実装
まず最初に中間テーブルとtagsテーブルのモデルを作成します。
テーブルの作成
tagsテーブル
docker-compose exec web bundle exec rails g model tag name:string中間テーブル
docker-compose exec web bundle exec rails g model board_tag_relation board:references tag:referencestagがnullであることを
db/migrate/xxxxxx_create_tags.rbt.string :name, null: false書き換えたら、マイグレーションを実行します。
docker-compose exec web bundle exec rake db:migrateモデルのアソシエーションの設定
中間モデルの確認
中間モデルは最初からboardモデルとtagモデルにbelongs_toによってassociateされています。
これによって中間モデルはboard_idとtag_idをカラムに持つことになり、上記で示したような2つのidを結びつけることが可能になります。app/model/board_tag_relations.rbclass BoardTagRelation < ApplicationRecord belongs_to :board belongs_to :tag endtagモデルの修正
タグから掲示板を関連づける設定をする。
tag.rbclass Tag < ApplicationRecord has_many :board_tag_relations has_many :boards, through: :board_tag_relations # throughオプションによって中間テーブルを経由して複数のboardを持つことを示している。 endboardsモデルの修正
掲示板からタグを関連づける設定をする。
board.rbclass Board < ApplicationRecord has_many :comments has_many :tag_board_relations has_many :tag, through: :tag_board_relations validates :name, presence: true, length: { maximum: 10 } validates :title, presence: true, length: { maximum: 30 } validates :body, presence: true, length: { maximum: 1000 } end次回はアソシエーションのdependentオプションを作成していきます。
- 投稿日:2019-10-09T21:34:20+09:00
A server is already running の対処法
Railsでアプリを作成中にa server is already runningが出てlocalサーバが起動しなくなってしまった。
already runningってことはサーバが閉じられてないってこと?
調べてみると
Railsプロジェクト/tmp/pids/server.pidのserver.pidを削除して直るらしい。server.pidはサーバを起動毎に作成されているようなのでサーバが閉じている時にserver.pidファイルがpidsファイルの中にあるのがそもそもおかしいみたい。
server.pidを削除して新たにサーバを立ち上げ直し。
server.pidファイルが新たに作られる。
解決!
- 投稿日:2019-10-09T21:06:47+09:00
csv
書き込み
- headerのセット
- パスのセット
require 'csv' peoples = [ ['alice', 14, 'femal'], ['alice', 15, 'femal'], ['alice', 16, 'femal'], ] headers = ["名前", "年齢", "性別"] file_path = "./test.csv" CSV.open(file_path, 'w', headers: headers ) do |row| row << headers peoples.each do |pe| row << pe end end読み込み
- headers trueを適応
- 要素を出力する
require 'csv' file_path = "./test.csv" CSV.foreach(file_path, headers: true) do |row| p row end CSV.foreach(file_path, headers: true) do |row| p row["名前"] p row["年齢"] p row["性別"] end
- 投稿日:2019-10-09T18:24:49+09:00
Railsチュートリアル 第5章<復習>
第5章の復習メモです。
個人的に重要と思ったことを書きます。
調べたことや、知っていたことも含めて書きます。Bootstrap
Twitterが作成したフロントエンドのフレームワーク。
デザインが予め用意されているので、いい感じのデザインを素早く実装できる。railsで使うには、Gemfileに
bootstrap-sass
を追加する。source 'https://rubygems.org' gem 'rails', '5.1.6' gem 'bootstrap-sass', '3.3.7' # ←追加 . . .追加後、
$ bundle install
を忘れずに実行する。また、Bootstrapを読み込ませるため、
CSSファイルには以下を追記する。~.scss@import "bootstrap-sprockets"; @import "bootstrap";補足
railsでは、generate controller
した時、
ビューと一緒に、対応するCSSファイルが作られる。
今回は、簡略化のため、全てのCSSを一つにまとめた物として、
app/assets/stylesheets/custom.scss
を作成した。
(カスタムCSSというらしい)部分テンプレート
ビューファイルのコードの冗長化を防ぐため、
共通する部分を、別ファイルに記載できる。
これを部分テンプレートと呼ぶ。ファイル名は、
app/views/layouts/_<任意の名前>.html.erb
の形式にする必要がある。呼び出す際は、renderメソッドを用いて、
<%= render 'layouts/<任意の名前>' %>
と記載する。<例>
部分テンプレートapp/views/layouts/_shim.html.erb<!--[if lt IE 9]> <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js"> </script> <![endif]-->呼び出す側
app/views/layouts/application.html.erb<!DOCTYPE html> <html> <head> <title><%= full_title(yield(:title)) %></title> <%= csrf_meta_tags %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <%= render 'layouts/shim' %> # ←ここで呼び出している </head> ・ ・以下も参考にさせていただきました。
https://qiita.com/taca10/items/dd4a0eae6864e2bdbf3aアセットパイプライン、Sass
アセットパイプライン
以下を参考にさせていただき、学習しました。
https://qiita.com/hogehoge1234/items/9a94ebc93c5f937502cdSass
CSSの強化版(?)で、
- ネスト
- 変数の使用
ができるみたい。書き方等、詳細は省略。
リンクの貼り方
ビューファイルでリンクを貼る場合、link_toメソッドを使う。
<%= link_to "文字列", "URL" %>ルーティングの変更、名前付きルート
ルーティングの変更
generate controller
コマンドでコントローラ等を作成すると、
ルーティングが自動生成される。config/routes.rbRails.application.routes.draw do get 'static_pages/about' endこの場合、
ルート/static_pages
にGETリクエストが来ると、
static_pagesコントローラの、aboutアクションにルーティングされる。
即ち、コントローラ名とアクション名に対して、URLが固定されている。これを、以下のように書き換えることで、URLを自由に決めることができる。
config/routes.rbRails.application.routes.draw do get '/about', to: 'static_pages#about' end上の例では、
ルート/about
にGETリクエストが来ると、
static_pagesコントローラの、aboutアクションにルーティングされる。名前付きルート
railsでは、
config/routes.rb
に記載したURLに対して、
ルート以降の相対パス、ルートを含めた絶対パスを表す変数が
それぞれ用意され、格納される。
<例>config/routes.rbRails.application.routes.draw do get 'static_pages/about' endの場合
- 相対パス('/static_pages/about') : 変数
static_pages_about_path
- 絶対パス('http://www.~.com/static_pages/about') : 変数
static_pages_about_url
ルーティングを変更すると、変数名も更新される。
<例>config/routes.rbRails.application.routes.draw do get '/about', to: 'static_pages#about' endの場合
- 相対パス('/about') : 変数
about_path
- 絶対パス('http://www.~.com/about') : 変数
about_url
統合テスト
テストについては、以下を参考にさせていただき、学習中です。
https://qiita.com/duka/items/2d724ea2226984cb544f復習記事を書いてみると、理解不足がとても実感できます・・・
- 投稿日:2019-10-09T17:57:11+09:00
Ruby インスタンス変数 の 値 を 順に出力する
目的
- インスタンス変数を出力する方法を知る。
書き方の例
- クラス
A
にはインスタンス変数b
とc
が定義されるものとする。- インスタンス変数
c
の値を順に出力したい。- インスタンス
1
と2
の2個作成するものとする。- クラス
A
から生成したインスタンスのインスタンス変数b
とc
には任意の値が入っているものとする。- 下記に処理を記載する。
# クラスAを定義 class A # 変数string_1にインスタンス1の内容を格納 string_1 = A.new(b: "インスタンス変数bに格納される値", c: "インスタンス変数cに格納される値") # 変数string_2にインスタンス2の内容を格納 string_2 = B.new(b: "インスタンス変数bに格納される値", c: "インスタンス変数cに格納される値") # 変数stringsに変数string_1とstring_2の内容を配列として格納 strings = [string_1, string_2] # 変数stringsに配列状に格納された内容を一つづつ変数stringに格納 strings.each do |string| # 変数stringに格納された内容のインスタンス変数cのみを出力 puts string.c # each文を閉じる end # クラス定義を閉じる endより具体的な例
- クラス
Menu
にはインスタンス変数content
とprice
が定義されるものとする。- インスタンス変数
content
の値を順に出力したい。- インスタンス
1
と2
の2個作成するものとする。- クラス
Menu
から生成したインスタンス1
のインスタンス変数content
には、文字列「お肉100g」が格納され、インスタンス変数price
には文字列「100円」を格納する。- クラス
Menu
から生成したインスタンス2
のインスタンス変数content
には、文字列「お魚1尾」が格納され、インスタンス変数price
には文字列「150円」を格納する。- 下記に処理を記載する。
# クラスMenuを定義 class Menu # 変数menu_1にインスタンス1の内容を格納 menu_1 = Menu.new(content: "お肉100g", price: "100円") # 変数menu_2にインスタンス2の内容を格納 menu_2 = Menu.new(content: "お魚一尾", price: "150円") # 変数menusに変数menu_1とmenu_2の内容を配列として格納 menus = [menu_1, menu_2] # 変数menusに配列状に格納された内容を一つづつ変数menuに格納 menus.each do |menu| # 変数menuに格納された内容のインスタンス変数cのみを出力 puts menu.content # each文を閉じる end # クラス定義を閉じる end
- 下記に前述の処理のコメント無しバージョンを記載する。
class Menu menu_1 = Menu.new(content: "お肉100g", price: "100円") menu_2 = Menu.new(content: "お魚一尾", price: "150円") menus = [menu_1, menu_2] menus.each do |menu| puts menu.content end end
- 投稿日:2019-10-09T17:24:30+09:00
Rubyにおけるプリントデバッグのすゝめ
※ 別に勧めてない ※
皆さん!プリントデバッグ使ってますか!使ってないですよね、どうせ皆さんデバッガでかっこよく問題解決しているんでしょう。だけれども、私はデバッガを使いこなすことができない程度の能力しか持っていないので、99.99%ぐらいの問題はプリントデバッグで地道に値をトレースし、頑張って解決しています。
そんな私のTipsです。
識別子付きで出力
ただ単に変数を
p
で出力するようなケースだと、次のように出力したい事がありますね。p "hoge -> #{hoge}"ただこれは入力が面倒。自分がパット見で区別できればいいので次のようにします。
p [:hoge, hoge]こうすると、
[:hoge, 1]
のように出力されるので都合がいいです。区切り線の表示
いろんな値を出力するときには欠かせない区切り線。
単純に出力する場合は次のようにするかもしれませんp '**************************************' p hoge p '**************************************'だけどこれはちょっと入力が面倒臭い。なので、次のように書きます
p ?**88
?
の累乗に見えますが、これは*
を88個出力しています。rubyの文字リテラルってやつを利用しています。
区切り線にはなんの文字を使ってもいいので、?-*100
とかして、-
を100個出力とかでもいいんでしょうが、コードの見た目が?**88
のほうがかっこいい!のでほかの文字は使いません。メソッドチェーンの途中を出力
この方法が必要になるケースはかなり少ないんですが・・。
たとえば意味のない例ですが次の様なメソッドのなげー連鎖がある場合。b = a.map(&:sono1).map(&:sono2)この
sono1
の直後の状態を出力したい時があるんじゃないでしょうか。
tappみたいなgemを使っているならそれでいいのですが、それを使わない環境で手軽にテストしたい場合は、次のようにするでしょうか。_a = a.map(&:sono1) p _a b = _a.map(&:sono2)でもでも、変数を増やしたり、メソッドチェーンをぶった切って途中で
p
を使ったり、書き換え量が多くて副作用がうっかり発生するかもしれない。
なので、次のように出力はチェーンに組み込みます。b = a.map(&:sono1).tap(&method(:p)).map(&:sono2) # もしくは ↓ b = a.map(&:sono1).tap{|_a|p _a}.map(&:sono2)どちらかは、好みですね。メソッドチェーンをぶった切って一時的な変数に格納する方法よりは副作用が少ない方法だと思ってます。
- 投稿日:2019-10-09T16:26:13+09:00
json ruby 実践
require 'net/http' #標準ライブラリの呼び出し require 'uri' require "json" #jsonを使うためのライブラリ u = URI.parse('http://zipcloud.ibsnet.co.jp/api/search?zipcode=6695221') res = Net::HTTP.get(URI.parse('http://zipcloud.ibsnet.co.jp/api/search?zipcode=6695221')) status = JSON.parse(res)["status"] results = JSON.parse(res)["results"] p "status:#{status}" p results参考記事
- 投稿日:2019-10-09T15:46:53+09:00
Ruby のメソッド定義で引数が「*」だけの場合
OSSライブラリのドキュメントを見ていると以下のようなコードがありました。
def initialize(*) super # 以下、何らかのコード endこの
*
が文法的にどういう意味なのか気になったので調べました。結論
任意の引数を受け取るが、特にコード内では参照しない(無視する)という意味になるようです。
例
class Foo def bar(*) "bar" end def baz "baz" end end Foo.new.bar("foo", 1, [2]) # => エラーにならない Foo.new.baz("foo", 1, [2]) # => ArgumentError が発生メソッド内で
super
を呼び出すと、親クラスのメソッドに指定された引数をそのまま渡します。
指定された引数の個数が、親クラスのメソッド定義の引数の個数と異なる場合、ArgumentError
が発生します。class Parent def hello(name) "Hello #{name}!" end end class Child < Parent def hello(*) super end end Child.new.hello("World") # => "Hello World!" Child.new.hello # => ArgumentError Child.new.hello(1, 2) # => ArgumentError参考
リファレンスマニュアルには以下のように記載されています。
https://docs.ruby-lang.org/ja/latest/doc/spec=2fdef.html#methoddef bar(x, *) # 残りの引数を単に無視したいとき puts "#{x}" end bar(1) #=> 1 bar(1, 2) #=> 1 bar(1, 2, 3) #=> 1
- 投稿日:2019-10-09T14:36:12+09:00
Rubyで[ ](カギ括弧)メソッドを定義する
Array型やHash型などのインスタンス変数の要素を
[添字]
の記法で取得するためには[]メソッドを定義します。以下のようにメソッド名を
[]
で定義すると、添字に指定した値が引数として渡されます。def [](引数名) end使用例
class ConfigModel attr_reader :config def initialize @config = {host: "127.0.0.1", port: 3000} end def [](key) @config[key] end end config = ConfigModel.new puts config[:host] puts config[:port]出力結果
127.0.0.1 3000
- 投稿日:2019-10-09T14:17:27+09:00
macOSをCatalinaにアップデートしたらdocker-syncが動かなくなって調べたこと
まえおき
Xcodeを過信してたらRubyから苦情もらった(docker-sync動かないorz) - https://qiita.com/CeMoReOn/items/9abb837727af5594fc0f
っていうタイムリーな記事があったので、これは rbenvとかhomebrew経由でRuby入れないとダメなのかなー・・・と思っていたけど、
Mac付属のRubyでも一応動いたのでメモっとく。ちなみに、次のMacバージョンからそもそもRubyが付属しなくなるという噂 もあるので、この記事の賞味期限はきっとかなり短いだろう。
OSをアップデートした直後
$ docker-sync-stack start -bash: /usr/local/bin/docker-sync-stack: /System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/bin/ruby: bad interpreter: No such file or directory前評判のとおり、こんなかんじのエラーは出る。
$ which ruby /usr/bin/ruby $ ls -l /usr/bin/ruby -r-xr-xr-x 1 root wheel 36624 9 30 05:28 /usr/bin/rubyRubyのバイナリ自体はある。
$ ls /System/Library/Frameworks/Ruby.framework/ Resources/ Ruby Versions/ $ ls /System/Library/Frameworks/Ruby.framework/Versions/2.6/ Resources/ Ruby _CodeSignature/ usr/このあたりで、「あー、Ruby 2.3じゃなくなったのね」と察しがつく。
docker-syncを入れ直す
$ sudo gem uninstall docker-sync $ sudo gem install docker-sync$ docker-sync-stack start mkmf.rb can't find header files for ruby at /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/include/ruby.h You might have to install separate package for the ruby development environment, ruby-dev or ruby-devel for example.エラーの種類が変わった。
エラー文言でぐぐると
xcode-select --install
とかxcodebuild ...
みたいなコマンド叩くといいみたいなのが出てくるが、環境によっては多分それでは無理っぽい。(自分の場合はうまくいかなかった)Xcode 11にする
これは実際に関係あるのかどうかわからないが、
とりあえずxcode-select --install
→xcodebuild ...
を叩くだけではXcode11にはならない。なので、App StoreからXcode 11を落としてくる。
ついでに、AppleのDeveloper向けサイトからコマンドラインツールも落としてくる。
11になったことを確認。
そもそものエラーの出どころを見てみる
mkmf.rb can't find header files for ruby at /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/include/ruby.h You might have to install separate package for the ruby development environment, ruby-dev or ruby-devel for example.これはそもそもdocker-syncに関係のないエラーだ。ということで、エラーの出どころを見てみる。
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/mkmf.rbtopdir = File.dirname(File.dirname(__FILE__)) path = File.expand_path($0) until (dir = File.dirname(path)) == path if File.identical?(dir, topdir) $extmk = true if %r"\A(?:ext|enc|tool|test)\z" =~ File.basename(path) break end path = dir end $extmk ||= false if not $extmk and File.exist?(($hdrdir = RbConfig::CONFIG["rubyhdrdir"]) + "/ruby/ruby.h") $topdir = $hdrdir $top_srcdir = $hdrdir $arch_hdrdir = RbConfig::CONFIG["rubyarchhdrdir"] elsif File.exist?(($hdrdir = ($top_srcdir ||= topdir) + "/include") + "/ruby.h") $topdir ||= RbConfig::CONFIG["topdir"] $arch_hdrdir = "$(extout)/include/$(arch)" else abort <<MESSAGE mkmf.rb can't find header files for ruby at #{$hdrdir}/ruby.h You might have to install separate package for the ruby development environment, ruby-dev or ruby-devel for example. MESSAGE end
RbConfig::CONFIG["rubyarchhdrdir"]
RbConfig::CONFIG["topdir"]
あたりがキモのようだ。このキーワードでぐぐると
https://www.programqa.com/question/20559255/
こんなページが出てきた。
$ ruby -rrbconfig -e 'puts RbConfig::CONFIG["rubyhdrdir"]' /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0 $ ls /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0 ruby ruby.h universal-darwin19お、ちゃんと
ruby.h
あるじゃん?ってことはいけるんじゃね?
あらためてdocker-syncしてみる
$ docker-sync start ok Starting unison for sync panel-workspace-syncあ、動いたw
まとめ
- docker-syncをインストールしなおす
- Xcode 11 + コマンドラインツール 11にする
で解決したのかなぁ・・・
(どこが解決ポイントだったのかは自分でもわかっていない)
- 投稿日:2019-10-09T13:50:49+09:00
40手前、気分は高校1年生。プログラミング(Ruby on Rails)を3ヶ月勉強して一口馬主とかPOGで少し役立ちそうな馬の検索WEBサービス(webアプリ)を作ってみた!
粛々と窓際社員を驀進中の小生であるが、ボケーーーっと平日を過ごし、
ただただ週末の競馬を楽しみに生きる人生。これでいい、とも思うし、これではダメだ。。とも思う。
ただギャンブルとは別のスパイスが欲しいという欲求と、プログラミングをちょっとやってみたい、という秘めた思いを10年越しに実現することにした。
窓際社員であることも、学習を進める上で大いに役立った。
だって・・・・仕事ないから・・・・・。ネットサーフィン感覚で、勉強できるのですもの。。。。。
ついでに毎日腕立てと腹筋を100回以上やることにした。
◆ 作ったサービス
うまBANG!
www.umabang.com◆ どんなサービス?
血統表に馬名を入れると該当する馬を検索できるサービスです。
とりあえず今は2013-2015年産世代のデータを検索対象にしています。こんな感じで検索すると
こんな感じで結果がわかる
◇ 動機というか一口馬主をやっていてのペイン
静止画、動画、血統、クラブ、厩舎、などなどなどなど一口馬主の馬選びは様々な要素を考慮する必要があり、
人それぞれ優位に思っていることは違う。
例えば小生は元々は静止画から判断していたが、最近だと動画、そして血統も考慮するようになった。
そう、続ければ続けるほど、何やら様々なものが見えすぎて、シンプルに馬選びを出来なってきているのだ。そうすると従来は出資しなかった馬に出資したり、どんどん深みにはまっていく。
そこに納得感があれば良いが、必ずしもそうではない。謎に出資馬を増やしてしまいそうになる誘惑に駆られることも多いが、めちゃくちゃ金持ちでない限り、台所事情はなかなか苦しくなっていく。
小生然り。ただ血統から絞れることも多く、さらにパズルのように様々な組み合わせを検証したくなる。
・スクリーンヒーローやキングカメハメハ牝馬は成績悪い?
・父 ディープインパクト 母父 stormcat は本当にニックス?
・では父父 サンデーサイレンス 母父 stormcat はどうなの?
・母父 orpen とか注目されているけど?(ポレンティア!)
・fastnetrock ってどうよ?(モーソンピーク!)
・母父 サンデーサイレンスを買っておけば良い簡単なお仕事です(ダイアトニック!アーモンドアイ!ブラストワンピース!)こんな気持ちを手軽に解決できたらな〜と思ったのがそもそもの動機。
確率的に期待値が低いことを明確にして、そもそも出資しない血統マイルールを今一度持ち直したいと考えている。◇ 一口馬主をやっていて、できれば出資馬に望むこと
重賞に出走して欲しい!できれば重賞で好走して欲しい!!!
一口馬主を数年やった小生が出資時に最も思うことである。当該週の重賞はメディアにも多く取り上げられ、様々な方が出資馬の名前を呼んでくれる。
なにものにも代え難い幸せ・・・。そこで、このサービスでは重賞出走歴のある馬のみで絞り込み検索できるようにした。
加えてなんとなく1000万以上稼いでくれると、最低限楽しませてくれる、ということも感じているので、
最低ラインとして獲得賞金1000万以上の馬が何頭マッチするのかも見られるようにした。
ノルマンディーであればこの辺りが損益分岐点の一つ基準になるだろう。◇ 改めますと・・・
・牡牝の成績差がわかる。
・重賞出走まで届く可能性をなんとなく調べられる。
・賞金1000万以上獲得する確率もなんとなくわかる。よろしければ遊んでみてください。もしご変なところがあればコメントをください。
うまBANG!
www.umabang.com今後これを使ってノルマンディーの馬を見てみようと考えている。
こっちのブログで。清純派 一口馬主ライフとパドック予想師!誠意の競馬日記と反省
http://paddock.hatenablog.com/◆ 番外
◇ 今後やりたいこと
対象の馬を増やす
検索時のサジェスト
並び替え
人気ランキングをちゃんとする
検索履歴の保持
サンデーサイレンスの 3x4 4x3 とか馬名と世代を指定して検索できるようにしたいなんかができればと思います。
◇ どんな勉強をしたか
WEBの講座をやりました。週2回メンターとのビデオMTGがあり、そこで褒めていただけるのでやりがいを持って進められました。
ひさしぶりに他の人から褒められる体験でした。
少しお値段は張りましたが、一口馬主のせいでお金の価値が暴落中なので、躊躇せず申し込めました。
◇ どれくらい勉強したのか
平均すると1日3-4時間程度を2.5ヶ月続けて、このうまBANG!に取り組みました。
◇ 一番辛かった時
スクールの環境が 開発環境 Cloud9 x MySQL 本番環境 Heroku x PostgreSQL だったので、いざ公開しようと思ったら動かなかったのが辛かったです。
さらに、Heroku を MySQL に変更しようとして失敗していた時は絶望に暮れました。◇ 今つらいこと
ギャグでAmazonアソシエイトとgoogleアドセンスに申し込んでみたのですが、審査で断れています。
一所懸命勉強して作ったのに。。。。。なんだろうこの疎外されている感じ。。。。理由もわからないし。。。。こういうことから JOKER が生まれるのだと思います。
- 投稿日:2019-10-09T12:44:36+09:00
テスト初心者がRSpecを学習するときにとまどったこと
前書き
私はRailsを学びはじめて1年に満たない初学者ですが、現在今まで避けてきたテストを学んでいます。
いろいろと手こずったので、私の経験が誰かの役に立てばと思いこの記事を書いています。つまづきポイント
何からはじめたら良いかわからない
RSpecどころかテストに触れるのもほぼ初めてだったため、どこからはじめればよいか全くわかりませんでした。書籍、レファレンス、Qiita記事等いろいろな情報を当たった結果、ご存知の方も多いと思いますが、@jnchitoさんの一連の記事が初学者には一番わかりやすかったです。
最初に上記に続く一覧の記事に目を通すと理解が進むと思います。
古い情報が役に立たない
これはプログラミング全般に言えることだと思いますが、改めて最新の情報を参考にすべきだと感じました。
Controller Specが非推奨となっていたり、RSpec3.7よりSystem Specが追加されているなど書きかたが全く異なることが多いのでなるべく新しい情報を参照すべきです。何をテストすればよいかわからない
これは簡単に論じられる問題ではないと思いますが、最初の学習としては、モデルのテストと何らかの機能のシステムテストを行うとまんべんなく基礎の基礎が学べて良いのかなと感じました。
最後に
今まで何となくテストめんどくさいなあと感じていたのですが、(おそらくRails Tutorialが原因)やってみると意外と面白かったです。
特にCapybaraでブラウザが自動操作されるのは見ていて興奮しました。
本当にまだ基本しかわかっていませんが、頑張って勉強を続けていきたいと思います。
- 投稿日:2019-10-09T12:16:49+09:00
Rails6 のちょい足しな新機能を試す92(config.disable_sandbox 編)
はじめに
Rails 6 に追加された新機能を試す第92段。 今回は、
config.disable_sandbox
編です。
Rails 6 では、rails console --sandbox
を実行したときに、エラーメッセージを表示して終了するオプションconfig.disable_sandbox
が追加されました。
本番環境などで、rails console --sandbox
したときにトランザクションログが大きくなりすぎて、メモリが不足してサービスがダウンしてしまうことを防ぐ目的で導入されたようです。Ruby 2.6.4, Rails 6.0.0 で確認しました。
$ rails --version Rails 6.0.0プロジェクトを作る
$ rails new rails_sandbox $ cd rails_sandboxconfig.disable_sandbox を設定する
今回は、
config/environments/development.rb
で設定します。config/environments/development.rbRails.application.configure do ... config.disable_sandbox = true endrails console を実行する
--sandbox
オプションつきで、rails console
を実行してみます。$ bin/rails c --sandbox Running via Spring preloader in process 48 Error: Unable to start console in sandbox mode as sandbox mode is disabled (config.disable_sandbox is true).エラーメッセージが表示されて実行できないことが確認できます。
試したソース
試したソースは以下にあります。
https://github.com/suketa/rails_sandbox/tree/try092_console_sandbox参考情報
- 投稿日:2019-10-09T11:20:23+09:00
【小学生でもわかる】クラスの概念「クラスはたい焼き」(オブジェクト指向)
オブジェクト指向におけるクラス
オブジェクト指向の言語に共通するクラスの概念について具体的な例えで解説
どんな人向けの記事?
ProgateでHTML/CSSなどのマークアップ言語から入って
「なんだプログラミングって簡単じゃん♪俺才能ある♪」
ってなった後、オブジェクト指向型言語に触れて...「...???...思ってたんと違う...」
ってなった人向けの記事
【本題】クラスは「たい焼き」
クラス = たい焼き機
どんな模様・形のたい焼きにするのか決めるのがクラス設計。
たくさんのたい焼き(たくさんのインスタンス)を作れるインスタンス = たい焼き
クラスを元にできたもの。
継承
たい焼き機をもとにして、タコ焼き機やベビーカステラ焼き機を作ること(クラスの継承)
たかがたい焼き機でも、どんな材質の鉄板を使うか、コンロで使うには厚みをどれくらいにしないといけないのかなども考えなければいけないので、一から作るより継承して作った方が速くて確実だよね。という話まとめ
クラス = たい焼き機
インスタンス = たい焼き
- 投稿日:2019-10-09T11:20:23+09:00
現在修正中【小学生でもわかる】クラスの概念「クラスはたい焼き」(オブジェクト指向)
オブジェクト指向におけるクラス
オブジェクト指向の言語に共通するクラスの概念について具体的な例えで解説
どんな人向けの記事?
ProgateでHTML/CSSなどのマークアップ言語から入って
「なんだプログラミングって簡単じゃん♪俺才能ある♪」
ってなった後、オブジェクト指向型言語に触れて...「...???...思ってたんと違う...」
ってなった人向けの記事
【本題】クラスは「たい焼き」
クラス = たい焼き機
どんな模様・形のたい焼きにするのか決めるのがクラス設計。
たくさんのたい焼き(たくさんのインスタンス)を作れるインスタンス = たい焼き
クラスを元にできたもの。
継承
たい焼き機をもとにして、タコ焼き機やベビーカステラ焼き機を作ること(クラスの継承)
たかがたい焼き機でも、どんな材質の鉄板を使うか、コンロで使うには厚みをどれくらいにしないといけないのかなども考えなければいけないので、一から作るより継承して作った方が速くて確実だよね。という話まとめ
クラス = たい焼き機
インスタンス = たい焼き
- 投稿日:2019-10-09T09:48:48+09:00
君はRailsの「Yay! You’re on Rails!」の画面がどこで記述されているか知っているか?
- 投稿日:2019-10-09T09:41:56+09:00
Railsのテスト環境でのいろいろなエラーでつらい
railsのテスト環境でやったときのいろいろなエラーの詰め合わせの記事です。
タイトルが抽象的ですみません。rails s -e test 2019-10-06 18:13:28 WARN Selenium [DEPRECATION] Selenium::WebDriver::Chrome#driver_path= is deprecated. Use Selenium::WebDriver::Chrome::Service#driver_path= instead. => Booting Puma => Rails 5.2.3 application starting in test => Run `rails server -h` for more startup options Puma starting in single mode... * Version 3.12.1 (ruby 2.6.3-p62), codename: Llamas in Pajamas * Min threads: 5, max threads: 5 * Environment: test * Listening on tcp://0.0.0.0:3000 Use Ctrl-C to stophttp://0.0.0.0:3000/
へアクセス。Puma caught this error: No route matches [GET] "/" (ActionController::RoutingError) # 以下、略こんな、エラがー起こる。
config/routes.rbroot 'rails/welcome#index'を追加する。
「Yay! You’re on Rails!」のおなじみの画面が出て安心する。ちなみにこのページのファイルはこのパスにあるようだ。
/Users/hoge/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-5.2.3/lib/rails/templates/rails/welcome/index.html.erbcurlで叩いてみる
curl localhost:3000/blogs/index/ Puma caught this error: PG::UndefinedTable: ERROR: relation "blogs" does not exist LINE 1: SELECT "blogs".* FROM "blogs" ^ : SELECT "blogs".* FROM "blogs" (ActiveRecord::StatementInvalid) # 以下、略。なんだかすごい。エラーが出ている。
落ち着いてみる。冒頭に
Puma caught this error: PG::UndefinedTable: ERROR: relation "blogs" does not exist
とある。
データベースがなんかおかしい?単に
rails s
だと正常に返ってくる。DBがないのか?
test用のDBを作成する。rails db:create RAILS_ENV=test 2019-10-06 17:55:03 WARN Selenium [DEPRECATION] Selenium::WebDriver::Chrome#driver_path= is deprecated. Use Selenium::WebDriver::Chrome::Service#driver_path= instead. Database 'todo_slim_test' already existsDBはあるようだ。
test用にmigrateしなくてはいけないのか?$ rails db:migrate RAILS_ENV=test 2019-10-06 17:55:36 WARN Selenium [DEPRECATION] Selenium::WebDriver::Chrome#driver_path= is deprecated. Use Selenium::WebDriver::Chrome::Service#driver_path= instead. == 20190818133341 CreateBlogs: migrating ====================================== -- create_table(:blogs) -> 0.0645s == 20190818133341 CreateBlogs: migrated (0.0646s) =============================ついでにseedsもやっておく。
$ rails db:seed RAILS_ENV=test 2019-10-06 17:55:50 WARN Selenium [DEPRECATION] Selenium::WebDriver::Chrome#driver_path= is deprecated. Use Selenium::WebDriver::Chrome::Service#driver_path= instead.再度やる。
$ rails s -e test 2019-10-06 17:55:58 WARN Selenium [DEPRECATION] Selenium::WebDriver::Chrome#driver_path= is deprecated. Use Selenium::WebDriver::Chrome::Service#driver_path= instead. => Booting Puma => Rails 5.2.3 application starting in test => Run `rails server -h` for more startup options Puma starting in single mode... * Version 3.12.1 (ruby 2.6.3-p62), codename: Llamas in Pajamas * Min threads: 5, max threads: 5 * Environment: test * Listening on tcp://0.0.0.0:3000 Use Ctrl-C to stop 2019-10-06 17:56:05 +0900: Rack app error handling request { GET /blogs/index } #<AbstractController::ActionNotFound: The action 'show' could not be found for BlogsController>なんだか、まだなにかしなくてはいけないようだ。
developではこんなことを言われないので、DBがおかしいのかと疑ってみる。
テスト環境のDBの状態を見に行く。rails db RAILS_ENV=test DEPRECATION WARNING: Passing the environment's name as a regular argument is deprecated and will be removed in the next Rails version. Please, use the -e option instead. (called from <top (required)> at /Users/hoge/product/ruby_sandbox/rails-blog-slim/bin/rails:9) config.eager_load is set to nil. Please update your config/environments/*.rb files accordingly: * development - set it to false * test - set it to false (unless you use a tool that preloads your test environment) * production - set it to true-eオプションつけてやってと言われた。
dbを初期化する。
migrateもする。rails db:migrate:reset rails db:migrate rails db -e testつないで、DBができていることを確認した。
$ curl localhost:3000/blogs/index [{"id":1,"title":"今日のできごと","article":"ごはんを食べて寝た","created_at":"2019-10-06T09:02:16.207Z","updated_at":"2019-10-06T09:02:16.207Z"}][値が返ってきた。
いろいろ試した結果、たぶんDBが良くなかったんだろうという結論。雑なポエム的なまとめ
test環境はdevelopと結構違ってつらい。
動きがおかしかったらDBをresetしてtest用に作り直す。参考サイト
Ruby - rails db:migrate RAILS_ENV=test ができない|teratailRuby - rails s -e testでlocalhost:3000を見るとエラーが出てしまいます。エラーを消したいです。|teratail
- 投稿日:2019-10-09T09:37:36+09:00
Ruby、Rails を学ぶ上でのおすすめの本まとめ
これは何?
Ruby、Rails に関して何によってどう学んできましたか?というのをよく聞かれるので、まとめた。
あくまで個人の経験に基づく感想です。(書籍へのリンクはアフィリエイトではありません)
対象
とりあえず Ruby でちょっとしたスクリプトは書けるし、Rails も軽く触ったことはあるよ、という方。
(全くRuby触ったことない人向けではないと思います)本
Rubyの言語仕様を学ぶ
効能
- Ruby っぽい書き方ってどんな書き方なんだろう?を学べる(map 使うとか)。
- Rails を読む上でのおまじないが減る。
- なぜ attr_accessor を書くとセッター/ゲッターが生えるのかとか、モデルがActiveRecord を継承していることの意味とかがわかるようになり不安が減る。
紹介
- Effective Ruby
- リファレンス的な本ではなく、もっと現実的に使われる文脈を意識して書かれているように感じた。読みやすかった。
- 写経しやすいのが良い。書いて身につけることができる。
- メタプログラミングRuby第2版
- メタプログラミングという切り口で Ruby の言語仕様を教えてくれる本だと思った。
- クラス定義の話(継承ツリーとか特異クラスとかinclude/extendとかの話)はこの本が一番分かりやすかった。
- 「ブロックがクロージャである」という表現を直感的に理解できるようになった。
設計力を高める
効能
- 以下のような疑問に対する自分なりの意見を持てるようになる。
- model/controller/view 以外にも app ディレクトリ以下に service とか作ることがあるっぽいけど、どこに何を書くのが美しいの?
- controller/model が肥大化してしまってつらいんだけどどうすればいいの?
- 実装に関して戦略レベルで大きなヘマをすることが減る。したがってコードレビューで大きくちゃぶ台返しされることが減る。
注意事項
- ちょっと読んでみて「難しくてほとんど全部よくわからん、」「言っている意味はわかるがこれを学んでなにか意味があるの?」となったら今読むべきではないと考えたほうが良いかもしれません。
- 知識というか考え方を学ぶ本だと私は解釈しており、理解できていない状態で読んでもほとんど学びはないのではないか?となっている。
- 具体的に開発を通じて悩んだ経験があると、「なるほどこういうふうに書けるのね!」となりやすいが、経験があまりないとピンとこないので記憶に残らない、ということもありそう。
紹介
- リファクタリング:Rubyエディション
- 神本。しかし絶版っぽい?
- 写経しやすいのが良い。書いて身につけることができる。
- リファクタリングの本なので、before の状態から after の状態に帰る方法としてどのような方法があるのかを学ぶことができる。
- before の状態を見てその問題点を列挙する力、after の候補を列挙する力、after の候補から最も良いものを選び出す力、を身につけるとアウトプットの質が大幅に改善される。
- Ruby によるデザインパターン
- 絶版っぽい?
- デザインパターンを Ruby で実装してみた、みたいなもの。
- 『リファクタリング:Ruby』 でしっかり学んでいると、だいたい「まぁそうだよね」、となるかもしれない。
- 「デザインパターンって言葉よく聞くけど何なのだろう?ちょっと学んでみたいな」みたいな人には特に向いているかと思う。
- オブジェクト指向設計実践ガイド―Rubyでわかる進化しつづける柔軟なアプリケーションの育て方(サンディメッツ本)
- 絶版じゃない!!!
- 上の2つの本で学んだこととかぶるところが多いので途中で読むのをやめたが、良本。
- 登場する具体例が自転車なので、自転車好きなら良いかも。個人的には特に興味も知識もないので、オブジェクトの例としてギアとかそういうの出てきてもピンとこなくてちょっとつらかった。
- 投稿日:2019-10-09T09:35:41+09:00
データ yaml json
yaml
- 構造化したデータを表現するモノ
記事
https://magazine.rubyist.net/articles/0009/0009-YAML.html
基本require 'yaml' yaml_data = <<-DATA - RED - GREEN - BLU DATA YAML.load(yaml_data)# リテラル yaml_data = <<-DATA - RED - GREEN - BLU DATA p YAML.load(yaml_data) # リテラル出力 ➜ Desktop ruby sample.rb ["RED", "GREEN", "BLU"] "\ndefault: &default\n adapter: mysql2\n host: 127.0.0.1\n encoding: utf8\n pool: 5\n username: root\n password:\n reconnect: false\n\ndevelopment:\n <<: *default\n database: development\n\ntest:\n <<: *default\n database: test\n\n\n" #yml形式 database = <<-DATA default: &default adapter: mysql2 host: 127.0.0.1 encoding: utf8 pool: 5 username: root password: reconnect: false development: <<: *default database: development test: <<: *default database: test DATA p YAML.load(database) #yml形式 出力 ➜ Desktop ruby sample.rb ["RED", "GREEN", "BLU"] {"default"=>{"adapter"=>"mysql2", "host"=>"127.0.0.1", "encoding"=>"utf8", "pool"=>5, "username"=>"root", "password"=>nil, "reconnect"=>false}, "development"=>{"adapter"=>"mysql2", "host"=>"127.0.0.1", "encoding"=>"utf8", "pool"=>5, "username"=>"root", "password"=>nil, "reconnect"=>false, "database"=>"development"}, "test"=>{"adapter"=>"mysql2", "host"=>"127.0.0.1", "encoding"=>"utf8", "pool"=>5, "username"=>"root", "password"=>nil, "reconnect"=>false, "database"=>"test"}}json
- json(JavaScript Object Notation)とは
javascriptのオブジェクト
require 'json' yaml_data = <<-DATA ["Red","Blue","Red"] DATA JSON.load(yaml_data)# json は基本はオブジェクト example.json { "ruby": { "rails":30000 }, "python": { "django":25000 } } require 'json' File.open("example.json") do |file| hash = JSON.load(file) p hash end hash = JSON.parse('{"ruby":{"rails":30000},"python":{"django":25000}}') p hash {"ruby"=>{"rails"=>30000}, "python"=>{"django"=>25000}}# 文字列型のjsonもある - parse hash = JSON.parse('{"ruby":{"rails":30000},"python":{"django":25000}}') p hash {"ruby"=>{"rails"=>30000}, "python"=>{"django"=>25000}}
- json 作成
generateハッシュ → jsonに require 'json' hash = JSON.generate({"ruby":{"rails":30000},"python":{"django":25000}}) p hashto_json# ruby で用意してくれている require 'json' hash = {"ruby":{"rails":30000},"python":{"django":25000}}.to_json p hash
- 投稿日:2019-10-09T09:26:17+09:00
【devise】confirmableを利用しているとき、メールアドレスを変更する際のメールによる確認作業をスキップする
config/initializers/devise.rb
を以下のように変更して保存。config/initializers/devise.rb... # If true, requires any email changes to be confirmed (exactly the same way as # initial account confirmation) to be applied. Requires additional unconfirmed_email # db field (see migrations). Until confirmed, new email is stored in # unconfirmed_email column, and copied to email column on successful confirmation. - config.reconfirmable = true + config.reconfirmable = false ...この時点でサーバーを起動していたなら再起動する。これでユーザー情報を変更する際に、確認作業なくメールアドレスを変更できる。
もし
users
テーブルにunconfirmed_email
カラムが残っているなら、不要なので削除する。$ rails g migration remove_unconfirmed_email_from_users unconfirmed_email:string $ rails db:migrate
- 投稿日:2019-10-09T09:26:17+09:00
【devise】confirmableを適用しているとき、メールアドレスを変更する際のメールによる確認作業をスキップする
config/initializers/devise.rb
を以下のように変更して保存。config/initializers/devise.rb... # If true, requires any email changes to be confirmed (exactly the same way as # initial account confirmation) to be applied. Requires additional unconfirmed_email # db field (see migrations). Until confirmed, new email is stored in # unconfirmed_email column, and copied to email column on successful confirmation. - config.reconfirmable = true + config.reconfirmable = false ...この時点でサーバーを起動していたなら再起動する。これでユーザー情報を編集する際に、メールアドレスを確認作業なく変更できる。
もし
users
テーブルにunconfirmed_email
カラムが残っているなら、不要なので削除する。$ rails g migration remove_unconfirmed_email_from_users unconfirmed_email:string $ rails db:migrate
- 投稿日:2019-10-09T09:26:17+09:00
【devise】confirmableを適用時の、メールアドレスを変更する際のメール確認をスキップする
config/initializers/devise.rb
を以下のように変更して保存。config/initializers/devise.rb... # If true, requires any email changes to be confirmed (exactly the same way as # initial account confirmation) to be applied. Requires additional unconfirmed_email # db field (see migrations). Until confirmed, new email is stored in # unconfirmed_email column, and copied to email column on successful confirmation. - config.reconfirmable = true + config.reconfirmable = false ...この時点でサーバーを起動していたなら再起動する。これでユーザー情報を編集する際に、メールアドレスをメールによる確認作業なしで変更できる。
もし
users
テーブルにunconfirmed_email
カラムが残っているなら、不要なので削除する。$ rails g migration remove_unconfirmed_email_from_users unconfirmed_email:string $ rails db:migrate
- 投稿日:2019-10-09T09:15:53+09:00
Deviseでログイン機能を追加・日本語化・Bootstrap適用まで
Deviseの日本語化やBootstrapの導入方法の記事はよく見かけます。ところが……
- ビューファイルを作成するときに,結局どのコマンドを使えばよいか分からない
$ rails g devise:views $ rails g devise:i18n:views $ rails g devise:views:bootstrap_templates
- 全て導入したはずなのにメール文が日本語化されない
など,順序を間違えると問題が発生します。そこで,ログイン画面を最低限のスタイルで実装するところまでをまとめてみました。
開発環境
- macOS Mojave 10.14.6
- Ruby 2.6.4
- Rails 5.2.3
- Bootstrap 4.3.1
- Devise 4.7.1 (confirmableなどの導入過程は記載していません)
0. 準備
以下の前提で進めていきます。(
-d postgresql
はお好みで)$ rails _5.2.3_ new devise_sample -d postgresql $ rails g controller homes indexconfig/routes.rbRails.application.routes.draw do root 'homes#index' endapp/views/layouts/application.html.erb(略) <body> <%= render 'shared/header' %> <%= yield %> </body>app/views/homes/index.html.erb<%= render 'shared/flash_messages' %>app/views/shared/_flash_messages.html.erb<% flash.each do |name, msg| %> <div class="alert alert-<%= name %>" role="alert" id="alert"> <a href="#" class="close" data-dismiss="alert">×</a> <%= msg %> </div> <% end %>app/views/shared/_header.html.erb<header> <nav class="navbar navbar-expand navbar-light"> <%= link_to "Deviseサンプル", root_path, class: 'navbar-brand' %> <div id="Navber"> <ul class="navbar-nav"> <% if user_signed_in? %> <li class="nav-item active"> <%= link_to 'ログアウト', destroy_user_session_path, method: :delete, class: 'nav-link' %> </li> <% else %> <li class="nav-item active"> <%= link_to "新規登録", new_user_registration_path, class: 'nav-link' %> </li> <li class="nav-item active"> <%= link_to "ログイン", new_user_session_path, class: 'nav-link' %> </li> <% end %> </ul> </div> </nav> </header>1. Gemの追加
- Gemfileに以下を追加して
$ bundle install
gem 'bootstrap', '~> 4.3.1' gem 'devise' gem 'devise-i18n' gem 'devise-i18n-views' gem 'devise-bootstrap-views', '~> 1.0' gem 'jquery-rails' gem 'rails-i18n'2. Bootstrapの導入
application.css
の拡張子をscss
に変更
application.scss
から,*= require_tree .
と*= require_self
を削除
application.scss
に@import "bootstrap";
を追加スタイルも追加
app/assets/stylesheets/application.scss@import "bootstrap"; // ログイン画面 .container-login { @extend .container-fluid; max-width: 576px; padding: 2rem; } // 「ログインしました」などのフラッシュ用スタイル .alert-notice { @extend .alert-info; } .alert-alert { @extend .alert-danger; }
application.js
に3つ追加app/assets/javascripts/application.js//= require jquery3 //= require popper //= require bootstrap-sprockets3. Deviseの導入
Devise
をインストール(user
の箇所は,任意のモデル名
でOKです)rails g devise:install rails g devise user rails db:create db:migrate
- 問題がなければ,
$ rails s
の後,http://localhost:3000
からログイン
ボタンを押せば,ログイン画面が表示されます。
gem 'devise-bootstrap-views'
を追加しているので, Bootstrapもある程度適用されています。
- 公式(hisea/devise-bootstrap-views)
- 横幅一杯表示されるのはちょっと……と思われるかもしれませんが,さらに見た目を整える作業は最後にします。
4. Deviseの日本語化
config/application.rbmodule AssociationTutorial class Application < Rails::Application # 以下を追加すれば日本語に + config.i18n.default_locale = :ja # タイムゾーンも変更するなら,以下を追加 + config.time_zone = 'Asia/Tokyo' end end
- サーバーを落として
$ rails s
で再起動すれば日本語に変更されます。5. メールを送信できるようにする(Gmailかつ開発環境のみ対応)
送信元の表示名
を変更しておきます。
- タイトル名はこの設定が反映されますが,メールアドレスの箇所は実際の送信するアドレスになります。
config/initializers/devise.rbDevise.setup do |config| - config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com' + config.mailer_sender = ''タイトル名 <noreply@example.com>' end
Gmailから送信する場合,安全性の低いアプリのアクセスを有効にする必要があります。
development.rb
のconfig.action_mailer.raise_delivery_errors = false
の箇所を置き換えます。
- メールアドレスやパスワードをgitの管理下に入れるのを避け,
credentials
管理にしておきます。本番環境で無駄にエラーが出ないようダミー情報を入れておきます。config/environments/development.rb# 削除 config.action_mailer.raise_delivery_errors = false # 以下に置き換え config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } if Rails.application.credentials.gmail.present? mail_address = Rails.application.credentials.gmail[:address] password = Rails.application.credentials.gmail[:password] else mail_address = 'admin@example.com' password = 'password' end config.action_mailer.raise_delivery_errors = true config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { enable_starttls_auto: true, address: "smtp.gmail.com", port: 587, user_name: mail_address, password: password, authentication: "plain" }
$ EDITOR=vi rails credentials:edit
で,credentials
の中に,メールアドレスとパスワードを記載します。gmail: address: 送信に使用するメールアドレス password: 送信に使用するパスワード
- メール送信の確認をするには,あらかじめ新規登録をした上で,ログイン画面の
パスワードを忘れましたか?
をクリックしてパスワード再設定メールを送信すればOKです。日本語にはなっているもののどうも不自然ですね……これは次の作業で解決します。
6. 日本語訳を変更
日本語訳を変更したい場合は,次のコマンドで
config/locales/devise.views.ja.yml
を作成し,編集すればOKです。rails g devise:i18n:locale ja
- なお,このコマンドの時点で,パスワード再設定メールの本文が自然なものに変わります。
- 例えば
アカウント登録
を新規登録
に変更したい場合は,devise.views.ja.yml
の該当文字を置換すればOKです。7. ログイン画面などの変更
- まず,次のコマンドでビューファイルを作成します。
rails g devise:i18n:views rails g devise:views:bootstrap_templates -f
【参考】それぞれのコマンドの最後に例えば
user
をつけることで,users
ディレクトリ内にファイルを作成することもできますが,その場合は,次の3つの作業を行わないと反映されません。
devise.views.ja.yml
30行目のdevise
をusers
に変更config/initializers/devise.rb
にあるconfig.scoped_views = false
のコメントアウトを外してtrue
に変更- サーバーを落として
$ rails s
で再起動例えば以下のファイルを
<div>
で囲むと,無駄に横長になっている状態を改善できます。
- ここから先はお好みで。
ファイル名app/views/devise/confirmations app/views/devise/passwords app/views/devise/registrations app/views/devise/sessions app/views/devise/unlocks<div class="container-login"> # 元のプログラム </div>
- エラーメッセージの表示がいまいちなので変更するためにオーバーライドします。
app/helpers/devise_helper.rbmodule DeviseHelper def bootstrap_devise_error_messages! return "" if resource.errors.empty? html = "" messages = resource.errors.full_messages.each do |errmsg| html += <<-EOF <div class="alert alert-danger alert-dismissible" role="alert"> <button type="button" class="close" data-dismiss="alert"> <span aria-hidden="true">×</span> <span class="sr-only">close</span> </button> #{errmsg} </div> EOF end html.html_safe end end
- ログイン画面だけエラーメッセージが表示されないので,追加しておきます。
app/views/devise/sessions/new.html.erb<div class="container-login"> <h1><%= t('.sign_in') %></h1> + <%= render 'shared/flash_messages' %> <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
app/views/devise
ディレクトリ内のファイルのbtn btn-primary
をbtn btn-primary btn-block
に置換すればボタンの横幅が自然になります。
- バリデーションはフロント側にも簡単に入れられます。
f.email_field
,f.password_field
にrequired: true
を入れることで空欄投稿できなくなります。- 新規登録(アカウント登録)画面では,例えば,
f.password_field
にrequired: true, minlength: '6', maxlength: '30'
を追加すれば,文字数のバリデーションも追加できます。app/views/devise/registrations/new.html.erb<div class="form-group"> <%= f.label :password %> - <%= f.password_field :password, autocomplete: 'current-password', - class: 'form-control' %> + <%= f.password_field :password, autocomplete: 'current-password', + class: 'form-control', + required: true, + minlength: '6', + maxlength: '30' %>
_links.html.erb
を編集して,一番下のリンクをボタンにしてみます。app/views/devise/shared/_links.html.erb<hr class="border-dark my-5"> <div class="form-group"> <%- if controller_name != 'sessions' %> <%= link_to t(".sign_in"), new_session_path(resource_name), class: 'btn btn-info btn-block' %><br /> <% end -%> <%- if devise_mapping.registerable? && controller_name != 'registrations' %> <%= link_to t(".sign_up"), new_registration_path(resource_name), class: 'btn btn-info btn-block' %><br /> <% end -%> <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> <%= link_to t(".forgot_your_password"), new_password_path(resource_name), class: 'btn btn-secondary btn-block' %><br /> <% end -%> <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> <%= link_to t('.didn_t_receive_confirmation_instructions'), new_confirmation_path(resource_name), class: 'btn btn-secondary btn-block' %><br /> <% end -%> <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> <%= link_to t('.didn_t_receive_unlock_instructions'), new_unlock_path(resource_name), class: 'btn btn-secondary btn-block' %><br /> <% end -%> <%- if devise_mapping.omniauthable? %> <%- resource_class.omniauth_providers.each do |provider| %> <%= link_to t('.sign_in_with_provider', provider: OmniAuth::Utils.camelize(provider)), omniauth_authorize_path(resource_name, provider), class: 'btn btn-info btn-block' %><br /> <% end -%> <% end -%> </div>
- さらに,リンクの
ログイン
,新規登録(アカウント登録)
を次のように変更してみます。# 上2つを次に置き換え <%- if controller_name != 'sessions' %> <%= link_to "アカウントをお持ちの方", new_session_path(resource_name), class: 'btn btn-info btn-block' %><br /> <% end -%> <%- if devise_mapping.registerable? && controller_name != 'registrations' %> <%= link_to "アカウントをお持ちでない方", new_registration_path(resource_name), class: 'btn btn-info btn-block' %><br /> <% end -%>単純なスタイルですが,ログイン画面がだいぶ整ったのではないでしょうか。
- 投稿日:2019-10-09T08:35:24+09:00
アンチパターン:Railsで外部キーとassociation名は同じにしない
要約
belongs_to :name
とforeign_key :name
が同じだと、その逆のhas_manyをとるときにどうがんばってもうまく取れなかった- 同じにしない
- 外部キーには
_id
つける詳細
- 以下のコードだと
to_messages
、from_messages
がとれないclass User < ApplicationRecord has_many :to_messages, class_name: 'Message', foreign_key: 'to', dependent: :destroy has_many :from_messages, class_name: 'Message', foreign_key: 'from', dependent: :destroy end class Message < ApplicationRecord has_many :to, class_name: 'User', foreign_key: 'to' has_many :from, class_name: 'User', foreign_key: 'from' end >Message.last.to =>#<User id: 373...> >User.last.to_messages =>[]
- has_manyの名前を変えたらいけた
class Message < ApplicationRecord has_many :to_user, class_name: 'User', foreign_key: 'to' has_many :from_user, class_name: 'User', foreign_key: 'from' end
- そもそも
foreign_key
は_id
がいいね- 自分では慣例的にやらないけどレビューであがってくることはあるので覚えておく
- 投稿日:2019-10-09T08:00:23+09:00
YOLPの2点間距離APIで緯度1度分・経度1度分の距離を調べる
概要
- 対象の位置に緯度・経度を1度 (または0.1度、0.01度、0.001度) 足したときの距離を Ruby + YOLP API で調べる
- 距離の計算には YOLP(地図):2点間距離API を使用する
- 可視化のために YOLP(地図):Yahoo!スタティックマップAPI を使用して地図画像を出力する
- 対象位置は「日本へそ公園 (兵庫県西脇市上比延町)」「名古屋駅」「納沙布岬 (のさっぷみさき) 離島を除けば日本の本土最東端」「荒崎 (あらさき) 沖縄本島最南端に位置する岬」の4箇所とする
ソースコード
動作確認環境: Ruby 2.6.5
require 'json' require 'open-uri' class Measure def initialize(appid) @appid = appid end # point: 基準となる位置など # cond: 移動量(緯度経度)など def output(point, cond) target = [] cond[:list].each_with_index do |info, i| # 緯度経度に移動分の緯度経度を足す t = {:lat => point[:lat] + info[:lat], :lon => point[:lon] + info[:lon]} # 2点間の距離を求める t[:dist] = distance(point, t) # ピン名をセット t[:pin] = info[:pin] # 移動量(緯度経度)に応じてどれだけの距離があるか出力 puts "#{point[:name]}(#{point[:lat]},#{point[:lon]}): 移動量(#{info[:lat]},#{info[:lon]}) => 距離#{t[:dist]}km" # 地図上に載せる情報を追加 target << t end # 地図画像を出力 open("distmap_#{point[:name]}_#{cond[:name]}.png", 'wb').write(map(point, target)) end # 2点間の距離を求める def distance(p, t) # YOLP(地図):2点間距離API - Yahoo!デベロッパーネットワーク # https://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/distance.html c = "#{p[:lon]},#{p[:lat]} #{t[:lon]},#{t[:lat]}" # 経度・緯度の順番 url = 'https://map.yahooapis.jp/dist/V1/distance?' + URI.encode_www_form({ 'appid' => @appid, 'coordinates' => c, 'output' => 'json', }) json = open(url).read # kmで小数点第6位までの値が入っている JSON.parse(json)['Feature'][0]['Geometry']['Distance'] end # 地図画像を返す # pointのpとtargetのt def map(point, target) # YOLP(地図):Yahoo!スタティックマップAPI - Yahoo!デベロッパーネットワーク # https://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/static.html # 緯度・経度の順番 pinp = "#{point[:lat]},#{point[:lon]},#{point[:lat]}\n#{point[:lon]}" pint = {} target.each do |t| # 緯度・経度の順番 pint["pin#{t[:pin]}"] = "#{t[:lat]},#{t[:lon]},#{t[:lat]}\n#{t[:lon]}\n#{t[:dist]}km" end url = 'https://map.yahooapis.jp/map/V1/static?' + URI.encode_www_form({ 'appid' => @appid, 'pinp' => pinp, 'width' => '600', 'height' => '600', }.merge(pint)) open(url).read end end # 基準となる場所 points = [ # 日本へそ公園 (兵庫県西脇市上比延町) {:name => 'Heso', :lat => 35, :lon => 135}, # 名古屋駅 {:name => 'Nagoya', :lat => 35.170634, :lon => 136.881751}, # 納沙布岬 (のさっぷみさき) 離島を除けば日本の本土最東端 {:name => 'Nosappu', :lat => 43.385056, :lon => 145.816278}, # 荒崎 (あらさき) 沖縄本島最南端に位置する岬 {:name => 'Arasaki', :lat => 26.075, :lon => 127.680833}, ] conds = [ { # 緯度経度に0.001度足す :name => '3', :list => [ {:pin => 'n', :lat => 0.001, :lon => 0.000}, {:pin => 'e', :lat => 0.000, :lon => 0.001}, ] }, { # 緯度経度に0.01度足す :name => '2', :list => [ {:pin => 'n', :lat => 0.01, :lon => 0.00}, {:pin => 'e', :lat => 0.00, :lon => 0.01}, ] }, { # 緯度経度に0.1度足す :name => '1', :list => [ {:pin => 'n', :lat => 0.1, :lon => 0.0}, {:pin => 'e', :lat => 0.0, :lon => 0.1}, ] }, { # 緯度経度に1度足す :name => '0', :list => [ {:pin => 'n', :lat => 1, :lon => 0}, {:pin => 'e', :lat => 0, :lon => 1}, ] }, ] appid = '<YOUR APPLICATION ID>' m = Measure.new(appid) points.each do |p| conds.each do |cond| m.output(p, cond) end end出力結果
- 日本では、緯度(南北方向の移動)の1度分はおおよそ110kmほどの距離になる
- 日本では、経度(東西方向の移動)の1度分はおおよそ90kmほどの距離になる
- 北海道は高緯度のため、経度方向の距離が小さくなる
- 沖縄は低緯度のため、経度方向の距離が大きくなる
Heso(35,135): 移動量(0.001,0.0) => 距離0.11094km Heso(35,135): 移動量(0.0,0.001) => 距離0.091288km Heso(35,135): 移動量(0.01,0.0) => 距離1.109405km Heso(35,135): 移動量(0.0,0.01) => 距離0.912882km Heso(35,135): 移動量(0.1,0.0) => 距離11.094135km Heso(35,135): 移動量(0.0,0.1) => 距離9.128817km Heso(35,135): 移動量(1,0) => 距離110.949629km Heso(35,135): 移動量(0,1) => 距離91.287788km Nagoya(35.170634,136.881751): 移動量(0.001,0.0) => 距離0.110944km Nagoya(35.170634,136.881751): 移動量(0.0,0.001) => 距離0.091098km Nagoya(35.170634,136.881751): 移動量(0.01,0.0) => 距離1.109437km Nagoya(35.170634,136.881751): 移動量(0.0,0.01) => 距離0.910983km Nagoya(35.170634,136.881751): 移動量(0.1,0.0) => 距離11.094448km Nagoya(35.170634,136.881751): 移動量(0.0,0.1) => 距離9.109825km Nagoya(35.170634,136.881751): 移動量(1,0) => 距離110.952776km Nagoya(35.170634,136.881751): 移動量(0,1) => 距離91.097874km Nosappu(43.385056,145.816278): 移動量(0.001,0.0) => 距離0.1111km Nosappu(43.385056,145.816278): 移動量(0.0,0.001) => 距離0.08103km Nosappu(43.385056,145.816278): 移動量(0.01,0.0) => 距離1.111002km Nosappu(43.385056,145.816278): 移動量(0.0,0.01) => 距離0.810299km Nosappu(43.385056,145.816278): 移動量(0.1,0.0) => 距離11.110106km Nosappu(43.385056,145.816278): 移動量(0.0,0.1) => 距離8.102994km Nosappu(43.385056,145.816278): 移動量(1,0) => 距離111.109843km Nosappu(43.385056,145.816278): 移動量(0,1) => 距離81.029456km Arasaki(26.075,127.680833): 移動量(0.001,0.0) => 距離0.110789km Arasaki(26.075,127.680833): 移動量(0.0,0.001) => 距離0.100054km Arasaki(26.075,127.680833): 移動量(0.01,0.0) => 距離1.107891km Arasaki(26.075,127.680833): 移動量(0.0,0.01) => 距離1.000541km Arasaki(26.075,127.680833): 移動量(0.1,0.0) => 距離11.078981km Arasaki(26.075,127.680833): 移動量(0.0,0.1) => 距離10.005405km Arasaki(26.075,127.680833): 移動量(1,0) => 距離110.796788km Arasaki(26.075,127.680833): 移動量(0,1) => 距離100.053811km出力結果 (地図画像)
日本へそ公園 (兵庫県西脇市上比延町)
- 緯度35度
- 経度135度
移動量1度
Heso(35,135): 移動量(1,0) => 距離110.949629km
Heso(35,135): 移動量(0,1) => 距離91.287788km
移動量0.1度
Heso(35,135): 移動量(0.1,0.0) => 距離11.094135km
Heso(35,135): 移動量(0.0,0.1) => 距離9.128817km
移動量0.01度
Heso(35,135): 移動量(0.01,0.0) => 距離1.109405km
Heso(35,135): 移動量(0.0,0.01) => 距離0.912882km
移動量0.001度
Heso(35,135): 移動量(0.001,0.0) => 距離0.11094km
Heso(35,135): 移動量(0.0,0.001) => 距離0.091288km
名古屋駅
- 緯度35.170634度
- 経度136.881751度
移動量1度
Nagoya(35.170634,136.881751): 移動量(1,0) => 距離110.952776km
Nagoya(35.170634,136.881751): 移動量(0,1) => 距離91.097874km
移動量0.1度
Nagoya(35.170634,136.881751): 移動量(0.1,0.0) => 距離11.094448km
Nagoya(35.170634,136.881751): 移動量(0.0,0.1) => 距離9.109825km
移動量0.01度
Nagoya(35.170634,136.881751): 移動量(0.01,0.0) => 距離1.109437km
Nagoya(35.170634,136.881751): 移動量(0.0,0.01) => 距離0.910983km
移動量0.001度
Nagoya(35.170634,136.881751): 移動量(0.001,0.0) => 距離0.110944km
Nagoya(35.170634,136.881751): 移動量(0.0,0.001) => 距離0.091098km
納沙布岬 (のさっぷみさき) 離島を除けば日本の本土最東端
- 緯度43.385056度
- 経度145.816278度
移動量1度
Nosappu(43.385056,145.816278): 移動量(1,0) => 距離111.109843km
Nosappu(43.385056,145.816278): 移動量(0,1) => 距離81.029456km
移動量0.1度
Nosappu(43.385056,145.816278): 移動量(0.1,0.0) => 距離11.110106km
Nosappu(43.385056,145.816278): 移動量(0.0,0.1) => 距離8.102994km
移動量0.01度
Nosappu(43.385056,145.816278): 移動量(0.01,0.0) => 距離1.111002km
Nosappu(43.385056,145.816278): 移動量(0.0,0.01) => 距離0.810299km
移動量0.001度
Nosappu(43.385056,145.816278): 移動量(0.001,0.0) => 距離0.1111km
Nosappu(43.385056,145.816278): 移動量(0.0,0.001) => 距離0.08103km
荒崎 (あらさき) 沖縄本島最南端に位置する岬
- 緯度26.075度
- 経度127.680833度
移動量1度
Arasaki(26.075,127.680833): 移動量(1,0) => 距離110.796788km
Arasaki(26.075,127.680833): 移動量(0,1) => 距離100.053811km
移動量0.1度
Arasaki(26.075,127.680833): 移動量(0.1,0.0) => 距離11.078981km
Arasaki(26.075,127.680833): 移動量(0.0,0.1) => 距離10.005405km
移動量0.01度
Arasaki(26.075,127.680833): 移動量(0.01,0.0) => 距離1.107891km
Arasaki(26.075,127.680833): 移動量(0.0,0.01) => 距離1.000541km
移動量0.001度
Arasaki(26.075,127.680833): 移動量(0.001,0.0) => 距離0.110789km
Arasaki(26.075,127.680833): 移動量(0.0,0.001) => 距離0.100054km
参考資料
- 投稿日:2019-10-09T06:00:14+09:00
マイグレーションファイルの命名規則
目的
マイグレーションファイルを作成する際に
作成のみでなく閲覧者などにもわかりやすい命名にするため規則などを記載していくtaskテーブルを作成
rails g migration CreateTasks name:string content:text
マイグレーションファイル例class CreateTasks < ActiveRecord::Migration[5.2] def change create_table :tasks do |t| t.string :name t.text :content end endtaskテーブルにカラムを追加
rails g migration AddStateToTasks state:string
rails g migration add_state_to_tasks state:string
マイグレーションファイル例class AddStateToTask < ActiveRecord::Migration[5.2] def change #[形式]add_column(テーブル名,カラム名,データ型) add_column :tasks, :state, :string end endadd_columnには次のオプションを指定することができる。
・ null:true … NOT NULL制約を削除
・ null:true … NOT NULL制約を追加
・ limit: size … ファイルのサイズに対する制限を設定
・default:[val]… [val]に設定した値をレコード作成じのカラムのデフォルト値とするtaskテーブルに追加したカラム名を変更
rails g migration RenameFromStateToTasks
rails g migration rename_state_to_tasks
マイグレーションファイル例class RenameFromStateToTasks < ActiveRecord::Migration[5.2] def change #[形式]rename_column(テーブル名,変更前のカラム名,変更後のカラム名) rename_column :tasks,:state,:status end endtaskテーブルに追加したカラムのデータ型を変更
rails g migration ChangeStatusOfTasks
rails g migration change_datatype_status_of_tasks
マイグレーションファイル例class ChangeDatatypeStatusOfTasks < ActiveRecord::Migration[5.2] def up #[形式]change_column(テーブル名,カラム名,データタイプ,オプション) change_column :tasks, :status, :integer # オプション # limit - カラム長の最大数 # change_column :tasks, :status, :integer, limit: 120 # default - カラムのデフォルト値を設定。NULLにしたい場合は、nilを指定 # change_column :tasks, :status, :integer, default: "タイトルがありません" # null - null制約を設定。false -> null制約がON。true -> null制約がOFF # change_column :tasks, :status, :integer, null: true end endtaskテーブルに追加したカラムにインデックスやユニーク制約の追加
rails g migration AddIndexStatusToTasks
rails g migration add_index_Status_to_tasks
マイグレーションファイル例class AddIndexStatusToTasks < ActiveRecord::Migration[5.2] def change add_index :tasks, :status #add_index :tasks, :status ,unique: true ユニーク制約も付加可能 end endtaskテーブルに追加したカラムにNULL制約の追加
rails g migration ChangeNotNullToTasks
rails g migration change_notnull_to_tasks
マイグレーションファイル例class ChangeNotNullToTasks < ActiveRecord::Migration[5.2] def change #tasksテーブルのstatusにNOT NULL制約を追加 change_column_null :tasks, :status, false end end
- 投稿日:2019-10-09T01:11:29+09:00
【49日目】Rails学習日誌 コメントの保存、表示、パーシャル作成、バリデーション、エラーの表示
68 コメント保存処理の実装 続き
コメントのコントローラーの編集
binding.pryでコメント入力時のパラメーターを確認
Rails flogによってパラメータが下記のように見やすく表示されるParameters: { "utf8" => "✓", "authenticity_token" => "(略)", "comment" => { "board_id" => "5", "name" => "例", "comment" => "コメント" }, "commit" => "送信" }ストロングパラメータの設定
保存できるパラメータはboard_id, name, commentのみにする
comments_controll.rbprivate def comment_params params.require(:comment).permit(:board_id, :name, :comment) endcreateアクションの作成
ストロングパラメータによって弾かれるかどうかをif文で分岐
分岐した結果、成功をエラーをflashメッセージを用いてリダイレクト先に表示comments_controll.rbdef create # コメントオブジェクトを作成 # フォームに入力されたパラメータで初期化 comment = Comment.new(comment_params) # コメントの保存。保存前にバリデーションチェック # 保存の可否によってif文で分岐 if comment.save flash[:notice] = 'コメントを投稿しました' #flashでリダイレクト先に一時的にメッセージを渡す redirect_to comment.board else # 以下はRails5.1以降専用 # コメントが保存できなかった場合入力したコメントオブジェクトとエラーメッセージのリストを返す。 # コメントオブジェクトの中身をリダイレクト先のフォームに戻したり、エラー表示は今後作る flash[:comment] = comment flash[:error_messages] = comment.errors.full_messages redirect_back fallback_location: comment.board # redirect_backで一つ前の画面に戻るようリダイレクト end end69 コメントの表示
showの問題を修正
修正前のshowアクション
boards_controller.rbdef show @comment = @board.comments.new endこの状態では、新しく作成されたが保存していない空のコメントが含まれてしまう。
=>常にからのコメントがコメント欄に表示されてしまうので修正する。boards_controller.rbdef show @comment = Comment.new(board_id: @board.id) endコメントの初期化の際にboard_idを用いることで、該当のboardのコメントで保存されたコメントのみを表示するようにした。
viewの作成
show.html.erb<div class="p-comment__list"> <div class="p-comment_listTitle">コメント</div> <%= render @board.comments %> # 特定のモデル(comment)のオブジェクトのリスト(comments)をrenderの引数に渡した場合、自動的にモデル名(comment)のviewが使用される。 # オブジェクトの数だけ繰り返しviewがレンダリングされる。 # 今回のrenderの対象は「comments」なので、/app/views/comments/_comments.html.erbがオブジェクトの数レンダリングされる </div>## コメント表示用のパーシャルの作成
/app/views/commentsを作成し、_comment.html.erbを作成。_comment.html.erb<div class="p-comment__item"> <p><%= simple_format(comment.comment) %></p> # simple_formatヘルパーで改行を<br>タグに変換してくれる <div class="p-comment__bottomLine"> <span><%= comment.name %></span> <span><%= comment.created_at.to_s(:datetime_jp) %></span> #以前作った日本語時刻表示 </div> </div>リファクタリング
commentを投稿するためのviewはcommentsディレクトリの下にある。
しかし、_comment_formはboardsディレクトリの下にある。
=>役割的にcommentsディレクトリ配下にあるべきなので修正する。_form.html.erb としてcomments配下にコピーした上で、shownのパーシャルの呼び出し方を変えれば完了。
show.html.erb<%= render partial: 'comments/form', locals: { comment: @comment } %>70 コメントモデルへのバリデーション追加
モデルにバリデーションを作成
comment.rbvalidates :name, presence: true, length: { maximum: 10 } validates :comment, presence: true, length: { maximum: 1000 }## エラーメッセージを作成
comments_controller.rbのcreateアクションのelse以下がバリデーションエラーの表示になる
以前作成した掲示板のcreate時のエラーメッセージを流用するapp/views/sharedディレクトリを作成
_error_messages.html.erbを作成<% if flash[:error_messages] %> <div class="alert alert-danger"> <ul> <% flash[:error_messages].each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %>各viewのエラー呼び出しを編集
まずはboardsから
こちらではすでに作成している_form.html.erb内にエラー表示の部分があるため、sharedを呼び出すように書き換える。_form.html.erb<%= render 'shared/error_messages' %>commentsにおいても_form.html.erbの先頭にsharedを呼び出すように上記と同じ記載をする。
エラーの日本語化
config/locales/ja.yml を編集
ja.ymlja: activerecord: attributes: board: name: 名前 title: タイトル body: 本文 comment: name: 名前 comment: コメント views: pagination: first: '最初' last: '最後' previous: '前' next: '次' truncate: '...'
- 投稿日:2019-10-09T00:04:47+09:00
RailsとDeviseのメモ
users/registrations/以下やusers/sessions/以下のviewの変更が反映されない
usersディレクトリではなくdeviseのもともとのディレクトリを読みに行ってしまっている。
routes.rbで明示的に示す必要がある。routes.rbdevise_for :users,controllers{ registrations: "users/registratons", sessions:"users/sessions", }メール(mailer)の場合はすこしやり方が違う。
views/users/mailer以下のファイルを編集したら以下の設定を行う。controllers/users/mailer.rbclass Users::Mailer < Devise::Mailer endを追加
config/initializers/devise.rbconfig.mailer = Users::Mailerを追加
http://yrfreelance.com/2019/01/13/rails-devise-mail-template/
SendGridでメールを送信する
starterは適宜変更
sendgridアドオンは無料のdynoでも使えるがクレカの登録が必要.settings > billing でクレジットカードを登録できる.
メール送信は400通/月まで無料heroku addons:create sendgrid:starter 確認 heroku config:get sendgrid_username heroku config:get sendgrid_password以下を追加する。
config/environments/production.rbconfig.action_mailer.default_url_options ={ host:"yourappname.herokuapp.com"} config.action_mailer.delivery_method = :smtp config.action_mailer.raise_delivery_errors = true config.action_mailer.smtp_settings ={ user_name:ENV["SENDGRID_USERNAME"], password:ENV["SENDGRID_PASSWORD"], domain:"heroku.com", adress:"smtp.sendgrid.net", port:587, authentication: :plain, enable_starttls_auto:true, }あるいは、以下を追加する
config/environment.rbActionMailer::Base.smtp_settings = { :address => 'smtp.sendgrid.net', :port => '587', :authentication => :plain, :user_name => ENV['SENDGRID_USERNAME'], :password => ENV['SENDGRID_PASSWORD'], :domain => 'heroku.com', :enable_starttls_auto => true }models/user.rb#devise_for に :confirmable を追加 devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable,:confirmableError: connect ECONNREFUSED
がでたら、上記の環境変数が適切に設定できているか確認migration fileを作成
bundle exec rails g migration addConfirmColumnToUser cconfirmed_at:datetime confirmation_token:string confirmation_sent_at:datetimedb/migrate/timestamps_add_confirm_column_to_user.rbdef change add_column :users, :confirmation_token, :string add_column :users, :confirmed_at, :datetime add_column :users, :confirmation_sent_at, :datetime add_index :users, :confirmation_token, unique: true end以下を追加
これがtrueだと、method missing エラーが起きる.
デフォルトでtrueになっていた気がするので注意。config/initializers/devise.rbconfig.reconfirmable = falsebundle exec rails db:migrateMailerが送信する認証用のアドレスをhttpからhttpsにする
httpとhttpsのサイトは別のサイト扱いされるのでパスワード保存がきかなくなってUXが低下するからhttpsのサービスを作っているならリンクもhttps化したほうがいい。
views/users/mailer/...#link_to の confirmation_url(@resource, :confirmation_token => @token)を # confirmation_url(@resource, :confirmation_token => @token, protocol: "https")に変える。