- 投稿日:2019-05-30T22:37:20+09:00
今日のリファクタリング -1
お腹ぐるぐるヨーグルト
どうも k1y0です。初めてのqiita投稿。今日のキニナルコード
before_action :set_content #@content def show if params[:type] == 'programming' @title = '速習 プログラミング!' @text = @content.programming_text elsif params[:type] == 'food' @title = '美味しい焼肉屋さん' @text = @content.food_text elsif params[:type] == 'money' @title = '爆速で100億稼ぐ方法' @text = @content.money_text end endこんなコードがありました。
どう変更したか
#before省略 def show @title, @text = case params[:type] when 'programming' '速習 プログラミング!', @content.programming_text when 'food' '美味しい焼肉屋さん', @content.food_text when 'money' '爆速で100億稼ぐ方法', @content.money_text end end課題
typeごとにhashとか作ってkeyで受け取った方がわかりやすそう。rubyむずかしい
- 投稿日:2019-05-30T20:47:08+09:00
【Ruby on Rails】resourcesで作られるルーティングの表記を作るアプリを作った。
タイトル見て「は?」って思った方もいるかなと思います。
Railsでアプリを作成する際に欠かせないルーティングですが、そこには resources っていう便利なメソッドがあります。
例えば、routes.rbに
routes.rbresources :usersって書くと
Prefix Verb URI Pattern Controller#Action users GET /users(.:format) users#index POST /users(.:format) users#create new_user GET /users/new(.:format) users#new edit_user GET /users/:id/edit(.:format) users#edit user GET /users/:id(.:format) users#show PATCH /users/:id(.:format) users#update PUT /users/:id(.:format) users#update DELETE /users/:id(.:format) users#destroy これらが一気に作られるわけですよ。(ああ便利)
ただ、たまに resources を使いたくない人とか使えない場合とかあったりなかったりします。
例えば、URI Patteren のところに users ではないコントローラーを使いたいときとか。
そんなとき用に完全個人用に Rails でアプリ作りました。
(個人用にサクッと作ったので見たらわかるやっすいやつやん)↓↓↓↓↓↓↓↓これです↓↓↓↓↓↓↓↓
https://resourcesrouting.herokuapp.com/使い方
Name と Name2 にそれぞれ何かしら文字列を入れて "Create Home" ボタン押すだけ。
あとはコピってペーストするだけ。
正直ワンパターンだけしかこんな今年ないならいらないですが、いくつもルーティングをこんな感じにする際は多少楽になるかなって思います。
後記
実際これ作るのに30分もかかってないですが、こんなの作ってる暇あったら素直に手打ちできたなと思っています(笑)
まぁでも、楽しいんでいいです(¬ω¬)b
ちなみにDBもセッションもなにも使ってないので何かが保存されることはないです。
- 投稿日:2019-05-30T17:38:56+09:00
【Rails】Active Storage + S3 + Active JobでGoogle Cloud Visionセーフサーチ
個人開発のWebアプリ「まちかどルート」v6.0rc6への実装メモです。
Amazon S3に画像をダイレクトアップロード
Railsガイドをもとに実装しました。
セーフサーチを実装
前回の記事のとおりです。
【Rails】Active Storage環境下でGoogle Cloud Visionのセーフサーチを実装
S3アップロード画像のパブリックURLを取得
こちらの記事を参考にしました。
Rails ActiveStorage で PUBLIC な URL を表示する
セーフサーチを非同期処理化
※controllerのコードは省略します
model
post.rbhas_one_attached :image after_commit :annotate_self, on: [:create, :update] def annotate_self if image.attached? ImageAnnotateJob.set(wait: 10.second).perform_later(self) end endpostの新規投稿もしくは編集のときに画像
imageが添付されていたらImageAnnotateJobというActive Jobのキューを走らせます。10秒後に走らすようセットした理由は、Amazon S3へのアップロード完了までのタイムラグが発生するかなと思ったからです。job
image_annotate_job.rbclass ImageAnnotateJob < ApplicationJob queue_as :second def perform(target) tempfile = target.image.attachment.service.send(:object_for, target.image.key).public_url require "google/cloud/vision" image_annotator = Google::Cloud::Vision::ImageAnnotator.new response = image_annotator.safe_search_detection image: tempfile response.responses.each do |res| safe_search = res.safe_search_annotation if safe_search.adult.to_s == "VERY_LIKELY" || safe_search.adult.to_s == "LIKELY" target.destroy return elsif safe_search.violence.to_s == "VERY_LIKELY" || safe_search.violence.to_s == "LIKELY" target.destroy return elsif safe_search.medical.to_s == "VERY_LIKELY" || safe_search.medical.to_s == "LIKELY" target.destroy return end end end endいったん
tempfileにS3アップロード画像のパブリックURLを格納。それをGoogle Cloud Visionのセーフサーチにかけます。このコードはすべてActive Jobによってバックグラウンド(非同期)処理されます。もし不適切な画像と判断されれば投稿そのものを削除する流れです。Sidekiq
config\sidekiq.yml:concurrency: 5 :queues: - [default, 7] - [second, 5]じぶんはActive JobのライブラリとしてSidekiqを使用しています。上記
image_annotate_job.rbのqueue_as :secondによってキューが処理される優先順位を設定しました。あとがき
駆け足ですが以上です。Google Cloud Visionのセーフサーチは高精度ですがレスポンスに1~2秒ほど要するため、そのぶん前回の記事のような同期処理だと投稿完了までにユーザーを待たせてしまううえ、サーバーサイドに負荷がかかります。今回の記事はそれらの課題を解決するものとなります。
また、苦労したのがS3アップロード画像のパブリックURLを取得する部分でした。
url_forやrails_blob_urlといったActive Storageのメソッドを使うと時限的なものorリダイレクトされるURLしか取得できずセーフサーチにかけても「そんな画像はありませんよ」と言われてしまいます。というわけで試行錯誤を経たおかげでよりレスポンス性とセキュリティ性を兼ね備えた画像投稿機能を実装できました。
- 投稿日:2019-05-30T15:01:21+09:00
[jQuery/Rails] Uncaught TypeError: t.modal is not a function
前提
Rails5.2
エラー内容
SummernoteのWYSIWYGエディターを使って、写真投稿をする機能を実装しようとしたら、エディターのImageタブをクリックしても、画像挿入のウィンドウが表示されない(エディター)、という問題。
Google Chromeのデベロッパーツール(Shift+Command+c)でエラー内容を確認すると、以下のエラーが発生する。
Uncaught TypeError: t.modal is not a function at Object.showDialog......... at Object.<anonymous>........色々ネットで調べると、このエラーメッセージは、
Uncaught TypeError: $(...).modal is not a function
直訳:「$(...).modalはfunctionではありません」
意訳:「.modal()なんて関数は存在しない」
っていう意味らしい。このエラーは、JavaScriptのエラーなので、railsとかrubyではなく、一番疑わしいのは、「自身のコード内に該当するJavaScriptの記述が存在するかどうか」らしい。よくわからんけど、要は、JavaScriptが怪しいらしい!!!
とりあえず、自分のjsが記述されている、javascripts/application.jsを見に行く。
よ〜く見ると、jqueryが3つも記述されている。これが怪しいかも。。。
//= require jquery2
//= require jquery
//= require jquery_ujsassets/javascripts/application.js//= require jquery2 ← この子 //= require rails-ujs //= require popper //= require bootstrap //= require bootstrap-sprockets //= require jquery ← この子 //= require jquery_ujs ← この子 //= require_tree . //= require toastr //= require jquery-ui //= require tag-it //= require summernote/summernote-bs4.min //= require summernote/lang/summernote-ja-JP //= require summernote-init //= require activestorage // = require turbolinks解決策
railsでのjqueryの記述の仕方について、原点に戻る。
【リンク】rails/jquery-railsすると、記述方法に以下の通り記載されている。
Installation
If you are running Rails 5.1 and up, and if you have included //= require rails-ujs, then jquery_ujs is not needed anymore. You can just add:
//= require jquery
If you want to use jQuery 2, you can require jquery2 instead:
//= require jquery2
//= require jquery_ujsと記載されている。
つまり、次の2点によって、エラーが発生していた。
1. Rails5.1以降は、rails-ujsがあれば、//= require jquery_ujsは不要
2.//= require jquery2使ってるなら、//= require jqueryは不要よって、次の2つを削除して、
//= require jquery
//= require jquery_ujs次の2つだけを残せばOKでした!!!
assets/javascripts/application.js//= require jquery2 ← キープ //= require rails-ujs ← キープ以上。
関連リンク
- 投稿日:2019-05-30T14:41:21+09:00
Rails OAuth::Unauthorized というエラー出たら
OAuth::Unauthorized エラー
Railsで現在サービスを開発しているホリカワ です。
本番環境でツイッター経由ログインしようとすると、上記のエラーが出ました。
原因としては
①CallbackURLの設定ミス
②Twitter API key関連の設定ミスが多いかとは思います。(これ以外にもたくさんありそう)
解決方法
僕の場合は①でした。
結論からいうと、config/initializers/devise.rbに設定を加えると解決しました。
config/initializers/devise.rbconfig.omniauth :twitter, "twiiter api key", "twitter secret key"scope: 'email', callback_url: 'example.com/auth/twitter/callback'
↑を追加config/initializers/devise.rbconfig.omniauth :twitter, "twiiter api key", "twitter secret key", scope: 'email', callback_url: 'example.com/auth/twitter/callback'わかったこと
このほかのエラーの原因として、本番環境の場合は
https://でないとダメみたいです。また、twitter dev のアプリの設定で、callback_urlが間違っていないかは
rails routesで確認してみましょう。user_twitter_omniauth_callback GET|POST /users/auth/twitter/callback(.:format終わりに
OAuth::Unauthorized は調べてみた感じだといくつかの要因が考えられそうです。
こちらの記事が解決のお手伝いになればと思います。
- 投稿日:2019-05-30T14:01:04+09:00
Rails Missing host to link to! のエラーが出た時
Missing host to link to! Please provide the :host parameter, set default_url_options[:host]
Railsでサービスを開発しているホリカワ です。
ついに開発環境で一通り終え、本番環境にデプロイしたら上記のようなエラーが出ました。
ようは確認URLを渡すメールが送れない、というエラーです。
解決方法
https://easyramble.com/missing-host-to-link-to.html
↑こちら参考にさせていただきました、ありがとうございます。上記のエラーは
「hostが見つからないので、default_url_options[:host]を指定してくれ」
ということなので、以下のようにすれば解決します。config/production.rb... config.action_mailer.default_url_options = { host: 'example.com'} ...
- 投稿日:2019-05-30T13:15:03+09:00
STIとポリモーフィックを利用したコメント機能の作成
はじめに
インターン先でSTIとポリモーフィックを利用したコメント機能を作成したときに
自分が求めてる情報が出てこなかったのと
ハマったことがいくつかあるのでメモ代わりに残していこうと思いますポリモーフィックやSTIについては
Railsのポリモーフィック関連とはなんなのか
みんなRailsのSTIを誤解してないか!?
などがとても丁寧でわかりやすく参考になります今回は設計やコード中心なので概念などはそちらで理解していただければと思います
私も未熟なところがたくさんあるので、指摘等あれば教えていただけると嬉しいです設計について
今回の設計はざっとこんな感じです。
(いろいろ省いて主要部分だけの実装を行っていきます)
1つのcommentsテーブルに2種類のテーブルがSTIで継承されており
taskかprojectのどちらかが紐づくような設計となっております!
常にprojectとtaskに紐づくcommentを作るわけではないので
projectとtaskからのびるcommentへのリレーションは点線で記述しました
(正しい書き方があるのかわからなかったです)
実装
早速実装に入っていきます!
テーブルの作成
commentsとtasksとprojectsテーブルの作成を行っていきます
commentsテーブルにはSTIのためのtypeを作成し
ポリモーフィックのためのcommentable_typeとcommentable_idという〇〇_typeと〇〇_idというカラムも作ります$ rails g model Comment content:string type:string commentable_type:string commentable_id:integer $ rails g model Task title:string content:string $ rails g model Project name:stringモデルの設定
モデルのディレクトリ改造は写真のようにcommentをtaskとprojectが継承するように作成します
こうすることによりSTIを行うことができます
次はモデルにポリモーフィックなどの設定を行っていきますcomment.rbclass Comment < ApplicationRecord belongs_to :commentable, polymorphic: true endproject.rbclass Project < ApplicationRecord has_many :comments, class_name: 'Comment::Project', as: :commentable, dependent: :destroy endtask.rbclass Task < ApplicationRecord has_many :comments, class_name: 'Comment::Task', as: :commentable, dependent: :destroy endcommentを継承しているprojectとtaskは
.rbclass Comment::Task < Comment end.rbclass Comment::Project < Comment endと記述することにより、commentを継承してくれます
モデルに記述することは以上ですポリモーフィックとSTIができているかの確認
この時点でrails consoleで以下のコマンドたちを打ってみてください!
pry(main)> Comment::Task.new => #<Comment::Task:0x00007fbf75f1e668 id: nil, type: "Comment::Task", commentable_type: nil, commentable_id: nil> pry(main)> @task = Task.create(title: "test", content: "test") pry(main)> @task.comments.build => #<Comment::Task:0x00007fbf7b0ba418 id: nil, type: "Comment::Task", commentable_type: "Task", commentable_id: 4, user_id: nil, content: nil, created_at: nil, updated_at: nil>typeには継承しているmodelが入っていおり
commentable_typeにはcommentに紐づくmodelが入り
commentable_idにはcommentに紐づくidが入っております
こうすることにより、commentという1つのモデルに2つのうちどちらか1つのモデルに紐づけることができます
この3つのカラムが作成できていたら、ポリモーフィックとSTIができていますルーティングとcontrollerの設定
routes.rbRails.application.routes.draw do resources :tasks do resources :comments, only: [:create], controller: 'task/comments' end resources :projects do resources :comments, only: [:create], controller: 'project/comments' end endタスクのコメント機能の作成
ここからはタスクのコメント機能について作成していきます
まずはcontrollerですtasks/show.html@comment = Comment::Task.newComment::Taskのインスタンスを作成してtasksの詳細ページに投稿画面を作成します
tasks/show.html.erb<%= form_for @comment, url: task_comments_path(task_id: @task.id) do |f| %> <%= f.text_area :content %> <%= hidden_field_tag :type, @comment.type %> <%= f.submit 'コメントを投稿する' %> <% end %>タスクを継承しているコメントControllerでcreateを行っていきます
controllers/task/comment_controller.rbdef create @comment = @task.comments.build(comment_params) @comment.save redirect_to task_path(@task) end private def comment_params params.require(params[:type].underscore.gsub('/', '_').to_sym).permit(:content) endパラメーターの受け取り方はStrong Parametersを動的に設定を参考にしました
実はこれだけでもうコメントの作成はできております!
終わりに
STIやポリモーフィック、最初全然理解は出来なかったですが、実際に手を動かすことで少し理解できたような気がします。
今はtaskとprojectにしか紐付かないのですが、もっといろんなモデルに紐づくものだと
紐づくために必要な外部キーを増やさなくて良かったり
新しくコメントに関するテーブルを作らなくていいので便利だと感じました。
でもなぜそういう使い方をしている記事がヒットしなかったんだろうという疑問が残りました。
最後まで見ていただきありがとうございました!
ご指摘あればどしどしおまちしております〜!
- 投稿日:2019-05-30T12:37:39+09:00
+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}
+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}+91-9501761003 Black magic Specialist Molvi ji in {{Mumbai}}
- 投稿日:2019-05-30T11:41:37+09:00
mac で rails new した後の bundle install 時に ffi 1.11.0 のインストールが失敗したのでバージョン固定で解決
バージョン
名前 バージョン macOS 10.13.6 ruby 2.3.7p456 (2018-03-28 revision 63024) [universal.x86_64-darwin17] rails 5.2.3 起きたエラー内容
$ bundle exec rails new ../sample create create README.md create Rakefile create .ruby-version create config.ru create .gitignore create Gemfile (略) Fetching gem metadata from https://rubygems.org/............ Fetching gem metadata from https://rubygems.org/. Resolving dependencies... Fetching rake 12.3.2 Your user account isn't allowed to install to the system RubyGems. You can cancel this installation and run: bundle install --path vendor/bundle to install the gems into ./vendor/bundle/, or you can enter your password and install the bundled gems to RubyGems using sudo. Password: Installing rake 12.3.2 Fetching concurrent-ruby 1.1.5 Installing concurrent-ruby 1.1.5 (略) Fetching coffee-rails 4.2.2 Installing coffee-rails 4.2.2 Fetching ffi 1.11.0 Installing ffi 1.11.0 with native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension. current directory: /private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c /System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/bin/ruby -r ./siteconf20190519-47252-1at7a63.rb extconf.rb checking for ffi.h... no checking for ffi.h in /usr/local/include,/usr/include/ffi... yes checking for ffi_call() in -lffi... yes checking for ffi_closure_alloc()... no checking for shlwapi.h... no checking for rb_thread_call_without_gvl()... yes checking for ruby_native_thread_p()... yes checking for ruby_thread_has_gvl_p()... yes creating extconf.h creating Makefile To see why this extension failed to compile, please check the mkmf.log which can be found here: /var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/extensions/universal-darwin-17/2.3.0/ffi-1.11.0/mkmf.log current directory: /private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c make "DESTDIR=" clean current directory: /private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c make "DESTDIR=" mkdir -p "/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c"/libffi-i386; (if [ ! -f "/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c/libffi"/configure ]; then echo "Running autoreconf for libffi"; cd "/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c/libffi" && /bin/sh /private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c/libffi/autogen.sh > /dev/null; fi); (if [ ! -f "/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c"/libffi-i386/Makefile ]; then echo "Configuring libffi for i386"; cd "/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c"/libffi-i386 && env CC=" xcrun clang" CFLAGS="-arch i386 " LDFLAGS="-arch i386" "/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c/libffi"/configure --disable-static --with-pic=yes --disable-dependency-tracking --disable-docs --host=i386-apple-darwin > /dev/null; fi); env MACOSX_DEPLOYMENT_TARGET=10.4 /Applications/Xcode.app/Contents/Developer/usr/bin/make -C "/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c"/libffi-i386 (略) libtool: link: ranlib .libs/libffi_convenience.a libtool: link: ( cd ".libs" && rm -f "libffi_convenience.la" && ln -s "../libffi_convenience.la" "libffi_convenience.la" ) /bin/sh ./libtool --tag=CC --mode=link xcrun clang -arch i386 -Wall -fexceptions -no-undefined -version-info `grep -v '^#' /private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c/libffi/libtool-version` '-arch' 'i386' -arch i386 -o libffi.la -rpath /usr/local/lib src/prep_cif.lo src/types.lo src/raw_api.lo src/java_raw_api.lo src/closures.lo src/x86/ffi.lo src/x86/sysv.lo libtool: link: xcrun clang -dynamiclib -o .libs/libffi.7.dylib src/.libs/prep_cif.o src/.libs/types.o src/.libs/raw_api.o src/.libs/java_raw_api.o src/.libs/closures.o src/x86/.libs/ffi.o src/x86/.libs/sysv.o -arch i386 -arch i386 -arch i386 -install_name /usr/local/lib/libffi.7.dylib -compatibility_version 9 -current_version 9.0 -Wl,-single_module ld: warning: The i386 architecture is deprecated for macOS (remove from the Xcode build setting: ARCHS) Undefined symbols for architecture i386: "___x86.get_pc_thunk.bx", referenced from: _ffi_call_i386 in sysv.o _ffi_closure_raw_SYSV in sysv.o _ffi_closure_raw_THISCALL in sysv.o "___x86.get_pc_thunk.dx", referenced from: _ffi_closure_i386 in sysv.o _ffi_closure_STDCALL in sysv.o ld: symbol(s) not found for architecture i386 clang: error: linker command failed with exit code 1 (use -v to see invocation) make[3]: *** [libffi.la] Error 1 make[2]: *** [all-recursive] Error 1 make[1]: *** [all] Error 2 make: *** ["/private/var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0/ext/ffi_c"/libffi-i386/.libs/libffi_convenience.a] Error 2 make failed, exit code 2 Gem files will remain installed in /var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/gems/ffi-1.11.0 for inspection. Results logged to /var/folders/_h/xgr__5xn3kscjx0f8m7v3qbr0000gn/T/bundler20190519-47252-1smbwrlffi-1.11.0/extensions/universal-darwin-17/2.3.0/ffi-1.11.0/gem_make.out An error occurred while installing ffi (1.11.0), and Bundler cannot continue. Make sure that `gem install ffi -v '1.11.0'` succeeds before bundling. In Gemfile: spring-watcher-listen was resolved to 2.0.1, which depends on listen was resolved to 3.1.5, which depends on rb-inotify was resolved to 0.10.0, which depends on ffi run bundle exec spring binstub --all bundler: command not found: spring Install missing gem executables with `bundle install` $macOS が 10.13.6 なのがきっといけないのだろうと思うが、そこじゃない場所で解決を試みる。
解決後に
Gemfile.lockを見ると、ffiの依存指定は一箇所のみで、こうなっていた。rb-inotify (0.10.0) ffi (~> 1.0)
ffi (~> 1.0)とあるので、ffiの1.xの最新版を取ろうとして、それがインストールできていない。解決方法
~> 1.0ということは1.11.0が必要なわけじゃないはずので、Gemfileを書き換えて、インストールできるバージョンに固定した。1.9.21は、あくまで例ですgem 'ffi', '= 1.9.21'(これは要らないかもしれない) 事前にインストールしておく。
$ sudo gem install ffi -v '1.9.21' Fetching: ffi-1.9.21.gem (100%) Building native extensions. This could take a while... Successfully installed ffi-1.9.21 Parsing documentation for ffi-1.9.21 Installing ri documentation for ffi-1.9.21 Done installing documentation for ffi after 3 seconds 1 gem installed $で、改めて bundle install
$ bundle install --path vendor/bundle The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`. Fetching gem metadata from https://rubygems.org/............ Fetching gem metadata from https://rubygems.org/. Resolving dependencies... Using rake 12.3.2 Using concurrent-ruby 1.1.5 (略) Using railties 5.2.3 Using coffee-rails 4.2.2 Fetching ffi 1.9.21 Installing ffi 1.9.21 with native extensionsうまくいった
バージョンの選び方
ffi 1.9.21を選ぶべきだというわけではないのですが、あらかじめ mac 側にインストールしてある可能性(他の ruby プログラムを動かすためにインストールしたことがあった、など)を考えれば、たとえばgem listで調べればインストール可能なバージョンがわかるはず$ gem list ffi *** LOCAL GEMS *** ffi (1.9.21) public_suffix (3.0.3)それ以外では、 https://rubygems.org/gems/ffi/versions を見て、一つ前のバージョンの最新を選ぶと良いと思います。今回だと、失敗したのは
1.11.0なので、1.10.xの中での最新の1.10.0を試す、それでもダメなら1.9.25を試す、...を繰り返す、など。時間がある人は、もちろん原因を特定してそれが解決できる最新のバージョンを選びましょう。
- 投稿日:2019-05-30T11:17:13+09:00
RSpec 設定
RSpec導入のための備忘録です。
Gemfile
Gemfilesource 'https://rubygems.org' ruby '2.6.3' gem 'rails', '~> 6.0.0.rc1' group :development, :test do gem 'factory_bot_rails' end group :test do gem 'capybara' gem 'selenium-webdriver' gem 'webdrivers' gem 'rspec-rails' endconfig/application.rbrequire_relative 'boot' require 'rails/all' Bundler.require(*Rails.groups) module Taskleaf class Application < Rails::Application config.load_defaults 6.0 config.generators do |g| g.test_framework :rspec, fixtures: true, view_specs: false, helper_specs: false, routing_specs: false, controller_specs: false, request_specs: true, system_specs: true end end end$ rm -rf ./test $ rails g rspec:installspec/spec_helper.rb# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration require 'capybara/rspec' RSpec.configure do |config| config.before(:each, type: :system) do driven_by :selenium_chrome_headless end # rspec-expectations config goes here. You can use an alternate # assertion/expectation library such as wrong or the stdlib/minitest # assertions if you prefer. config.expect_with :rspec do |expectations|spec/rails_helper.rb# コメントされているので、コメントを外す # spec/support以下に、いろいろファイルを置けるようになる Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f } RSpec.configure do |config| # テスト中に、FactoryBot.create(:user) ではなく、create(:user) と書けるようになる。 config.include FactoryBot::Syntax::Methods endspec/support/login_support.rbmodule LoginSupport # 利用者がログインする def login_as(user) visit root_path click_link "Sign in" fill_in "Email", with: user.email fill_in "Password", with: user.password click_button "Log in" end end # RSpecの設定 LoginSupport をinclude RSpec.configure do |config| config.include LoginSupport endRSpecのレポートを見やすく
.rspec--require spec_helper --format documentationファクトリ追加
rails g factory_bot:model userspec/factories/users.rbFactoryBot.define do factory :user do name { '太郎' } sequence(:email) { |n| "user#{n}@example.com" } # 連番 password { 'password' } end endスペック作成
# rails g rspec:system users # ジェネレータ無いので手動 rails g rspec:request users rails g rspec:model users参考
使い方
使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」
使えるRSpec入門・その2「使用頻度の高いマッチャを使いこなす」
使えるRSpec入門・その3「ゼロからわかるモックを使ったテストの書き方」
使えるRSpec入門・その4「どんなブラウザ操作も自由自在!逆引きCapybara大辞典」
rspec-rails 3.7の新機能!System Specを使ってみた書籍
Everyday Rails - RSpecによるRailsテスト入門
現場で使える Ruby on Rails 5速習実践ガイド
- 投稿日:2019-05-30T10:54:54+09:00
rails new の手順メモ
メモ: アプリケーションを作るときに必要な Gemfile と、アプリケーションで使う Gemfile は別でよい。
Rails アプリケーション作成用のプロジェクトを作る
Gemfile
rails_generator みたいなディレクトリを作って、そこに Gemfile って名前のファイルを置く。内容は下記
Gemfile# frozen_string_literal: true source 'https://rubygems.org' gem 'rails'bundle install
デバッグ用なので path を指定する
$ bundle install --path vendor/bundleこんな感じになるはず
$ ls vendor Gemfile Gemfile.lock $rails new
ディレクトリを指定して rails new をする。今回は
-+- (root) |- rails_generator (今操作していたディレクトリ) `- sampleとなるように下記を実行してみる。
$ bundle exec rails new ../sample終わったら、 rails_generator 配下は消して良い
- 投稿日:2019-05-30T10:36:53+09:00
【Rails】個人開発のアプリに5,000万円の交渉相手が現れました
個人開発のWebアプリ「まちかどルート」。
驚いたことに5,000万円の交渉話が飛び込んできました。
【速報】
— 西村 治久(ハル) (@west2538) May 29, 2019
個人開発のアプリ #まちかどルート に5,000万円の買い手が現れました。これから交渉しますhttps://t.co/I47lB4Z8pL pic.twitter.com/uIF322UZS6まだ交渉中ではありますが、ここに至る1年弱の所感をまとめたいと思いました。
RubyとRailsに入門して1年弱
プログラミングを学んだのは、40代でセミリタイア&山奥で隠居生活するようになってからというもの、新たなたしなみのひとつにしようと思ったのがきっかけです。
ソーシャルな隠居の、新たな“たしなみ”。プログラミングをはじめました
アイデアがどう生まれたか
世間と隔絶されずより一層ひととの関係性を高める自称 ソーシャルな隠居生活では、じぶんの時間がたくさん持てます。余白の時間に「あ、こんな機能を作ってみようかな」というアイデアがふと生まれやすいです。
アイデアとは、ひねり出すものではなく、それまで興味の赴くまま得てきた数多くのインプットと行動から余白の時間にふと思いつくものなのでしょうか。
よくローカル環境構築などと言いますが、ノートPC上だけでなく自身の環境構築も大事なんだと思いました。そういう意味ではじぶんの環境構築は恵まれていたかもしれません。
生活への変化
プログラミングをたしなみのひとつにしたおかげで、そうした余白の時間が充実したものになりました。
たとえばカフェなどで思いがけず待ち時間が長くなったとしても、ふとアイデアを思いついたらノートPCを開き、コードに落とし込みます。
いままで持て余していた時間が楽しいものとなりました。
どう学んできたか
書籍を読んだりスクールに通うということをしていません。ほとんどが必要に応じてインターネットで調べるという独学スタイルです。そのせいか基本的な知識がところどころ抜けているように思います。
反面、基本的な知識がないおかげなのか、参考文献をそのまま写すのではなく「もしかしてこんなふうに書けば動くのかな」という感じでコードを自由奔放に書き換えたりするんですけど、それが本当に動くとうれしいですね。いわゆる論理的思考が鍛えられているのでしょうか。
開発を続けられた理由
オープンソースのSNS「Mastodon」に触れていたことが大きかったと思います。だいぶお手本にさせていただきましたし、APIで連携することで個人開発の幅が広がりました。
Mastodonが日本に普及して2年。インスタンス運営と連携アプリの開発が楽しい
これから
5,000万円の交渉の成否はこれからのことなのでさておき、じぶんの生活を経済的というよりひととの関係性や精神的に豊かにするための趣味の個人開発ですから飽きるまで続けていこうと思います。
なによりも、スタートアップやエンジニア関係のつながりがこれまで以上に増えたことがうれしいです。やはりコミュニティとして日常的に学びあうことが、成長のスピードを加速させるんでしょうね。
- 投稿日:2019-05-30T09:57:38+09:00
[初心者]テストコードを書く際の原則
テストコードとは?
テストコードとは、本番環境に実装する前に、各メソッドがしっかりと自分が期待した値を取得し、保存しているのか確認することを指します。
もしなにもテストせずに本番環境に実装してしまったら、ユーザーからの苦情があり、サーバーを止めて修正しないといけないですよね??
それらの原因が結果的に、損失だったり、ユーザーの評価を下げてしまうことになる可能性があります?今回はテストコードを書く際の大切な原則について書いていきたいと思います!!
①各exampleで期待する値は1つだけ
期待する値を2つ以上含めてしまうと、どちらのエクスペクテーションでエラーが出たのか判別できず、正確なテストができないため、1つだけにしておきましょう!!
※エクスペクテーション(予想、期待、切望、待望)
②期待する結果をはっきりと分かりやすく記述
明快な記述にすることで、自身の確認やメンバーとの共有、顧客への仕様説明が楽になります。
結果としてコミュニケーションミスが低下し、スムーズに仕事を進めることができます。もし分かりづらい記述だったら、一々相手に確認をしてテストするという無駄な時間が生まれますよね?
③起きて欲しいことと起きてほしくないこと両方をテストする
これはどちらもテストで予期せぬ動作が残るのを防ぐためにどっちも行います!!
そうすればエラー発生率の低下に繋がると思っています?
④境界値をテストする
例えば、パスワード登録の際に8文字以上を保存するとしましょう。
テストする際には、8文字以上保存されているかの確認と、逆に7文字以下のパスワードは保存されていないかテストをする必要があります。
よくバリデーションとかに使われるので、しっかりチェックする必要がありますね?可読性を考えつつ、適度にDRYする
DRYとはDon't Repeat Yourselfの略になります。
テストコードにおいて何よりも相手に伝わる分かりやすさが大切です。
分かりづらくなってテストの見落としが起きるよりマシだと思いませんか?最後に
本番環境前には必ずテストコードを書き、
ちゃんとメソッドが定義されているのか、
値がしっかり取得されているのかを確認してしっかりとしたアプリケーションを作っていきましょう!!!
- 投稿日:2019-05-30T09:57:38+09:00
【スクール生】12日目:テストコードを書く際の原則
テストコードとは?
テストコードとは、本番環境に実装する前に、各メソッドがしっかりと自分が期待した値を取得し、保存しているのか確認することを指します。
もしなにもテストせずに本番環境に実装してしまったら、ユーザーからの苦情があり、サーバーを止めて修正しないといけないですよね??
それらの原因が結果的に、損失だったり、ユーザーの評価を下げてしまうことになる可能性があります?今回はテストコードを書く際の大切な原則について書いていきたいと思います!!
①各exampleで期待する値は1つだけ
期待する値を2つ以上含めてしまうと、どちらのエクスペクテーションでエラーが出たのか判別できず、正確なテストができないため、1つだけにしておきましょう!!
※エクスペクテーション(予想、期待、切望、待望)
②期待する結果をはっきりと分かりやすく記述
明快な記述にすることで、自身の確認やメンバーとの共有、顧客への仕様説明が楽になります。
結果としてコミュニケーションミスが低下し、スムーズに仕事を進めることができます。もし分かりづらい記述だったら、一々相手に確認をしてテストするという無駄な時間が生まれますよね?
③起きて欲しいことと起きてほしくないこと両方をテストする
これはどちらもテストで予期せぬ動作が残るのを防ぐためにどっちも行います!!
そうすればエラー発生率の低下に繋がると思っています?
④境界値をテストする
例えば、パスワード登録の際に8文字以上を保存するとしましょう。
テストする際には、8文字以上保存されているかの確認と、逆に7文字以下のパスワードは保存されていないかテストをする必要があります。
よくバリデーションとかに使われるので、しっかりチェックする必要がありますね?可読性を考えつつ、適度にDRYする
DRYとはDon't Repeat Yourselfの略になります。
テストコードにおいて何よりも相手に伝わる分かりやすさが大切です。
分かりづらくなってテストの見落としが起きるよりマシだと思いませんか?最後に
本番環境前には必ずテストコードを書き、
ちゃんとメソッドが定義されているのか、
値がしっかり取得されているのかを確認してしっかりとしたアプリケーションを作っていきましょう!!!
- 投稿日:2019-05-30T07:49:21+09:00
Rails6 のちょい足しな新機能を試す27(perform_deliveries 編)
はじめに
Rails 6 に追加されそうな新機能を試す第27段。 今回は、
perform_deliveries編です。
perform_deliveriesの値が false(nil) のとき、log への出力メッセージがメールの送信をスキップしたことを示す内容に変わりました。今回は、User を登録するときに
perform_deliveriesの値を画面から指定できるようにする(メールを送信する、しないを指定できるようにする)ことにより、動作を確認します。Ruby 2.6.3, Rails 6.0.0.rc1 で確認しました。Rails 6.0.0.rc1 は
gem install rails --prereleaseでインストールできます。$ rails --version Rails 6.0.0.rc1Rails プロジェクトを作る
$ rails new rails6_0_0rc1 $ cd rails6_0_0rc1User の CRUD を作る
User の CRUD を作ります。
$ rails g scaffold User nameUserMailer を作る
メールを送信できるように、UserMailer を作ります。
$ rails g mailer UserMailerView を変更する
_form.html.erbにperform_deliveriesを true にするか false にするか指定するチェックボックスを追加します。app/views/users/_form.html.erb<%= form_with(model: user, local: true) do |form| %> ... <div class="field"> <%= label_tag :perform_deliveries %> <%= check_box_tag :perform_deliveries %> </div> ... <% end %>User controller を変更する
UsersController#createメソッドを変更し、DBへの保存が成功したら、 メールを送信するようにします。
このとき、perform_deliveriesの値をパラメータとしてUserMailerに渡すようにします。app/controllers/users_controller.rbclass UsersController < ApplicationController ... def create @user = User.new(user_params) respond_to do |format| if @user.save perform_deliveries = params[:perform_deliveries].to_i == 1 UserMailer.with(user: @user, perform_deliveries: perform_deliveries).created_email.deliver_later format.html { redirect_to @user, notice: 'User was successfully created.' } format.json { render :show, status: :created, location: @user } else format.html { render :new } format.json { render json: @user.errors, status: :unprocessable_entity } end end end ... end以下の2行が追加した部分になります。
perform_deliveries = params[:perform_deliveries].to_i == 1 UserMailer.with(user: @user, perform_deliveries: perform_deliveries).created_email.deliver_laterこのあとは、
UserMailer側を修正していきます。UserMailer クラスにメソッドを追加する
メールを送信する
created_emailメソッド とperform_deliveriesを設定するコールバックを追加します。app/mailers/user_mailer.rbclass UserMailer < ApplicationMailer after_action :set_perform_deliveries def created_email @user = params[:user] mail(to: 'admin@example.com', subject: 'user created') end private def set_perform_deliveries mail.perform_deliveries = params[:perform_deliveries] end endメールのテンプレートを作成する
今回は手抜きで テキストメールのみとし、 HTML メールは作成しません。
app/views/user_mailer/created_email.text.erbUser created ============= User <%= @user.name %> was createdメールをファイルに保存する
今回は実際にメールを送信せず、ファイルに保存するように設定を変更します。
config/environments/development.rbRails.application.configure do ... config.action_mailer.delivery_method = :file ... enddb:migrate を実行する
$ bin/rails db:create db:migraterails server を実行してブラウザからUserを登録する
User を登録するときに、
perform_deliveriesチェックボックスをチェックします。
ユーザーが無事、登録できれば、メールは、tmp/mails ディレクトリ内に保存されます。
このときログを確認するとlog/development.log... Delivered mail 5ce9f3619b8f4_2f32ae97743a3b0258ac@8baf8e28fbad.mail (6.1ms)とメールが送信されたことが記録されています。
今度は、
perform_deliveriesチェックボックスをチェックしないで User を登録します。
tmp/mails ディレクトリの admin@example.com ファイルには何も追加されません。
このときログを確認するとDeliveredとはならずにlog/development.log... Skipped delivery of mail 5ce9f380b1ad6_2f32ae97743a3b025957@8baf8e28fbad.mail as `perform_deliveries` is falseとメールの送信をスキップしたことがログに記録されます。 (←これが今回のちょい足し機能です。)
試したソース
試したソースは以下にあります。
https://github.com/suketa/rails6_0_0rc1/tree/try027_perform_deliveries参考情報
- 投稿日:2019-05-30T05:14:01+09:00
ReactやVueなどのJavascriptフレームワークからRailsの多対多モデルに対して、関連付けも含めて一気に作ってみた
こんにちは!@hairgaiです。
突然ですが、とあるTeamを作成するときにMemberを一緒に所属させたい!と思うことって一日に一回くらいありませんか?
今回は、それを実装するときにJavascriptからRailsへのパラメータで若干悩んだので、それを共有しようかなと思います。前提
よくある多対多です。
- Teamモデル
has_many :team_membershas_many :members, through: :team_members- TeamMemberモデル
belongs_to :teambelongs_to :member- Memberモデル
has_many :team_members: :destroyhas_many :teams, through: :team_membersReact 16.8.6、Rails 5.2.2
実装
Memberが数人いて何かTeamを作るときに、一度作成して後から所属させるのは面倒なので、当然ながら「Teamを作るときにMemberを所属させつつ作れたらいいのに」と思うと思います。
なので、フロントでTeamを作成するときに、既に登録済みのMemberを一覧で表示して、それを選択させることでパラメータを同時に送らせることにします。こんな感じですね。
また、Railsでは、モデルを作成するときに、その多対多関係にあるモデルを一緒に関連付けることが可能です。
なので、上記のように「Teamを作るときにMemberを所属させつつ作れたらいいのに」と思ったら、pry(main)> Member.create!(email: 'a@example.com') => #<Member:0x00007fb1498f04d8 id: 1, email: "a@example.com", # ... pry(main)> team = Team.create!(name: 'hoge', member_ids: [1]) => #<Team:0x00007fb142722860 id: 1, name: "hoge", # ... pry(main)> team.members => [#<Member:0x00007fb149951af8 id: 1, email: "a@example.com", # ... ]のように、
[モデル名]_idsというパラメータに配列を渡すと関連付けることが出来ます。
なので、フロント側でこのパラメータが渡ってくるようにURLパラメータを生成すれば良いということですね。パラメータ送りたい
ググると色々な記事が出てくる通り、JavascriptからURLにパラメータ用のクエリを乗っけるときは、qsを使いました。
qsは、Javascriptの連想配列(Hash)からURLパラメータを生成してくれるライブラリで、例えばimport qs from 'qs'; // or var qs = require('qs'); const params = { team: { name: 'hoge' }}; qs.stringify(params) // => 'team%5Bname%5D=hoge'という感じで使います。
なので(今回はパラメータの話なので解説しませんが)、フロント側でいい感じにパラメータを連想配列として生成します。// 実際はフレームワーク上でユーザの入力に合わせて作りますが、下記のような連想配列が生成されます。 const params = { team: { name: 'hoge', member_ids: [2, 3] } } qs.stringify(params) // => 'team%5Bname%5D=hoge&team%5Bmember_ids%5D%5B0%5D=2&team%5Bmember_ids%5D%5B1%5D=3'これをライブラリ等を用いてRailsに送ってみると…(axiosを使いました)
15: def update 16: binding.pry => 17: @team.update!(team_params) # ... [1] pry(#<Api::V1::TeamsController>)> params => <ActionController::Parameters {"team"=>{"id"=>"1", "name"=>"hoge", "member_ids"=>{"0"=>"1", "1"=>"2", "2"=>"3"}}, "format"=>"json", "controller"=>"api/v1/teams", "action"=>"update", "id"=>"1"} permitted: false>あれ?なんか変な形で送られてますね。
クエリの生成方法のオプションがあった
qsが生成したURLパラメータをデコードしてみると…team[name]=hoge&team[member_ids][0]=2&team[member_ids][1]=3ということで、
team[member_ids][0]=2&team[member_ids][1]=3のように指定されています。これをRailsでは"member_ids"=>{"0"=>"2", "1"=>"3"}と解釈してしまうようですね。(確かにHashっぽいです)
では、Railsではどう記述すればArrayと解釈されるのか、ということで、逆にArrayからクエリを生成してみましょう。pry(main)> { name: 'hoge', member_ids: [2, 3] }.to_query('team') => "team%5Bmember_ids%5D%5B%5D=2&team%5Bmember_ids%5D%5B%5D=3&team%5Bname%5D=hoge" # => team[member_ids][]=2&team[member_ids][]=3&team[name]=hoge順番は違いますが、若干指定の仕方が違いますね。Arrayのクエリでは、
[]のように数字を入れずに指定すれば良いようです。
現在はその数字の処理はqs側にまかせています。qsのGitHubをよく読んでみると…You may use the arrayFormat option to specify the format of the output array:
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' }) // 'a[0]=b&a[1]=c' qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' }) // 'a[]=b&a[]=c' qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }) // 'a=b&a=c' qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'comma' }) // 'a=b,c'とのことです。
なので、フロント側でURLパラメータを生成する際に、const params = { team: { name: 'hoge', member_ids: [2, 3] } } qs.stringify(params, { arrayFormat: 'brackets' }) // => 'team%5Bname%5D=hoge&team%5Bmember_ids%5D%5B%5D=2&team%5Bmember_ids%5D%5B%5D=3'とオプションを追加してみると…
[1] pry(#<Api::V1::TeamsController>)> params => <ActionController::Parameters {"team"=>{"id"=>"1", "name"=>"hoge", "member_ids"=>["2", "3"]}, "format"=>"json", "controller"=>"api/v1/teams", "action"=>"update", "id"=>"1"} permitted: false>出来ました!レコードも正常に作られます。
結論
Railsは、Railsが提供するWayに沿えば非常に強力なフレームワークですが、その分色々な決まりがあるので、こういった細かいところもキチンと調べていきたいですね。
この記事が誰かの参考になれば幸いです。
参考
ありがとうございました!
- 投稿日:2019-05-30T01:05:48+09:00
~勉強会~ヘルスケアwebサービスを自分で作る医者の日記
やっぱ勉強会に参加は有意義
1人でやると煮詰まるし、上級者や他の人の視点で、視界や開ける。rails チュートリアル4章まで終了
頑張ろう








