- 投稿日:2019-05-29T23:40:54+09:00
Rspecで突然謎のエラーが
circleCIで通常通り動いていたテストコードが突然動かなくなりましたが解決したのでその方法を書いていきます。
開発環境
Ruby 2.6.2
Rails 5.2.3
Docker 18.09.2
docker-compose 1.23.2今回発生したエラー
Selenium::WebDriver::Error::UnknownError: unknown error: session deleted because of page crash from unknown error: cannot determine loading status from tab crashed原因
エラーを調べたところ日本語での記事が少なく詳しくはわからなかったのですが、メモリ不足によってクラッシュしてしまうとのこと。
ブラウザのサイズを小さくすれば解決するとの記事を見て試してみたのですが、僕の場合小さくしても解決しませんでした。解決方法
rails_helperのchromeOptionsのところに
--no-sandbox
と--disable-dev-shm-usage
というargumentsを追加してください。--disable-dev-shm-usage
と書くことでChromeは/tmpディレクトリを代わりに使用するようになるみたいです。メモリの代わりにディスクが使用されるので、実行が遅くなる場合があるみたいですがそんなに変わってない気がします。spec/rails_helper.rbCapybara.register_driver :selenium_remote do |app| driver = Capybara::Selenium::Driver.new( app, browser: :remote, desired_capabilities: Selenium::WebDriver::Remote::Capabilities.chrome( chromeOptions: { args: [ 'window-size=500,500', #念の為サイズも小さく 'headless', '--no-sandbox', # crush回避 '--disable-dev-shm-usage' # crush回避 ] } ), url: 'http://chrome:4444/wd/hub', ) endこれで解決すると思います。
もし間違いがあれば訂正お願いいたします。
参考サイト
https://qiita.com/jb-vasseur/items/d3aa33e08ebba3b9231e
https://stackoverflow.com/questions/53902507/unknown-error-session-deleted-because-of-page-crash-from-unknown-error-cannot
- 投稿日:2019-05-29T23:30:11+09:00
【1分で読める】プログラミングスクールに通って1ヶ月で学んだこと(できるようになったこと)、感じたこと
WEBエンジニアに転向するため2019年5月から某プログラミングスクールに通っています。執筆時点で約1ヶ月経過したので、学んだことやら、感じたことやらを書き記します。スクール自体はあと数ヶ月続きます。
プログラミングスクールに通うか迷っている人の参考になればと思います。(進捗はあくまでも自分の場合です!周りを見ると、進捗は本当にバラバラ)
なんでプログラミングスクールに入ったのかーとか諸々は卒業後にまたまとめて書こうかなと!
スペックとか
- 言語:Ruby
- 年齢:29
- 性別:男
- 5月からプログラミングスクールに通ってるけど、4月15日から事前に学習をスタート
- プログラミング歴はなし!学生時代に授業でやったくらい
- 勉強時間は7〜10時間/日くらい。頭が疲れたら、基本的にやらない感じ
学んだこと(できるようになったこと)
Ruby(Rails)を使ってtwitter,facebook,instagramのようなアプリは作れるようになった!!!(コードのコピペじゃない!)
投稿機能はもちろん、投稿のお気に入り機能、ユーザのフォローフォロワー機能を実装したり、LINEみたいなメッセージのやりとり機能を実装したりもできるようになった。Ajaxを使ったりも。
さらにherokuを使えば簡単に全世界に公開もできる。すごすぎるぞ、自分!!
デザインとか、サーバのこととか、セキュリティとか考えるとまだまだかもしれないけど、1ヶ月半くらいで、railsアプリ開発の基本的なことはできるようになったのかなと勝手に思ってます。
あとは、リファクタリングとかコーディング規約を守るとか頑張らないとなーって感じ。
(本当はもっとあるんだろうな…)感じたこと
- 想像していたものがブラウザ上で形になるのは楽しい!嬉しい!
- 上っ面のところしか理解できていない感がとてもある
- 一人で黙々とやっていたらこんなにハイペース?で勉強を進められないだろうなと実感
→同期、メンターの存在のおかげで頑張ろって思えるし、分からないことも教えあえる。また、一人じゃ気付けなさそうなことも会話から気づきを得ることができる。感謝感謝。
一人ならダラダラと勉強しちゃいそう。。これからのこと
- サーバ(AWS)のことや、フロント(Vue.js)のことを学んでいくぞい!
- RubyやRailsも知れば知るほど、新たな疑問が生まれるのでもっともっと理解を深めていくぞい!
- 就活も始めるぞい!
乞うご期待!
- 投稿日:2019-05-29T23:26:23+09:00
GIF画像検索してブラウザでLGTM画像生成とアップロードをしてMarkdown記法でコピーできるツール作った話
今回の開発でわかったこと&この記事で言いたいこと
JavaScript
はすごい。
firebase
もすごい。
個人開発なら、なんでもかんでも自分で作ろうとしないこと。
世の中の既存のサービスにも目を向けること。
GIFバイナリは面白かった。
いやまじでfirebase
はすごい。ツール開発経緯
この記事に触発された。
ちょっとそこのあなた! 自分だけのオリジナルLGTMをチームで使ってみませんか?
そうだよね!LGTM画像って動く方がいいよね!めっちゃわかる
でもLGTMって書かれていないGIF画像って素っ気ないよね!
じゃGIF画像検索できて、それをすぐにLGTM画像に生成してMarkdown形式でコピペしたい!!
何ができたのか
できたツールがこれ。
Chrome
とFirefox
でしか確認していません。。大まかにどうやっているのか
- GIF画像をバイナリで取得する。
- バイナリを分析して一枚の画像ごとに分ける。
- LGTMの文字と一枚の画像をcanvasに描画していく。
- 全部くっつけてLGTM GIF画像が出来上がる。
- サーバーにLGTM画像をアップロードしURL取得して終わり。
サーバーでは画像を保存することしかしていません。
ブラウザのみでGIF検索、LGTM画像生成、アップロード、Markdown記法クリップボードにコピーをしています。
具体的にどうやってるのか
- GIPHY APIの
Search API
でGIF画像を検索する。- クリックされたら幅200pxのGIF画像を
arraybuffer
形式でファイルを取得する。- それをomggif.jsを使用して一枚ずつの画像にする。
- gif.js で一枚になった画像とLGTM文字を
canvas
にdraw
する。- GIF画像の枚数分、LGTM文字付きの画像をgif.jsで
addFrame
したらrender
する。- gif.js で
render
すると完成したGIF画像がblob
に変換される。blob
をfirebase storage
にそのままアップロードする。- 最後に
firebase storage
のdownloadUrl
を取得してクリップボードに保存する。これを実装するまでの物語
目的:GIF画像検索してそれをLGTM画像にして簡単にMarkdown記法でコピーしてGithubに貼り付けたい!
よく
Ruby on Rails
使っていたのでrmagick
とかいう画像編集gemで実装してみる。
できたが、実装が悪いのかGIF画像生成に時間がかかった。
これではたくさん画像生成するとなると遅くなってしまう。。
うーむ。
もっと早く画像編集する方法を探る。
Python
とOpenCV
に出会う。
早い気がするが、結局画像生成に時間がかかる。
うーむ。
もっともっと早く画像編集したい!
Halideに出会う。
少し触って、「あれ、なにしようとしてたんだっけ??」ってなる。--数年後--
ちょっとそこのあなた! 自分だけのオリジナルLGTMをチームで使ってみませんか?を見る。
そうだよな。LGTM画像ってLGTMの文字が入ってこそだよなぁ。
うーむ。--数日後--
そっか、使ってもらう人に画像生成してもらえばサーバーの負荷減るなー。
今に至る。完
ライセンス
https://github.com/deanm/omggif MIT License
https://github.com/jnordberg/gif.js MIT License
- 投稿日:2019-05-29T22:53:44+09:00
Ruby/Ruby on rails/MysqlをDockerで環境構築
DockerでRuby/Ruby on rails/mysqlの環境構築からデプロイまでできたのでメモしておきます。
(1)Dockerfile作成
DockerfileFROM ruby:2.5.3 RUN apt-get update -qq && \ apt-get install -y build-essential \ libpq-dev \ nodejs RUN mkdir /app_name ENV APP_ROOT /app_name WORKDIR $APP_ROOT ADD ./Gemfile $APP_ROOT/Gemfile ADD ./Gemfile.lock $APP_ROOT/Gemfile.lock RUN bundle install ADD . $APP_ROOT(2)docker-compose.yml作成
docker-compose.ymlversion: '3' services: db: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: root ports: - "3306:3306" web: build: . command: bundle exec rails s -p 3000 -b '0.0.0.0' volumes: - .:/app_name ports: - "3000:3000" links: - db(3)Gemfile作成
Gemfilesource 'https://rubygems.org' gem 'rails', '5.2.2'Gemfile.lockも作成
$ touch Gemfile.lock(4)新しいアプリを作成
$ docker-compose run web rails new アプリ名 . --force --database=mysql --skip-bundledatabese.ymlを編集
database.ymldefault: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: password host: dbGemfileをbundle install
$ docker-compose run web bundle install(5)コンテナをビルドと起動
$ docker-compose build # コンテナをビルド $ docker-compose up # コンテナの一斉起動※bundle installの後にbuildする
(6)DB作成
$ docker-compose run web rails db:createDBを作らないとエラーが出る
DBを作成後localhost:3000で初期画面が表示される!
()Herokuでデプロイ
herokuの登録,heroku cliはインストール済みとする
Herokuにアプリ作成
$ heroku createデータベースをMySQLに変更
$ heroku addons:add cleardbClearDBアドオンとは,ClearDBというデータベースサービスが提供している,MySQLを使うためのもの。
$ heroku config | grep CLEARDB_DATABASE_URL
mysql:// 〜 reconnect=true
がデータベース情報
mysql
の部分をmysql2
に変更環境変数を変更
$ heroku config:set DATABASE_URL=mysql2:// 〜 reconnect=true //先ほどのデータベース情報全部$ git add . $ git commit -m "update for upload to heroku"アプリをデプロイ
$ git push heroku masterマイグレーションファイル作成
$ heroku run rake db:migrate参考
- 投稿日:2019-05-29T22:28:59+09:00
RailsでのセッションとCookieについて
Railsチュートリアルを進めていてセッションとCookieについて整理したかったので自分用メモとして書いた。
セッション
WebアプリケーションではブラウザからサーバへHTTPリクエストを送り、HTTPレスポンスを受け取って画面表示を行う。しかしHTPPはステートレスなプロトコルであるため、同じユーザーから送られた1つ目のリクエストから2つ目のリクエストの情報を引き継ぐことができない。そのためセッションを用いることで、1つのブラウザから連続して送られている一連のリクエスト間で状態を共有できるようにしている。
Railsではsessionメソッドを使うことで実現できる。sessionはハッシュのように扱うことができ、セッションにデータを入れるには任意のキーを指定して値を格納する。
session[:user_id] = @user.id
値を取り出すには下記の通り書く。
@user.id = session[:user_id]
Cookie
複数のリクエストの間で共有したい状態をブラウザ側に保存する仕組み。クライアントが情報を持っているのでブラウザを閉じても破棄されない。また暗号化しないと簡単に読み取られる。ログイン情報をセッションのみで扱うとブラウザを閉じるたびにログインしないといけなくなる。そのためCookieにもログイン情報を持たせてしまい、ブラウザを閉じても状態を保持させるという使い方が一般的。Railsではcookiesメソッドを使ってこの機能を実現する。
RailsでのセッションとCookieの関係
Railsのセッションの仕組みの一部はCookieによって実現されている。ブラウザを閉じると破棄されるようなCookieという形で暗号化されたセッション情報をクライアント側に保存するという仕組み。またRailsではセッションデータの保管場所を複数の選択肢から選ぶことができるが、デフォルトでCookieになっている。そのためブラウザ側で対応するCookieを消せば、セッションはリセットされることになる。
- 投稿日:2019-05-29T18:29:11+09:00
サービスクラス(Trailblazerも含めて)での実装がときめかない
はじめに
私のボスが「Trailblazerを使い、Railsのモデルの肥大化問題からサヨナラする」の記事をSlackで共有してきました。それを読んだエンジニア歴が浅い新人がプロジェクトに導入すべきかどうか悩んでいます。
私は直感的に思いました。「ダメだ。私たちにはまだ早い! いきなりTrailblazerでサービスクラスなんか書いていたら、WEBアプリケーションの設計の美しさに気づくことなく一生を終えてしまう。」
なお、ここでいうサービスクラスというのは、「俺が悪かった。素直に間違いを認めるから、もうサービスクラスとか作るのは止めてくれ」の記事にあるような、すべてのビジネスロジックを手続き型プログラミングのように書く実装を意味しています。そして、私にとっては、流行りのTrailblazerのOperationでさえも、そのようなサービスクラスをきれいに整えただけ1のように見えて、ときめきを感じないのです。
Trailblazerについての人気記事のコードを見てみる
先ほどの記事のようなサービスクラスのコードは、日々Qiitaを読んでいるような皆さんにとってはうんざりでしょう。
一方、そのサービスクラスを進化させることによってFat Model問題を解決しようとしているTrailblazerのコードについてはどのような印象をお持ちでしょうか?
Operationのサンプルコード
はじめにで出てきたTrailblazerについての人気記事「Trailblazerを使い、Railsのモデルの肥大化問題からサヨナラする」で書かれているコードを引用しながら見ていきましょう。
コントローラー
まず、コントローラーは以下のようになっています。
def create # ユーザー認証機能をDeviseで作った場合、ユーザーはcurrent_userで取得できる run Post::Create, params[:post], current_user: current_user do # バリデーションに成功したら(全Stepが成功したら)こちらに入る redirect_to action: :index and return end # バリデーションに失敗したら(いずれかのStepが失敗したら)こちらにくる render :new end注目のサービスクラス
そして、こちらがサービスクラス(Operation)のコードです。コメント部分はすべて私が書きました。注目すべきは、フォームのバリデーションなども含めたすべてのビジネスロジックが、まるで手続き型プログラミングのように書かれていることです。そして、それらのステップの記述には
step
と呼ばれるDSLが使われています。app/concepts/post/operation/create.rb# Operationというのはサービスクラスのこと class Post::Create < Trailblazer::Operation # DSLを使う extend Contract::DSL # Postモデル用のフォームオブジェクト(Reformと呼ばれる)を記述する。 # Reformではモデル単位ではなく、フォーム単位でバリデーションを行う。 contract do model "post" property :title, validates: { presence: true, length: { maximum: 100 } } property :body, validates: { presence: true, length: { maximum: 2000 } } end # ここのDSLが特徴的。ビジネスロジックをステップごとに記述する。 step Model(Post, :new) # Postモデルを生成 step :assign_current_user! # post.user = current_user と同等 step Contract::Build() # フォームオブジェクト(Reform)をビルド step Contract::Validate() # フォームオブジェクト(Reform)をバリデート step Contract::Persist() # フォームオブジェクト(Reform)を使ってモデルを保存 step :notify_author! # ユーザーへの通知 def assign_current_user!(options) post = options["model"] post.user = options["current_user"] end def notify_author!(options) # ユーザーへの通知処理 end endその他のコード
フォームオブジェクトである
Contract
のコードは、元記事をご覧ください。フォームやモデルのバリデーションだけでなく、Strong Parametersの処理もやってくれます。感想: これが主流になると悲しい...
TrailblazerのOperationでのサービスクラスは、とてもすっきり書かれていて、何をやっているのかがわかりやすいです。プログラマーじゃなくても概要を理解できるレベルだと思います。
しかしですよ! MVCモデルのWEBアプリケーションフレームワークの集大成であり、WEBアプリケーション設計におけるノウハウの塊であるRuby on Railsのクールな機能がほとんど使われていないじゃないですか? 私たちが好きなのはオブジェクト指向ですよ、デザインパターンですよ、そして、オブジェクト同士がメッセージを送り合うコールバックを使う設計ですよ! 手続き型プログラミングみたいに書いてんじゃないよ(涙)
さらに、テストケースを書くならまだしも、一番大切なメインのコードを書くのに独自言語(DSL)を使うのですか! Ruby on Rails作者のDavid Heinemeier Hansson氏は美しいコードを書けるからRubyを選んだと言っています。その美しいコードを書けるRubyを捨ててまでやるのですか(涙)
Rails標準の機能を使って書いてみる
Trailblazerとの比較のために、同じことをRails標準の機能を使って書いてみます。
コントローラー
まずはコントローラーです。Railsの標準で書いた場合、コントローラーのコード量はTrailblazerと比べて少し増えてしまいます。ただ、これから述べるようにモデルをしっかりと書けば、コントローラーが肥大化することはありません。
def create form = NewPostForm.new(post_params) # ユーザー認証機能をDeviseで作った場合、ユーザーはcurrent_userで取得できる form.user = current_user # ここでバリデーション、モデルの保存、ユーザーへの通知が行われる if form.save redirect_to action: :index and return end render :new end def post_params params.require(:post).permit(:title, :body) end注目のモデル
そして、注目のモデルです。Railsではコールバックの仕組みが積極的に使われます。ここでは、そのコールバックと、それをバリデーションの目的に特化したその名もバリデーションという仕組みを見ていきます。
コールバック
まずはコールバックです。
普通に書く場合
app/models/post.rbclass Post < ApplicationRecord after_save :notify_author # ... def notify_author # ユーザーへの通知処理 end endモデルの保存後に
after_save
で定義したメソッドがコールバックされます。ここでは、投稿(Post)が完了したら、ユーザーにメールなどで通知を行うようになっています。つまり、ユーザーモデルを保存するだけで、必要なメソッドが必ず実行されるわけです。サービスクラスに書いた場合、コードをコピペして新しいサービスクラスを作ったときに、必要な処理もうっかり消してしまうことがあります。モデルに書いておくとそんな心配もありません。
Fat Model対策をする場合
モジュール
もしモデルの肥大化が気になる場合は、Railsのモジュールの仕組みを使って、モデルを分割することができます。
app/models/post.rbclass Post < ApplicationRecord include PostNotificator # モデルにはこれを書くだけ # ... endapp/models/concerns/post_notificator.rb# 機能をモジュールとして、別のファイルで定義する module PostNotificator extend ActiveSupport::Concern included do after_save :notify_author end def notify_author # ユーザーへの通知処理 end end元のコードでは、モデルを保存した後の処理はユーザーへの通知だけでしたが、他にも、たとえば「モデルを保存した後にKVSの値も更新する」などの処理も、モデルに
include KVSUpdater
と記述して、KVSUpdater
モジュールを定義すれば、Postモデルにすっきりと機能を追加することができます。app/models/post.rbclass Post < ApplicationRecord include PostNotificator include RedisUpdater # モデルに機能を追加 # ... endapp/models/concerns/kvs_updater.rbmodule KVSUpdater extend ActiveSupport::Concern included do after_save :update_kvs end def update_kvs # ここにKVSを更新するコード end endデリゲート
デリゲートの仕組みを使って、特定の処理を別クラスに移譲させることもできます。
app/models/post.rbclass Post < ApplicationRecord # notify_authorメソッドの処理を移譲する delegate :notify_author, to: :notify def notify PostNotificator.new(self).notify end # ... endバリデーション
コールバックに続いて、バリデーションです。バリデーションの使い方は、カラムのフォーマット合っているかというようなシンプルものだけではありません。外部APIを呼び出して、その結果によってはモデルを保存しないようなこともバリデーションクラスに書けばすっきりします。
app/models/post.rbclass Post < ApplicationRecord # モデルの保存前(バリデート時)にコールバックされる validates_with SubscriptionValidator # ... endapp/validators/subscription.rbclass SubsctiptionValidator < ActiveModel::Validator def validate(record) # このユーザーが課金しているかどうかを外部APIを使って調べるなどの複雑な処理 end endその他のコード
フォームオブジェクトであるTrailblazerのReformは、モデル単位ではなくフォーム単位でバリデーションを行うのですが、Rails標準のActiveModelでも同じようなことができます。
ただ、フォームオブジェクトに関してはReformの方が便利で使いやすいと思います。簡潔に書けるだけでなく、Strong Parametersの処理までやってくれます。元記事のContract(Reform)をご覧ください。
本記事の趣旨からは外れますが、ActiveModelを使ったフォームオブジェクトの実装も書いておきます。
app/forms/new_post_form.rbclass NewPostForm include ActiveModel::Model include ActiveModel::Attributes # Rails5.1以前ではActiveModelAttributesのgemを使う # モデルにあるアトリビュート def self.attributes [:name, :body, :user] end attr_accessor *self.attributes # モデルにないアトリビュート attribute :privacy_policy, :boolean, default: false # バリデーション validates :privacy_policy, acceptance: true def to_model Post.new(to_hash) end def save return false unless valid? to_model.save end def to_hash self.class.attributes.inject({}) do |hash, key| hash.merge({ key => self.send(key) }) end end end上記の実装はとても大変な感じがしますね。ActiveModelをTrailblazerのReform並に便利にするには、たくさんハックする必要があります。以下のURLを参考にすれば、
self.attributes
やto_hash
のあたりが各フォーム間で共通化できると思います。
ActiveModel attributes - Stack Overflow感想: やっぱりRailsはクール!
ActiveModelのコードを除き、上記のモデルの書き方はやっぱりクールです。必要なコールバックを定義して、そこをトリガーにして動かすのです。
コントローラーの主な処理は、渡されてきたパラメーターでモデルを作成/更新/破棄することだと思います。これに加えて、モデルを扱う前後でいくつかの処理が必要となります。Railsのモデル(ActiveRecord)では、その前後の処理をコールバックを使うことでロジックを分けて書けるようになっているのです。
コールバックの種類はこちらを参照してください。
Active Record コールバック - Rails ガイドサービスクラスを作った方がよいケースもある?
ここまで書いておいてアレですが、サービスクラスを作った方がいいケースがあることは認めます。代表的なものはバッチ処理でしょう。
ただ、よく(コントローラーの1つのアクションで)複数モデルを扱う場合もサービスクラスが向いているんじゃないかという意見も聞きますが、複数モデル間でリレーションが張られていればやはりモデルだけで済みます。
accepts_nested_attributes_for
を定義すれば、1つのモデルを更新するコードを書くだけで他の関連付けられたモデルも更新されます。もちろん、その際、それぞれのモデルのコールバックも呼ばれます。まとめ
特別なケースを除けば、サービスクラスを作るとおもしろくなくなるという私見から、私はTrailbrazerはあまり使いたくないなぁ...と思います。ただ、時代の流れには逆らえませんし、もしかすると食わず嫌いなだけかもしれませんので、今後使う機会があれば、ぜひ一度がっつりとやってみたいとも思っています。
もちろん、ソースコードをきれいに整えて可読性、凝縮性を上げることが何より大切なのは理解しています。 ↩
- 投稿日:2019-05-29T16:31:55+09:00
【Rails】ネストされたcontroller宛てのform_withの書き方
namespaceでnestされたcontroller(Admin::Userなど)のアクション宛てformを
form_with
で記述したい場合の雛形になります。書き方
◆ new → create
new.html.erbのviewから
Admin::UsersController
のcreate
アクションへ送りたい場合、htmlレベルでは<form action="/admin/users" method="post" > <input type="text" name="user[name]"> </form>こうなっていてほしいが、form_withではどう記述すればよいか?
① model: を使う方法
model:
で@userを指定し、url:
でpathを指定します。new.html.erb<%= form_with model: @user, url: admin_users_path, local: true do |f| %> <%= f.text_field :name %> <% end %>② model: を使わない方法
scope:
で:user
を指定し、url:
でpathを指定します。
scope: :user
によってパラメーターのuser[]
を生成するようです。new.html.erb<%= form_with scope: :user, url: admin_users_path, local: true do |f| %> <%= f.text_field :name %> <% end %>(ちなみに、
scope: :user
をなくすと)new.html.erb<%= form_with url: admin_users_path, local: true do |f| %> <%= f.text_field :name %> <% end %>↓htmlレベルでは
<form action="/admin/users" method="post" > <input type="text" name="name"> </form>
user[name]
ではなく、name
になっています。◆ edit → update
同様に、edit.html.erbから
Admin::UsersController
のupdate
アクションへ送りたい場合、htmlレベルでは<form action="/admin/users/3" method="post"><input type="hidden" name="_method" value="patch" /> <input type="text" name="user[name]"> </form>こんな感じになっていてほしいが、form_withではどう記述すればよいか?
① model: を使う方法
model:
で@userを指定し、url:
でpathを指定します。edit.html.erb<%= form_with model: @user, url: admin_user_path, local: true do |f| %> <%= f.text_field :name %> <% end %>② model: を使わない方法
scope:
で:user
を指定し、url:
でpath、method:
で:patch
を指定します。edit.html.erb<%= form_with scope: :user, url: admin_user_path, method: :patch, local: true do |f| %> <%= f.text_field :name %> <% end %>(ちなみに、
method: :patch
をなくすと)edit.html.erb<%= form_with scope: :user, url: admin_user_path, local: true do |f| %> <%= f.text_field :name %> <% end %>↓htmlレベルでは
<form action="/admin/users/3" method="post"> <input type="text" name="user[name]"> </form>
<input type="hidden" name="_method" value="patch" />
が無くなりました。
これにより「htmlメソッドはpatchという体裁で送っているよ」というメッセージが消えたので、railsサーバーはPOSTが届いたと認識します。(詳しくはこちら)
methodがPOST、pathがadmin_user_pathの組み合わせは存在しないので、Routing Errorになるはずです。結論
form_withでは
model:
を使えば空気を読んで自動翻訳くれるのでかなり楽。
しかし、nestされている状態とpathまでは空気読みきれないので、mode:
とurl:
のセットを使えばOK.
- 投稿日:2019-05-29T16:04:24+09:00
gem 'devise'
gemfile.rbgem 'devise'terminal.rb$ bundle install $ rails generate devise:installdevelopment.rbconfig.action_mailer.default_url_options = { host: 'localhost', port: 3000 }terminal.rails g devise モデル名create db/migrate/20190529070217_devise_create_users.rb
このようにマイグレーションファイルが作成されるのでこれをdb:migrateして反映させる
== 20190529070217 DeviseCreateUsers: migrating ================================
-- create_table(:users)
-> 0.0015s
-- add_index(:users, :email, {:unique=>true})
-> 0.0008s
-- add_index(:users, :reset_password_token, {:unique=>true})
-> 0.0009s
== 20190529070217 DeviseCreateUsers: migrated (0.0035s) =======================*localhost3000/users/sign_up
- 投稿日:2019-05-29T16:04:24+09:00
gem 'devise' デバイス実装の流れ自分メモ
まずデータベース作成した後
gemfile.rbgem 'devise'terminal.rb$ bundle install $ rails generate devise:install$ rails g controller home(このタイミングでコントローラーを作成した)
development.rbconfig.action_mailer.default_url_options = { host: 'localhost', port: 3000 }terminal.rails g devise モデル名create db/migrate/20190529070217_devise_create_users.rb
このようにマイグレーションファイルが作成されるのでこれをdb:migrateして反映させる
== 20190529070217 DeviseCreateUsers: migrating ================================
-- create_table(:users)
-> 0.0015s
-- add_index(:users, :email, {:unique=>true})
-> 0.0008s
-- add_index(:users, :reset_password_token, {:unique=>true})
-> 0.0009s
== 20190529070217 DeviseCreateUsers: migrated (0.0035s) =======================*localhost3000/users/sign_upしてみる
application_controller.rbbefore_action :authenticate_user!認証していないとアクセスを弾くコマンド
ただトップページだけは認証されていなくとも表示したいので、
home_controller.rbclass HomeController < ApplicationController skip_before_action :authenticate_user! def index end endとしておく。
ここからtaskのモデルを作っていこうと思う
- 投稿日:2019-05-29T14:51:20+09:00
railsでコメント機能を作ろう
コメント機能の実装
投稿データ =>
Image model
コメント =>Comment model
投稿フォームは投稿一覧に作成する(images#show)
Model作成
$ rails g model Comment content:string image:references
content
=> コメント格納用image
=> imageモデルと関連付けるため(models/comment.rb)
belongs_to :image validates :content, presence: true
belongs_to
=> imageモデルに属している(自動記入)precense: true
=> 空白を不可とする(models/image.rb)
has_many :comments, dependent: :destoroy
has_many
=> たくさんのコメントを持つことができる(1対多)dependent: :destroy
=> imageが削除されたらcommentsも削除されるRoutes設定
resources :images do resouces :comments, only: [:create, :destroy] end生成されるURL
create =>/images/:image_id/comments
destroy =>/images/:image_id/comment/:id
image_id
をControllerで活用- どの投稿の、どのコメントかを判別する必要がるためこのようになる
Controller作成
$ rails g controller comments create destroy
create
とdestroy
の機能を指定する(Viewは削除)private def content_params params.require(:comment).permit(:content) end
- ストロングパラメーターを設定する
def create image = Image.find(params[:image_id]) @comment = image.comments.build(comment_params) if @comment.save flash[:success] = "コメントしました" redirect_back(fallback_location: image_url(image.id)) else flash[:danger] = "コメントできません" redirect_back(fallback_location: image_url(image.id)) end end
params[:image_id]
=> URLから取得する(ルーティングで設定)redirect_back(fallback_location: image_url(image.id))
=> 直前のURLにリダイレクト(showで投稿しshowに戻る)def destroy image = Image.find(params[:image_id]) @comment = image.comments.find(params[:id]) @comment.destroy redirect_back(fallback_location: image_path(image) end
image.comments.find(params[:id])
=> 取得したimageのコメントを:idで探すView作成
投稿フォーム
<%= form_with(model: [@image, @comment], local: true) do |f| %> <%= f.text_field :content %> <%= f.submit "コメントする", class: "btn btn-primary" %> <% end %>
model: [@image, @comment]
=> commentがimageに紐づいているモデルのため、配列にして記載する必要がある#ImageControllerで定義 def show @image = Image.find(params[:id]) @comment = @image.comments.build end削除ボタン
<% link_to "DELETE", image_comment_path(image_id: @image, id: comment.id), method: :delete %>
image_comment_path
=> 必要な引数を記載 (/images/:image_id/comment/:id)
- 投稿日:2019-05-29T13:17:13+09:00
RailsのService層のクラスをauto_loadpathに含める
環境
- Ruby 2.4.2
- Rails 5.1.4
やりたいこと
app - services/ - neko.rb - - utils/ - - - hoge.rb - - users/ - - - test.rbみたいな
serivces
ディレクトリ構成があるとして、全てのディレクトリ内のファイルをオートロードパスに含めたいが、デフォルトでは出来ないので、その方法について記載します。デフォルトでは、
services
ディレクトリの直下のみがオートロードパスの対象となっています。services.rbを編集
config/initializers
ディレクトリ内にserices.rb
を作成します(自分の環境にはありませんでした)。
services.rb
を以下のようにします。
rb
Dir.glob("app/services/**/*.rb") do |file|
require_dependency Rails.root.join(file)
end
これで全てのファイルが対象となっているかと思います。
- 投稿日:2019-05-29T12:55:38+09:00
【Haml】条件(if)に応じてClassを変更させる方法
例えば、Eventというモデルの編集ページにおいて、編集不可の要素に対して付与する
is-disabled
というクラスを用意したとします。.event-panel.is-disabledEventがeditable?でないときのみ
is-disabled
を付与する場合は以下のように書きます。- event = @event .event-panel{class:('is-disabled' unless event.editable?)}
- 投稿日:2019-05-29T11:54:44+09:00
Rails herokuデプロイ時のエラーについて
rails初学者です。
herokuにアプリをデプロイしたところ、特定のページでのみエラーとなります。
試行錯誤を繰り返したのですが、自力での解決が難しいため質問させてください。下記、「heroku logs -t」でのエラー文です。
PG::DatatypeMismatch: ERROR: argument of WHERE must be type boolean, not type integer LINE 1: SELECT "users".* FROM "users" WHERE (1) LIMIT $1 : SELECT "users".* FROM "users" WHERE (1) LIMIT $1): app/controllers/posts_controller.rb:89:in `follows'上記の文面から、postsコントローラーのfollowsアクションで、「WHERE句はinteger型ではなくboolean型ですよ。」との内容だと思うのですが...
修正が必要と思われる箇所はこちらです↓posts_controller.rbdef follows @user = User.find_by(params[:id]) #ここが89行目 @follows = Follow.where(follower_id: @user.id) @posts = [] if @follows.present? @follows.each do |follow| posts = Post.where(user_id: follow.followed_id).order(updated_at: :desc) @posts.concat(posts) end @posts.sort_by!{|post| post.created_at}.reverse! if @posts.nil? flash[:notice]="まだ投稿がありません…" redirect_to("/posts/index") end else flash[:notice]="誰かをフォローしてみましょう!" redirect_to("/posts/index") end説明に不足・見当違いなどございましたらご指摘いただければ幸いです。
ご回答のほど、よろしくお願い致します!
- 投稿日:2019-05-29T11:01:11+09:00
みなさんが必ず使う検索機能について・・・
みなさんこんにちは☀️
検索・・・
それは誰でもしたことあるやつです。インターネットで調べる時、メルカリで欲しいものを検索したい時など。
現代ではスマートフォンによっていつでもどこでも検索することができます。
僕がプログラミング学習しているときでも、
検索を常にしています。
今日はその検索機能をRubyではどう書くのかみていきたいと思います。検索機能
RubyではLIKE旬を利用します。
LIKE旬とは、曖昧な文字列を検索することができることです。
これは、Whereメソッドと一緒に使います。実行サンプルを置いておきます。
aから始まるタイトル
where(‘title LIKE(?)’, “a%”)bで終わるタイトル
where(‘title LIKE(?)’, “%b”)cが含まれるタイトル
where(‘title LIKE(?)’, “%c%”)dで始まる2文字のタイトル
where(‘title LIKE(?)’, “d_”)eで終わる2文字のタイトル
where(‘title LIKE(?)’, “_e”)
- 投稿日:2019-05-29T11:01:11+09:00
【スクール生】11日目:みなさんが必ず使う検索機能について
みなさんこんにちは☀️
検索・・・
それは誰でもしたことあるやつです。インターネットで調べる時、メルカリで欲しいものを検索したい時など。
現代ではスマートフォンによっていつでもどこでも検索することができます。
僕がプログラミング学習しているときでも、
検索を常にしています。
今日はその検索機能をRubyではどう書くのかみていきたいと思います。検索機能
RubyではLIKE旬を利用します。
LIKE旬とは、曖昧な文字列を検索することができることです。
これは、Whereメソッドと一緒に使います。実行サンプルを置いておきます。
aから始まるタイトル
where(‘title LIKE(?)’, “a%”)bで終わるタイトル
where(‘title LIKE(?)’, “%b”)cが含まれるタイトル
where(‘title LIKE(?)’, “%c%”)dで始まる2文字のタイトル
where(‘title LIKE(?)’, “d_”)eで終わる2文字のタイトル
where(‘title LIKE(?)’, “_e”)
- 投稿日:2019-05-29T10:45:28+09:00
Rails6 のちょい足しな新機能を試す26(MySQL utf8mb4 編)
はじめに
Rails 6 に追加されそうな新機能を試す第26段。 今回は、
MySQL の utf8mb4
編です。
Rails 6.0.0 では、 rails new -d mysql を実行(データベースにMySQLを指定)したときに encoding が utf8mb4 になります。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 プロジェクトを作る
-d mysql
を指定します。$ rails new rails6_0_0rc1 -d mysql $ cd rails6_0_0rc1database.yml を確認する
yda database.yml を確認すると、 encoding が utf8mb4 になっていることがわかります。
config/database.ymldefault: &default adapter: mysql2 encoding: utf8mb4 ...User の CRUD を作る
utf8mb4 を試すために、実際に User の CRUD を作ります。
$ bin/rails g scaffold User name
データベースの migration
$ bin/rails db:create db:migrate
rails server
を実行してユーザーを登録する
bin/rails s
を実行して、 http://localhost:3000/users/new にアクセスして User を登録します。
このとき name に?と?
を入力します。$ bin/rails s
Rails 6.0.0rc1 では無事に登録できました。
Rails 5.2.3 ではエラーになります。
蛇足ですが
name
に絵文字はないだろうとか思ったりしましたが、そこはスルーで。
rails g scaffold Book title
とかにした方がまだ良かったかもと思わないでもないです...。スクリーンショットの絵文字とこの記事の絵文字の見え方が違うのは、多分 OS の(フォント?)の違いです。
スクリーンショットは Ubuntu 16.04 の Chrome で取ったものです。試したソース
試したソースは以下にあります。
https://github.com/suketa/rails6_0_0rc1/tree/try026_mysql_utf8mb4参考情報
- 投稿日:2019-05-29T01:48:11+09:00
color_fieldすご
Articleモデルカラムに色を登録するカラム
color_1
とcolor_2
を追加するcolor_field
jqueryのカラーピッカーとかを使って色を登録しようかなんて思っていたところRailsが提供している
color_field
というものを見つけた。これで色を選択できる!こんなかんじ↓
_form.html.erb<tr> <th scope="row">吹き出し1</th> <td><%= f.text_field :balloon_1, size: "90x10" %> <%= f.color_field :color_1 %> </td> </tr> <tr> <th scope="row">吹き出し2</th> <td><%= f.text_field :balloon_2, size: "90x10" %> <%= f.color_field :color_2 %> </td> </tr>色の表示
<div class = "balloon1" style="background-color:<%= @article_.color_1 %>"><div class = "balloon1" style="background-color:#b8e1f5">
- 投稿日:2019-05-29T01:48:11+09:00
color_fieldとインラインでの擬似要素の表示について
吹き出しの背景色をその時の気分で色を決めたい!
変更前がこちら
やること
Articleモデルに色を登録するカラム
color_1
とcolor_2
を追加するcolor_field
jqueryのカラーピッカーとかを使って色を登録しようかなんて思っていたところRailsが提供している
color_field
というものを見つけた。これで色を選択できる!こんなかんじ↓
_form.html.erb<tr> <th scope="row">吹き出し1</th> <td><%= f.text_field :balloon_1, size: "90x10" %> <%= f.color_field :color_1 %> </td> </tr> <tr> <th scope="row">吹き出し2</th> <td><%= f.text_field :balloon_2, size: "90x10" %> <%= f.color_field :color_2 %> </td> </tr>色の表示
<div class = "balloon1" style="background-color:<%= @article_.color_1 %>"><div class = "balloon1" style="background-color:#b8e1f5">これだとまだ吹き出しの3角の部分の色がstyle.cssで指定したままの色なので未完成です。
この吹き出しのCSSはこのようなコードでできています。style.css.detail .article .balloon1{ position: relative; padding: 20px; border-radius: 10px; background-color: #ffb1cd99; width: 75%; height: 25px; } /* 三角アイコン */ .balloon1::before{ content: ''; position: absolute; display: block; width: 0; height: 0; left: -15px; top: 17px; border-right: 15px solid #ffb1cd99; border-top: 15px solid transparent; border-bottom: 15px solid transparent; }::beforeってのが擬似要素ってやつでこれのスタイル指定を別で行わなきゃいけないようです。
擬似要素ってなあに?って方はこちら↓
この方の記事がわかりやすかったです!
いろんな仕様の変更とかで::
と:
が混じってわかりにくい記事も多いです
参考:擬似要素と擬似クラス<style>.balloon1::before { border-right: 15px solid <%= @article_.color_1 %>; }</style> <div class = "balloon1" style="background-color:<%= @article_.color_1 %>"><%= @article_.balloon_1 %></div>できた!