- 投稿日:2019-10-28T23:53:08+09:00
railsでサジェスト機能を実装してみた
railsでサジェスト機能を実装した時のメモ?
autocomplete系のgemが軒並みメンテされていなかったので、jquery-uiで実装していきます。
動作環境
rails 5.2.2.1
jquery-ui-rails 6.0.1やること
company属性を持つUserというモデルを想定し、
User作成画面でcompanyのテキストフィールドに入力した際、
既にDBに存在するデータをもとに候補をサジェストする機能を実装します?Gemfile
Gemfileに下記を追加し
bundle installGemfilegem 'jquery-ui-rails'bundle installapplication.js
下記を追加
/assets/javascripts/application.js//= require jquery-ui/widgets/autocompleteapplication.scss
下記追加
/assets/stylesheets/application.scss@import "jquery-ui/autocomplete"; @import "jquery-ui/theme"; @import "jquery-ui/menu";筆者環境だと、theme、menuを外すと表示が崩れました?
routes.rb
サジェストの配列を返すルートを追加します。
routes.rbresources :users do get '/autocomplete_company/:company', on: :collection, action: :autocomplete_company endモデル
前方一致検索のscopeを追加します。
user.rb# 前方一致検索 scope :by_company_like, lambda { |company| where('company LIKE :value', { value: "#{sanitize_sql_like(company)}%"}) }コントローラー
サジェストの候補を返すaction追加
受け取ったパラメータをもとにサジェストしたい文字列の配列を返すようにします。user_controller.rbdef autocomplete_company # params[:company]の値でUser.companyを前方一致検索、company列だけ取り出し、nilと空文字を取り除いた配列 companies = User.by_company_like(autocomplete_params[:company]).pluck(:company).reject(&:blank?) render json: companies # レスポンスの例: ["てすと1会社","てすと2会社","てすと3会社"] end private def autocomplete_params params.permit(:company) endビュー
autocompleteのsourceに
サジェスト候補の配列を取得する関数をセット。_form.html.slim= form_with(model: @user, local: true) do |form| .form-group = form.label :company = form.text_field :company / id='user_company'で生成される javascript: $(function() { const dataList = function(request, response) { $.ajax({ url: '/users/autocomplete_company/' + request.term, dataType: 'json', type: 'GET', cache: true, success: function(data) { response(data); }, error: function(XMLHttpRequest, textStatus, errorThrown) { response(['']); } }); } // #user_companyの部分は必要に応じてidなり指定してください $('#user_company').autocomplete({ source: dataList, autoFocus: true, // 自動的に先頭の項目にフォーカスするか delay: 300, // 入力してからサジェストが動くまでの時間(ms) minLength: 2 // 2文字入力しないとサジェストが動かない }) });テキストフィールドの内容に応じて、動的に内容を変える必要がなければ
dataListにサジェストしたい文字列の配列を直接入れればOKです!javascript: $(function() { const dataList = ["こうほ1","こうほ2"]; });まとめ
jquery-uiを使って、サジェスト機能を実装しました。
今回は説明のため、Viewに直接javascriptを書いてますが
別ファイルにしたり、ヘルパーを切り出したりすると良いと思われます☺️間違っているところがあればご指摘ください!
- 投稿日:2019-10-28T23:22:33+09:00
Rails5.2 + Vue.js + Dockerでプロジェクトを作成
はじめに
Railsを使っていてVueも一通り学んだのでRailsとVueを使えるように環境構築してみようと思い勉強してみたことをアウトプット。
Rubyのバージョンは2.5.3
Railsのバージョンは5.2.3
DBはMysqlを使用Railsのプロジェクトを作成するディレクトリを事前に作成しておく
$ mkdir <任意のフォルダ名>
フォルダを作成したら作成したディレクトリに移動しておくDocker用のファイルの作成
Dockerのコンテナを作成するためのファイルを作成
Dockerfile
docker-compose.yml
Gemfile
Gemfile.lock
の4つのファイルを作成する。DockerfileFROM ruby:2.5.3 RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - && apt-get update && \ apt-get install -y nodejs --no-install-recommends && rm -rf /var/lib/apt/lists/* RUN apt-get update -qq && apt-get install -y build-essential libpq-dev RUN apt-get update && apt-get install -y curl apt-transport-https wget && \ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ apt-get update && apt-get install -y yarn RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - && \ apt-get install nodejs RUN yarn add node-sass RUN mkdir /app WORKDIR /app COPY Gemfile /app/Gemfile COPY Gemfile.lock /app/Gemfile.lock RUN bundle install COPY . /appdocker-compose.ymlversion: '3' services: web: build: . command: bundle exec rails s -p 3000 -b '0.0.0.0' volumes: - .:/app ports: - 3000:3000 depends_on: - db tty: true stdin_open: true db: image: mysql:5.7 volumes: - db-volume:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: password volumes: db-volume:Gemfilesource 'https://rubygems.org' ruby '2.5.3'Gemfile.lock
はbuildした後に自動的に記述されるので空にしておく。(ファイルは必要)この4つのファイルを作成し、先ほど作成したディレクトリに置く。
Railsプロジェクトの作成
次にRailsのプロジェクトを作成するため次のコマンドを実行
$ docker-compose run web rails new . --force --database=mysql
(rails newの . は現在いるディレクトリにそのままプロジェクトを作成するというもの)プロジェクトの作成が終わったら
docker-compose psでコンテナが作成されているか確認。
次にRailsプロジェクトのdatabase.ymlを編集します。config/database.ymldefault: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: password host: dbpasswordとhostの部分をdocker-compose.ymlの記述と合わせます。
$ docker-compose upコマンドでコンテナを立ち上げ、localhost:3000に接続し、RailsのHello World画面が表示されれば無事成功です!Vue.jsの導入
vue.jsをRailsで使用できるようにするためにまずはWebpackerの導入が必要。Gemfileに以下を追加します。
Gemfilegem 'webpacker'記述したら
$ docker-compose run web rails webpacker:installを実行自分の場合、Gemfileの記述を
gem 'webpacker', github: 'rails/webpacker'
とするとyarnエラーが出てインストールができませんでした。インストールが完了したらいろいろRailsのプロジェクトにファイルが追加されると思います。
次にVueをインストールしていきます。
$docker-compose run web rails webpacker:install:vueこれでVue.jsの導入が完了しました。
vue.jsファイルのビルド
次にVue.js関連のコンポーネントをJavascriptにコンパイルするため
$ docker-compose run web bin/webpackコマンドを実行します。RailsのViewsファイルに
<%=javascript_pack_tag 'hello_vue'%>と記述し問題なく表示されていれば成功です!参考
dockerでrails+vueの環境を作ったので解説
Rails5.2 + Docker環境にVue.js (Webpacker) を導入する
- 投稿日:2019-10-28T22:04:37+09:00
Rails: validates: 指定した値の時だけ複数カラムでuniquenessを制約を掛ける方法備忘録
- 投稿日:2019-10-28T21:42:31+09:00
rubyの予約語を使っちゃったカラム名をfactory_botでテストしたい
例えば
classというカラムを作ってしまっけれど factory_bot でテストしたいと思ったら…factory :reservation do add_attribute(:class) { 'A組' } end
add_attribute!"Getting Started" に書いてある!
https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#method-name--reserved-word-attributes
- 投稿日:2019-10-28T21:23:24+09:00
railsでfaviconを3ステップで実装してみた
STEP1
下記ファイルに<%= favicon\_link\_tag('favicon.ico') %>を追加する
application.html.erb<!DOCTYPE html> <html> <head> <title>Sample</title> <%= favicon\_link\_tag('favicon.ico') %>//この1行を追加する </head> [省略]STEP2
下記のサイトでアイコンにしたい画像を変換する
https://ao-system.net/favicon/
favicon.icoが生成されるSTEP3
assets/assets/images配下にfavicon.icoファイルを設置する
あとはサーバーを再起動すれば実装されています!!
- 投稿日:2019-10-28T20:45:51+09:00
【rails】かんたんログイン機能導入方法
現在railsでポートフォリを作成中ですが、よりスムーズに使ってほしいためにこの機能を導入したくなったので作りました。
若干手抜き感が否めないですが、一応使えます。これはdivise導入済みで進めていきます。
まずはテストユーザーで新規登録します。
name:テストユーザー email:test@example.com password:testtestログインを簡単にする機能なのでまずは登録ないと始まりません。
view側を編集
もともと
views/devise/sessions/new.html.slimというファイルがありますが中身を真似て、
views/devise/sessions/_testuser.html.slimというファイルを作ります。_testuser.html.slimh2 | かんたんログイン = form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| .field =f.hidden_field :email ,value: "test@example.com" =f.hidden_field :password ,value: "testtest" .actions = f.submit "かんたんログイン"このように書いて
views/devise/registrations/new.html.slimにnew.html.slim....... = render 'devise/sessions/testuser'これで新規登録画面にかんたんログインボタンが表示されるようになります。
編集ボタンを隠す
私の場合は
views/users/show.html.slimにユーザー詳細画面がありますがテストユーザーのみ編集ボタンをを隠したいと思いますshow.html.slim..... - unless @user.email == "test@example.com" = link_to "edit",edit_user_registration_pathこれではurlに直接打ち込むとアクセスできてしまうのが注意です。
deviseに対応したコントローラーを導入
$ rails g devise:controllers usersルーティングの編集
userのコントローラーを作ったので、そこにアクセスするようにルーティングを編集します。
routes.rbdevise_for :users, controllers: { registrations: 'users/registrations' }コントローラー内を編集
テストユーザーを編集、削除されてほしくないので制限する。
registrations_controller.rb...... before_action :forbid_test_user, {only: [:edit,:update,:destroy]} ...... private def forbid_test_user if @user.email == "test@example.com" flash[:notice] = "テストユーザーのため変更できません" redirect_to root_path end end .......これによりかんたんログイン機能ができるようになります。
参考:【学習アウトプット2】離脱率を下げる!かんたんログイン機能の実装
- 投稿日:2019-10-28T16:55:07+09:00
Dockerで起動したRails(DB:postgres)のDBにDBeaverで接続する
はじめに
Dockerで作り始めたRailsアプリのデータベースをpostgresにしたので
Sequel Proよろしく中身を見に行くか〜!と思って簡単に考えていたら
思ったよりも大変だったのでまとめておく。
というより前の記事のせいで苦労した環境
- MacOS Mojave 10.14.5
- Rails 5.2.3
- ruby 2.5.7
- postgres 11
設定
ここでの設定はDockerでRailsの環境構築してHerokuへデプロイするで紹介されている内容と一緒になります。
Docker-compose.yml
docker-compose.ymlversion: '3' services: db: image: postgres:11 ports: - '5432:5432' environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: test_db volumes: - postgresql-data:/var/lib/postgresql/data web: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/myapp ports: - "3000:3000" depends_on: - db volumes: postgresql-data: driver: localdatabase.yml
config/database.ymldefault: &default adapter: postgresql encoding: unicode host: db username: postgres password: pool: 5 development: <<: *default database: myapp_development test: <<: *default database: myapp_test production: <<: *default database: myapp_production username: myapp password: <%= ENV['MYAPP_DATABASE_PASSWORD'] %>DBeaverのインストール
こちらの記事を参考にインストールしてください。
DBeaverを使ってpostgresへ接続
- dockerでRailsアプリの起動
$ docker-compose startこんな感じになる。
接続が完了したら、終了を押して完了させる。データベースの情報を表示させる
無事にデータベースへの接続が完了したら
これでデータベースに保存されているカラムの内容が表示されます。
もちろん書き換えもできます。FATAL: role “postgres” does not exist と出る時
結論は、「他のpostgresサーバーが5432ポートで起動している」ため
postgresのコンテナサーバーへの接続にエラーが出ているようです。まずは基本に立ち返って、エラー文に書いてあることを解消していきます。
こちらの記事を参考に、データベースにrole postgresがあるか確認しにいきます。
- 稼働しているコンテナの状況を確認
$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c920fadb8d27 application_web "entrypoint.sh bash …" 30 hours ago Up 55 minutes 0.0.0.0:3000->3000/tcp application_web_1 2479f579d66e postgres:11 "docker-entrypoint.s…" 30 hours ago Up 55 minutes 0.0.0.0:5432->5432/tcp application_db_1データベースのコンテナの名前は"application_db_1"のようですね。
(名前はそれぞれの環境によって異なります)
- データベースのコンテナに入る
$ docker exec -it application_db_1 bash root@2479f579d66e:/# ここでコマンド待ちの状態になる
- データベースにアクセスする
psql -U postres を実行する root@2479f579d66e:/# psql -U postgres psql (11.5 (Debian 11.5-3.pgdg90+1)) Type "help" for help. postgres=# ここでコマンド待ちの状態になる
- roleの状態を確認する
\du を実行する postgres=# \du List of roles Role name | Attributes | Member of -----------+------------------------------------------------------------+----------- postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {} postgres=#どうやら、postgresは存在するようです。
原因は他にあるようですが・・・?他のpostgreインスタンスが動いていた
こちらの記事では、同じような問題に対して
The problem was simple enough that my computer was already running an instance of Postgres that I was not aware was still running (not inside Docker) on :5432, checked with:
と説明されています。コマンドも示されているので試してみましょう。
(ターミナルで実行してください)$ lsof -n -i:5432 | grep LISTEN postgres 419 user_name 5u IPv6 0xe1a2b61a846df097 0t0 TCP [::1]:postgresql (LISTEN) postgres 419 user_name 6u IPv4 0xe1a2b61a8514b617 0t0 TCP 127.0.0.1:postgresql (LISTEN) com.docke 594 user_name 18u IPv6 0xe1a2b61a96bd6f57 0t0 TCP *:postgresql (LISTEN)一番下のcom.dockeがdockerで動かしているデータベースのコンテナのようですが
他に2つ動いているようです。(実際にはPIDが419で同じなので1つです)
先ほどの記事では、他のposgresインスタンスをストップさせれば接続できるようなので
早速ストップさせてみます。
- postgresインスタンスの状態を確認する
$ pg_ctl status pg_ctl: server is running (PID: 419) /usr/local/Cellar/postgresql/11.5/bin/postgres "-D" "/usr/local/var/postgres"先ほどと同じPIDのサーバーが動いていることが確認できました。
こいつをストップさせましょう。
- postgresインスタンスをストップさせる
$ pg_ctl stop -D "/usr/local/var/postgres" -m s waiting for server to shut down.... done server stopped止まったようですね!本当に止まっているか、念の為確認しておきましょう
$ pg_ctl status pg_ctl: server is running (PID: 76742) /usr/local/Cellar/postgresql/11.5/bin/postgres "-D" "/usr/local/var/postgres"新たに生まれ落ちているようですね・・・自動再起動しているようです。
とりあえずもう一度削除を試みますが・・・$ pg_ctl stop -D "/usr/local/var/postgres" -m s waiting for server to shut down............................................................... failed pg_ctl: server does not shut down HINT: The "-m fast" option immediately disconnects sessions rather than waiting for session-initiated disconnection. $ pg_ctl stop -D "/usr/local/var/postgres" -m fast waiting for server to shut down............................................................... failed pg_ctl: server does not shut down $ pg_ctl stop -D "/usr/local/var/postgres" -m i waiting for server to shut down............................................................... failed pg_ctl: server does not shut downstopのオプションたちを全て試してみるも、posgresインスタンが止まらないようです。
これは困った。lanchctlでなんとかした
こちらの記事で紹介されているコマンドでpostgresインスタンスの削除を試みます。
$ launchctl unload -w ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist $ pg_ctl status pg_ctl: no server runningやりました!postgresインスタンスを削除できたようです!
これでもう一度、コンテナを立ち上げ直してDBeaverから接続を試すと、成功するはずです!立ち上がっていたインスタンスは何者か?
前の記事でサーバーを建てて放置していたのが原因っぽいです。
終わったら片付けることは大事ですね・・・
- 投稿日:2019-10-28T16:19:05+09:00
Railsアプリ〜デプロイへの道〜その③Capistrano3設定編【ConoHa VPS・CentOS・Capistrano3・Nginx・Unicorn】
Railsアプリケーションをデプロイした時の手順まとめ第3弾です。
Railsアプリ〜デプロイへの道〜はこの記事でいったん完結します。今回はnginxのインストールからCapistrano3の設定、デプロイまで一気に紹介するので、
今までよりボリュームが多いです。
てんこ盛りです。前回、前々回同様こちらの記事がベースとなっています。
https://qiita.com/ryo2132/items/f62690f0b16ec11270feこれまでの記事同様、この記事は基本的に手順を記したものなので(僕の理解が不十分であることも否めませんが)、詳しい説明は省いています。
背景などを理解したい方は、ぜひ引用元の記事(リンク先記事)をご覧ください。〈関連記事〉
Railsアプリ〜デプロイへの道〜その①リモートサーバーへのSSH接続編
Railsアプリ〜デプロイへの道〜その②Ruby・MySQLインストール編開発環境
・Mac OS
・Rails 5.2.3
・Ruby 2.5.1
・ConoHa VPS
・CentOS 7.6
・Capistrano3
・Nginx
・UnicornNginx
WebサーバーNginxのインストールおよび設定を行います。
〈参考〉
https://koooza.net/post-382
https://qiita.com/glvty83/items/abd99a6b712e4e006af11.インストール
yumで一発です。
サーバー$ cd ~ $ sudo yum install nginx #確認。バージョン出ればOK $ nginx -v2.設定ファイルの編集
〈参考〉
https://qiita.com/naoki_mochizuki/items/657aca7531b8948d267bリクエストの処理方法、webアプリのディレクトリ設定等を行います。
まずファイルを作成。$ cd /etc/nginx/conf.d/ $ sudo vi hoge_app.conf # 名前は任意。webアプリの名前など続いてファイルの中身を以下のように修正してください。
hoge_appの部分は任意の名称に、serer_nameの部分はconohaのipアドレスに変えてください。#各種ログのディレクトリ設定 error_log /var/www/hoge_app/current/log/nginx.error.log; access_log /var/www/hoge_app/current/log/nginx.access.log; #処理を受け取る最大許容量 client_max_body_size 2G; upstream app_server { # 連携するunicornのソケットのパス server unix:/var/www/hoge_app/current/tmp/sockets/.unicorn.sock fail_timeout=0; } server { listen 80; server_name xxx.xxx.xxx.xxx; # conohaのipアドレス #次のリクエストが来るまでの待ち時間(秒 keepalive_timeout 5; #静的ファイルを読みに行くディレクトリ root /var/www/hoge_app/current/public; #キャッシュのディレクトリ try_files $uri/index.html $uri.html $uri @app; location @app { # HTTP headers proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_pass http://app_server; } #エラーページを設置する場所 error_page 500 502 503 504 /500.html; location = /500.html { root /var/www/hoge_app/current/public; } }/var/www/hoge_app/フォルダはのちほど作成します。
3.ファイアウォールのポート開放
ファイアウォールの80番ポートを解放します。
ファイアウォールのポートの開放をしないと、httpでの通信ができません。なぜ80番ポートなのかと言うと、80番ポートがhttp通信用のポートだからです。
〈参考〉
http://inaba.hatenablog.com/entry/2017/02/26/040218アクティブなゾーンを確認
ファイアウォールは「事前に定義されたゾーンに対して、指定されたルールの通信を通す。」という事をしています。 なので、まずはどのゾーンへのファイアウォールが動いているかを確認します。
$ firewall-cmd --get-active-zones public interfaces: eth0--get-active-zonesというオプションをつけると、現在アクティブなゾーンが表示されます。
上記だとpublicというゾーンがアクティブだとわかります。
アクティブなゾーンが複数ある場合は、eth0が外部公開されているインタフェースなので、eth0が定義されているゾーンが外部向けポートを追加する対象です。許可されているポートの確認
次は先程確認したアクティブなゾーンのpublicについて、現在許可されているポートを確認します。
$sudo firewall-cmd --info-zone public public (active) target: default icmp-block-inversion: no interfaces: eth0 sources: services: dhcpv6-client ssh ports: protocols: masquerade: no forward-ports: sourceports: icmp-blocks: rich rules:servicesには定義されているサービス(ルールのような物)が表示されます。
上の例だとservicesにdhcpv6-clientとsshが設定されています。次のコマンドでサービスの内容を確認できます。
$ sudo firewall-cmd --info-service dhcpv6-client詳しくはこちらの記事をお読みください。
http://inaba.hatenablog.com/entry/2017/02/26/040218portsにはサービスとは別に開放されているポートが表示されます。
今回はportsには何も表示されていませんが、例えば8080番ポートが開放されていると、ports: 8080/tcpのように表示されます。定義されているサービスを確認
サービスの一覧は—get-servicesオプションで確認できます。
$ firewall-cmd --get-services RH-Satellite-6 amanda-client amanda-k5-client bacula bacula-client ceph ceph-mon dhcp dhcpv6 dhcpv6-client dns docker-registry dropbox-lansync freeipa-ldap freeipa-ldaps freeipa-replication ftp high-availability http https imap imaps ipp ipp-client ipsec iscsi-target kadmin kerberos kpasswd ldap ldaps libvirt libvirt-tls mdns mosh mountd ms-wbt mysql nfs ntp openvpn pmcd pmproxy pmwebapi pmwebapis pop3 pop3s postgresql privoxy proxy-dhcp ptp pulseaudio puppetmaster radius rpc-bind rsyncd samba samba-client sane smtp smtps snmp snmptrap squid ssh synergy syslog syslog-tls telnet tftp tftp-client tinc tor-socks transmission-client vdsm vnc-server wbem-https xmpp-bosh xmpp-client xmpp-local xmpp-server結構量が多いのですが、この中にhttpというサービスがあります。
httpサービスの内容を確認します。
$sudo firewall-cmd --info-service http http ports: 80/tcp protocols: source-ports: modules: destination:80番ポートがルールとして定義されています。
サービスをゾーンに追加
httpサービスが80番ポートを開放するサービスという事がわかったので、publicゾーンにhttpサービスを追加します。
$sudo firewall-cmd --permanent --zone public --add-service http success $sudo firewall-cmd --reload success--permanentは設定の永続化。(無いと再起動時に設定が消えます。)
--zone publicはゾーンの指定。 --add-service httpは追加するサービスの指定です。
--add-serviceだけでは設定が反映されないので、設定をした後に--reloadでファイアウォールに設定を反映させます。設定が反映されているか確認します。
$sudo firewall-cmd --info-zone public public (active) target: default icmp-block-inversion: no interfaces: eth0 sources: services: dhcpv6-client http ssh ports: protocols: masquerade: no forward-ports: sourceports: icmp-blocks: rich rules:設定が反映されました。
4.自動起動設定
サーバーの再起動の際にもNginxが自動的に起動するよう設定します。
$ chkconfig nginx on自動起動確認
$ systemctl is-enabled nginx enablednginx基本コマンド
〈参考〉
https://qiita.com/MuuKojima/items/afc0ad8309ba9c5ed5ee起動 $ sudo systemctl start nginx 停止 $ sudo systemctl stop nginx 再起動 $ sudo systemctl restart nginx 再起動しても設定ファイルが反映されない場合など $ sudo nginx -s reload 状態の確認 $ sudo systemctl status nginxGithubの公開鍵登録
capisatranoでは、直接ローカルからファイルを送るのではなく、githubなどのホスティングサービスを経由します。
なので、サーバー側からgithubへsshで接続できるようにキーペアの作成・登録を行います。〈参考〉
https://qiita.com/shizuma/items/2b2f873a0034839e47ce1.キーの作成
サーバー
$ cd ~/.ssh/ $ mkdir github $ cd github # キーペアの作成 $ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/hoge/.ssh/id_rsa): /home/hoge/.ssh/github/id_rsa # 先程作成したフォルダを指定 Enter passphrase (empty for no passphrase): # Enter Enter same passphrase again: #Eneter $ cat id_rsa.pub # 出力をコピーして、githubのコンソールより公開鍵を登録 # 設定ファイルを作成 $ sudo vi ~/.ssh/config # 以下を記述 Host github github.com Hostname github.com User git IdentityFile ~/.ssh/github/id_rsa※Host名に注意してください。
❌Host github
⭕️Host github github.comgithubだけではエラーが発生しました。
2.公開鍵をGitHubにアップする
以下のリンクから公開鍵をGithubにアップできます。(GitHubに登録していることが前提条件です)
https://github.com/settings/ssh手順はこちらの記事でご確認ください。
>>https://qiita.com/shizuma/items/2b2f873a0034839e47ce接続確認
$ ssh -T github #確認はyes #以下のような文章が出力されればOK You've successfully authenticated, but GitHub does not provide shell access.Rails
1.データベースの設定
本番環境用のデータベースの設定をします。
Railsconfig/database.ymldefault: &default adapter: sqlite3 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> timeout: 5000 development: <<: *default database: db/development.sqlite3 test: <<: *default database: db/test.sqlite3 # ここから変更 production: adapter: mysql2 encoding: utf8mb4 charset: utf8mb4 pool: 5 database: hoge_app_production username: root password: root # その1で設定したサーバー側のmysqlのパスワード socket: /var/lib/mysql/mysql.sock2.Gemfile修正
groupでくくられていないgem ’sqlite3’をコメントアウトし、developmentのグループのなかに’sqlite3’を追加します。
さらにproductionのグループを追記し、そちらにmysql2を設定しています。Gemfile. . # Use sqlite3 as the database for Active Record # gem 'sqlite3' コメントアウト . . group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] # Adds support for Capybara system testing and selenium driver gem 'capybara', '~> 2.13' gem 'selenium-webdriver' # 追加 gem 'sqlite3' end . . # 以下追加 group :production, :staging do gem 'mysql2' endインストール
$ bundle install3.Githubでのバージョン管理開始
CapistranoではGithubを介したデプロイを行うので、githubのremoteリポジトリの登録とpushを行います。
# 変更履歴のコミット $ git add . && git commit -m 'first commit' # リモートリポジトリの登録(事前にご自身のgithubでリポジトリを作っておいてください) # リポジトリ追加の際に表示される案内に従ってコマンドを入力 $ git remote add origin git@github.com:[ユーザID]/[リポジトリ].git # リモートへのアップ $ git push -u origin masterCapistrano
Capistranoとは、Ruby製のデプロイ自動化ツールです。
アプリケーションのファイルをサーバーにアップしてインターネット上に公開し、ユーザーが使える状態にするデプロイ作業を自動で行ってくれます。Capistranoがデプロイを自動化するツールなら、ここまでの作業はなんだったのか??
デプロイの準備作業ということになりますね。実を言うと、僕は手動デプロイをしたことがないのですが、手動デプロイには引き継ぎや再利用がしづらいといったデメリットがあるようです。
Capistranoは保守性が高く、再利用もしやすいと言ったメリットがありますが、それでも設定する項目が多く複雑です。
仕組み部分の理解がこれまで以上に重要になってきます。
設定に入る前に、こちらの記事に目を通すことを強くお勧めします。
https://labs.gree.jp/blog/2013/12/10084/〈参考〉
https://qiita.com/naoki_mochizuki/items/657aca7531b8948d267b1.インストール
Railsアプリにcapistranoおよびunicornのgemをインストールします。
Rails
Gemfilegroup :development do # Access an IRB console on exception pages or by using <%= console %> anywhere in the code. gem 'web-console', '>= 3.3.0' gem 'listen', '>= 3.0.5', '< 3.2' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' # 以下追記 gem 'capistrano' gem 'capistrano-bundler' gem 'capistrano-rails' gem 'capistrano-rbenv' end group :production, :staging do gem 'mysql2' # 以下追記 gem 'unicorn' endローカル
$ bundle install2.capistranoの設定ファイル生成
新たにcapコマンドが使えるのでそれでcapistranoの設定ファイルを作成します。
$ bundle exec cap install以下のようなファイルが生成されます。
hogeapp
├─ Capfile
├─ config
│ ├─ deploy
│ │ ├─production.rb
│ │ └─staging.rb
│ └─deploy.rb
└─ lib
└─capistrano
└─tasks3.capistranoの基本設定
Rails
capistranoの設定ファイルを編集します。
まず、何を読み込むかを、Capistranoでどのような動作を行うかに合わせて決めます。最初に記載されている内容は削除で大丈夫です。
今回は下の用に設定しましょう。
require hogehogeの部分で読み込むファイルを設定しています。capfilerequire "capistrano/setup" require "capistrano/deploy" require "capistrano/rbenv" require "capistrano/bundler" require "capistrano/rails/assets" require "capistrano/rails/migrations" require "capistrano/scm/git" install_plugin Capistrano::SCM::Git # taskを記述したファイルを読み込む用に設定。 # なおデフォルトでは *.rakeとなっているのでもとの記述をそのまま使う場合は注意!! Dir.glob("lib/capistrano/tasks/*.rb").each { |r| import r }4.productionの環境設定
生成したconfig/deploy配下にあるprouction.rbにサーバーの情報を記述します。
ちなみにstaging.rbはその名の通り、ステージングの情報です。こちらも元のコードは全削除で大丈夫です。
config/deploy/production.rb# conohaのサーバーのIP、ログインするユーザー名、サーバーの役割 # xxxの部分はサーバーのIPアドレス # 10022はポートを変更している場合。通常は22 server 'xxx.xxx.xxx.xxx', user: 'hoge', group: "wheel", roles: %w{app db web}, port: 10022 #デプロイするサーバーにsshログインする鍵の情報。サーバー編で作成した鍵のパス set :ssh_options, { keys: %w(~/.ssh/id_rsa), forward_agent: true, auth_methods: %w(publickey) }次にproductionとstaging共通の設定について、deploy.rbに記述します。
こちらも最初の記述は全削除で。
※ capistranoのバージョンを確認して、以下記述のバージョンを調整してください。
rubyのバージョンからアプリケーション名、デプロイで送るgithubのリポジトリ、capistranoのタスクなどを記述します。config/deploy.rb# capistranoのバージョン固定 lock "~> 3.10.1" # デプロイするアプリケーション名 set :application, 'hoge_app' # cloneするgitのレポジトリ # 1-3で設定したリモートリポジトリのurl set :repo_url, 'git@github.com:hogehoge/hoge_app.git' # deployするブランチ。デフォルトはmasterなのでなくても可。 set :branch, 'master' # deploy先のディレクトリ。 set :deploy_to, '/var/www/hoge_app' # Default value for :pty is false set :pty, true # シンボリックリンクをはるファイル # Default value for :linked_files is [] append :linked_files, "config/master.key" # シンボリックリンクをはるフォルダ # Default value for linked_dirs is [] append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "vendor/bundle", "public/system" # 保持するバージョンの個数(※後述) set :keep_releases, 5 # rubyのバージョン # rbenvで設定したサーバー側のrubyのバージョン set :rbenv_ruby, ‘2.5.1’ # 出力するログのレベル。 set :log_level, :debug # デプロイのタスク namespace :deploy do # unicornの再起動 desc 'Restart application' task :restart do invoke 'unicorn:restart' end # データベースの作成 desc 'Create database' task :db_create do on roles(:db) do |host| with rails_env: fetch(:rails_env) do within current_path do # データベース作成のsqlセット # データベース名はdatabase.ymlに設定した名前で sql = "CREATE DATABASE IF NOT EXISTS hoge_app_production;" # クエリの実行。 # userとpasswordはmysqlの設定に合わせて execute "mysql --user=root --password=root -e '#{sql}'" end end end end after :publishing, :restart after :restart, :clear_cache do on roles(:web), in: :groups, limit: 3, wait: 10 do end end end各パラメータの内容は、次の参考記事で詳しく説明してくれています。
こちらも一読することをオススメします。
(Capistrano編)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで - Qiita5.master.keyの設定
Railsで設定しているmaster.keyの内容をサーバーにコピーします。
Rails5.2からはmaster.keyはcredentials.yml.encファイルで設定します。
詳しくは次の参考記事をお読みください。
〈参考〉
https://qiita.com/yuuuking/items/53a37a2e998972be32b8
https://qiita.com/katsu105/items/88675da5119762d73d92まず必要なディレクトリを作成します。
サーバー$ cd /var $ sudo mkdir -p www/hoge_app/shared/config # 所有者を設定 $ sudo chown -R hoge www # ファイルの作成 $ cd www/hoge_app/shared/configshared/configにmaster.keyを作ります。
$sudo touch /var/www/hoge_app/shared/config/master.key作成したmaster.keyを編集します。
$sudo vim /var/www/hoge_app/shared/config/master.keyローカルのmaster.keyの内容をコピーし、本番環境のmaster.keyにコピーします。
〈メモ〉
mkdir -p-pオプション(--parentsオプション)を指定することで、ディレクトリが存在していてもエラーメッセージを表示せず、現在あるディレクトリはそのままにして新規に作成することはなく子ディレクトリを作成する。
また、親ディレクトリが存在しなくてもエラーメッセージを表示せずに親ディレクトリと子ディレクトリを作成する。参考:https://eng-entrance.com/linux-command-mkdir
〈メモ〉
chown -R指定したディレクトリとそのディレクトリ以下のファイルやディレクトリの所有権を再帰的に変更
参考:https://webkaru.net/linux/chown-command/
unicornのセットアップタスク
unicornのセットアップタスクを記述します。
unicornはアプリケーションサーバーで、Railsアプリケーションを制御します。〈参考〉
https://qiita.com/naoki_mochizuki/items/657aca7531b8948d267bRails
lib/capistrano/tasks/unicorn.rb#unicornのpidファイル、設定ファイルのディレクトリを指定 namespace :unicorn do task :environment do set :unicorn_pid, "#{current_path}/tmp/pids/unicorn.pid" set :unicorn_config, "#{current_path}/config/unicorn/production.rb" end #unicornをスタートさせるメソッド def start_unicorn within current_path do execute :bundle, :exec, :unicorn, "-c #{fetch(:unicorn_config)} -E #{fetch(:rails_env)} -D" end end #unicornを停止させるメソッド def stop_unicorn execute :kill, "-s QUIT $(< #{fetch(:unicorn_pid)})" end #unicornを再起動するメソッド def reload_unicorn execute :kill, "-s USR2 $(< #{fetch(:unicorn_pid)})" end #unicronを強制終了するメソッド def force_stop_unicorn execute :kill, "$(< #{fetch(:unicorn_pid)})" end #unicornをスタートさせるtask desc "Start unicorn server" task start: :environment do on roles(:app) do start_unicorn end end #unicornを停止させるtask desc "Stop unicorn server gracefully" task stop: :environment do on roles(:app) do stop_unicorn end end #既にunicornが起動している場合再起動を、まだの場合起動を行うtask desc "Restart unicorn server gracefully" task restart: :environment do on roles(:app) do if test("[ -f #{fetch(:unicorn_pid)} ]") reload_unicorn else start_unicorn end end end #unicornを強制終了させるtask desc "Stop unicorn server immediately" task force_stop: :environment do on roles(:app) do force_stop_unicorn end end endkillの種類
kill -QUIT : 停止
kill -HUP : 再起動
kill -USR2 : 緩やかな停止6.unicornの設定ファイル
unicornの設定ファイルproduction.rbを作成し、ファイルのパスなどを設定します。
中身は以下のように記述してください。config/unicorn/production.rb#ワーカーの数 $worker = 2 #何秒経過すればワーカーを削除するのかを決める $timeout = 30 #自分のアプリケーション名、currentがつくことに注意。 $app_dir = "/var/www/hoge_app/current" #リクエストを受け取るポート番号を指定。後述 $listen = File.expand_path 'tmp/sockets/.unicorn.sock', $app_dir #PIDの管理ファイルディレクトリ $pid = File.expand_path 'tmp/pids/unicorn.pid', $app_dir #エラーログを吐き出すファイルのディレクトリ $std_log = File.expand_path 'log/unicorn.log', $app_dir # 上記で設定したものが適応されるよう定義 worker_processes $worker working_directory $app_dir stderr_path $std_log stdout_path $std_log timeout $timeout listen $listen pid $pid #ホットデプロイをするかしないかを設定 preload_app true #fork前に行うことを定義 before_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! old_pid = "#{server.config[:pid]}.oldbin" if old_pid != server.pid begin Process.kill "QUIT", File.read(old_pid).to_i rescue Errno::ENOENT, Errno::ESRCH end end end #fork後に行うことを定義 after_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection endgithubへのpush
今までの変更をgithubへpushします。
capistranoはgithubを介してサーバーにファイルを送るためです。ローカル
# 変更履歴をステージング $ git add . # コミット $ git commit -m 'config complete' # githubへ送信 $ git push origin masterデプロイ
いよいよデプロイを行います。
1.データベース作成
デプロイ前に本番用のデータベースを作成します。
サーバー
$ sudo mkdir /var/www/hoge_app/current #サーバー側でディレクトリの作成次にローカル側のデプロイするアプリのディレクトリで以下のコマンドを実行します。
$ bundle exec cap production deploy:db_createどうやら一度きり実行するものはcap deploy時にtask名を明示してあげないといけないみたいなので、初回のみDBを作成するtaskを明示してあげないといけないようです。
最後に先程作成したサーバー側のcurrentディレクトリを削除します。
サーバー$ sudo rm -r /var/www/hoge_app/currentなぜこのような手順を追うかと言うと、先ほどのデータベース作成時にはcurrentがないと、デプロイ時にはcurrentがあるとエラーが発生することがあるみたいです。
もっといいやり方があるかもしれません。〈メモ〉
rm -r
rmコマンドは、オプションを設定しなければ、ディレクトリを削除の対象としない。
ディレクトリも削除の対象とする場合は、-rオプションを指定する。
参考:https://eng-entrance.com/linux_command_rm#-r--recursive2.デプロイの実行
ついにやってまいりました。
デプロイのお時間です!!!ローカルで次のコマンドを入力してください。
$ bundle exec cap production deploy3.Nginxの起動
デプロイがうまくいったら、サーバーにアクセスしてnginxを起動してください。
サーバー
$ sudo service nginx start4.サイト確認
それではサイトにアクセスしてください。
$ open http://xxx.xxx.xxx.xxx # conohaのipアドレス無事に表示されればデプロイ成功です!
お疲れ様でした!!
おまけ
ここからはおまけになりますが、一応読んでおいてください。
僕はデプロイが完了した後、いったんConoHaサーバーを停止し、また起動させました。
すると、We're sorry, but something went wrong. If you are the application owner check the logs for more informationというエラーメッセージが表示され、アプリが表示されなくなってしまいました。
色々といじるも解決せず、デプロイし直したら、今度はデプロイまでエラーが発生してしまいました。
SSHKit::Runner::ExecuteError: Exception while executing as fukaya@150.95.204.25: kill exit status: 1 kill stdout: kill: sending signal to 5001 failed: そのようなプロセスはありません kill stderr: Nothing writtenunicorn.pidを削除することでデプロイ時のエラーは解決しました。
$ cd /var/www/hoge_app/current/tmp/pids $ sudo rm -r unicorn.pid〈参考〉
http://movieman.hatenadiary.com/entry/2017/01/26/010635再デプロイ後にnginxを起動させたら、きちんとアプリが表示されました。
何が言いたいかというと、
いったんデプロイしたら、不用意にConoHaサーバーを停止しないようにしましょう!!!
ということです。
まとめ
いかかがでしたか??
スムーズにデプロイできましたか??
僕もそうでしたが、初めてのデプロイだとなかなかスムーズにはいかないと思います。
ですが、試行錯誤しながら苦労してデプロイをしたことで、確実にデプロイ前より成長しているはずです。
ちなみに僕は初デプロイの時に途中で詰まり、色々とイジっていたら収拾がつかなくなったので、
最初からデプロイし直しました。1からやり直したことでいい復習になり、結果的に理解も深まりました。
どうしようもなくなったら、思い切って最初からやり直すのもアリだと思います。
僕もまだまだわからないことばかりで、偉そうなことは言えないので、
これからもっと精進していきたいと思います。初デプロイ達成、おめでとうございます!!
〈関連記事〉
Railsアプリ〜デプロイへの道〜その①リモートサーバーへのSSH接続編
Railsアプリ〜デプロイへの道〜その②Ruby・MySQLインストール編
- 投稿日:2019-10-28T15:34:45+09:00
ENV[HOGEHOGE]でenvファイルの環境変数にアクセスできない!
結論
springを再起動したら通りました。
$spring stopspringについては以下を参考。
https://ruby-rails.hatenadiary.com/entry/20141026/1414289421超ざっくり説明すると、毎回全システム起動してたら時間かかるからよく使うやつロードしたままにするね!みたいな感じ
経緯
外部APIのtokenを隠しておこうと、dotenv-railsを導入。
.envファイルを作成して環境変数を定義。
いざENV[HOGEHOGE]で値を取りに行くとnilが帰ってきてしまった。
変数名、定義法もあっていたのでもしやと思いつつspringを止めてみると案の定でした。
環境変数の読み込みもspringでストックさるんですね。めでたしめでたし。
- 投稿日:2019-10-28T14:38:32+09:00
【第2回】Ruby + Seleniumを使ってスクレイピングしてみる
@cosmeの商品レビューをスクレイピングしてみる
第1回の前置きが長くなってしまいましたが、今回からコーディングしていきたいと思います。
想定仕様
1.プロダクトIDが入ったURLを受け取る
2.上記で指定した商品の各レビューページに設置されている「続きを読む」リンクを踏み、全文レビューページに遷移
3.レビュー全文を取得する
4.同ページにある「次へ」リンクを踏み、次のレビュー全文ページに飛ぶ
5.3&4を任意で指定したレビュー取得件数分繰り返す
6.完了したらchromeを閉じるこんな感じの仕様ができればと思います。Seleniumを使うことで、「4.同ページにある「次へ」リンクを踏み、次のレビュー全文ページに飛ぶ」という仕様ができるのが本当にデカいですね。これなら各レビューIDを指定する必要もないので、100件でも1000件でも楽々取得できるようになります。
Let's ruby
今回使用するライブラリはこんな感じです
#自動ブラウジング require 'selenium-webdriver' #HTMLをパースする require 'nokogiri' #指定したURLを開く&レビュー本文を取得 require 'open-uri' #既存のxlsxフォーマットの書き込み require 'rubyXL'
nokogiriとopen-uriはスクレイピングではほぼ必須のライブラリ。
今回はxlsxファイルへの「書き込み」のみ(読み込みはしない)ですのでrubyXLを使用します。Selenium起動&全文レビューページに遷移
#Seleniumを立てる(今回はchromeを使います) driver = Selenium::WebDriver.for :chrome #商品ページのURLを変数input_urlで受け取る input_url = "https://www.cosme.net/product/product_id/10163439/top" #input_urlで受け取ったページに移動する driver.navigate.to("#{input_url}") #「続きを読む」リンクを踏み、全文レビューページに遷移する driver.find_element(:partial_link_text,'続きを読む').click #カウンター(後のwhile文で使います) count = 0 #取得レビュー件数を変数limitで受け取る limit = 50 #商品名を変数nameで受け取る(任意の商品名を設定する。出力するxlsxのファイル名になります。) name = "チェリー本" #変数reviewsの空配列を置いておく(取得した各レビューは、変数reviewsの配列の要素として代入されます。) reviews = []・
driver = Selenium::WebDriver.for :chrome
今回はchromeで行いたいと思います。firefox, IE, Safariなどにも対応しているようです。・
limit = 50
取得レビュー件数はここで指定します。今回はwhile構文を使った繰り返し処理を行いますが、その繰り返しの回数=limitの値になります。・
reviews = []
取得した各レビューは配列の要素としてreviewsに追加できるようにします。while文による繰り返し処理
while count < limit.to_i #現在のページのURLを変数current_urlで取得 current_url = driver.current_url #UTF-8に変換(@cosmeの文字コードはShift_JISなので) doc = Nokogiri::HTML.parse(open(current_url, "r:Shift_JIS:UTF-8").read) #レビューを指定&本文のみを変数nに代入 n = doc.css("p.read").text #変数reviewsに配列要素としてnを代入する reviews << n #カウンターを追加 count+=1 #Dos対策(次のレビューページに遷移するまで1秒以上空ける) sleep 1 #ページ内の「次へ」を選択&ページ遷移 driver.find_element(:partial_link_text,'次へ').click end・
while count < limit.to_i
今回はwhile文を使ってみました。構文内にカウンターを設置し一周ごとにcount+=1になるようにしてます。limitで指定した取得レビュー件数を上回るまで繰り返し処理を実行する、という仕組みです。・
doc = Nokogiri::HTML.parse(open(current_url, "r:Shift_JIS:UTF-8").read)
なんとよくよくみたら@cosmeはShift-JISだったことが判明。UTF-8に変換しておきます。<meta http-equiv="Content-Type" content="text/html; charset=shift_jis">・
sleep 1
次のHTTPリクエストまで1秒以上空けます。取得したレビューをEXCELに書き込む
#フォーマットのxlsxを選択 workbook = RubyXL::Parser.parse("@cosme_format.xlsx") #シートを指定&シート名を変更 worksheet_a = workbook[0] worksheet_a.sheet_name ="@cosmeレビュー収集" #指定したセルに各レビューを書き出す p = 1 reviews.each do |re| worksheet_a.add_cell(p,2,"#{re}") p+=1 end #書き込みが完了したらブラウザを終了する driver.quit #保存する(序盤で任意で設定したnameの値がここに代入されます。) workbook.write("@cosmeレビュー収集結果_#{name}.xlsx")・
workbook = RubyXL::Parser.parse("@cosme_format.xlsx")
エクセルを操作できるrubyのライブラリは色々ありますが、今回は読み込みはせず書き込みだけなのでrubyXLを使ってみました。アウトプット例
まとめ
・
sleep 1で次のリクエストまで1秒開けているものの、あまりにも膨大な量を続けてリクエストすることはあまり良くないので、使用には十分注意する。長時間連続して回し続けないこと。
・特殊絵文字?などがレビュー本文に含まれている場合、エラーが起きて処理が止まってしまうので例外処理を用いて止まらないようにする。
- 投稿日:2019-10-28T13:54:53+09:00
【Rails】検索機能を実装しよう
はじめに
検索機能を実装しましょう!
今回は完全一致、部分一致、前方一致、後方一致を実装します。
それぞれ簡単に実装できるのでこの記事を理解して実装してみてください!!
今回はPostテーブルのtextカラムを検索する機能を実装します実装方法
機能の大まかな内容は以下の通りです。
1. 検索方法を選択し、検索フォームに単語を入力する
2. 検索ボタンをクリックするとsearchアクションに繋がる
3. searchアクションでテーブルから検索をかける
4. 検索結果をビューで表示する実装方法をビュー、モデル、コントローラーの順に説明していきます
ビュー
以下、検索フォームのソースです。
app/views/posts/search.html.erb<%= form_tag(posts_search_path , method: :get) do %> <%= select(@search_content, :search_method, [["前方一致","forward_match"], ["後方一致","backward_match"], ["完全一致","perfect_match"], ["部分一致","partial_match"]])%> <%= text_field(@search_content, :search_word)%> <%= submit_tag "検索" %> <% end %>
@search_contentにsearch_method、search_wordが含まれています。
search_methodが検索方法です。ドロップダウンリストで選択します。
search_wordが入力フォームに入力した単語を代入します。モデル
以下がモデルに検索のメソッドを定義する部分です。
app/models/post.rbdef self.search(method,word) if method == "forward_match" @posts = Post.where("text LIKE?","#{word}%") elsif method == "backward_match" @posts = Post.where("text LIKE?","%#{word}") elsif method == "perfect_match" @posts = Post.where("#{word}") elsif method == "partial_match" @posts = Post.where("text LIKE?","%#{word}%") else @posts = Post.all end end引数の
methodによって検索方法を選択し、wordで検索します。コントローラー
以下、コントローラーの内容です
app/controllers/posts_controller.rbdef search method = params[:search_method] word = params[:search_word] @posts = Post.search(method,word) end検索方法と単語を引数に渡し検索をします
終わりに
以上が検索機能の実装方法になります。
疑問、気になるところがございましたら、質問、コメントよろしくお願いします!!!
- 投稿日:2019-10-28T12:18:22+09:00
Rails6 のちょい足しな新機能を試す100(不正なURLパラメータのリクエスト編)
はじめに
Rails 6 に追加された新機能を試す第100段。 今回は、 不正なURLパラメータのリクエスト編です。
Rails 6 では、 不正なパラメータのリクエストの場合でもエラーにならずに、Railsのエラー画面を表示するようになりました。Ruby 2.6.5, Rails 6.0.0 で確認しました。
$ rails --version Rails 6.0.0今回は、Userの CRUD を作って確認します。
Rails プロジェクトを作る
$ rails new rails_sandbox cd rails_sandboxUser の CRUD を作る
$ bin/rails g scaffold User nameデータベースのマイグレーションを実行する
$ bin/rails db:create db:migrate不正なパラメータのURLにアクセスする
ここで、 rails server を実行して、不正なパラメータつきの存在しないURLにブラウザからアクセスしてみます。
今回は、 http://localhost:3000/foo?x=1&x[y]=2 にアクセスしてみますエラー画面が表示されます。
このときパラメータの情報は画面には表示されません。
試しに不正ではないパラメータを使い http://localhost:3000/foo?x=1 にアクセスしてみます。
このときは、パラメータの情報が画面に表示されます。
Rails 5 では
Rails 5.2.3 では、 http://localhost:3000/foo?x=1&x[y]=2 にアクセスしたときに Rails のエラー画面は表示されません。
試したソース
試したソースは以下にあります。
https://github.com/suketa/rails_sandbox/tree/try100_malformed_url参考情報
- 投稿日:2019-10-28T11:33:13+09:00
遷移元のコントローラーとアクションを取得して、条件分岐をする
~同じコントローラーのアクションを使って今いるページからのリンク先を変える方法~
起きていたこと
1.新規登録の時(修正前)
/signup/cards
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓/card/show
2.カード情報を追加登録の時(修正前)
/card/new
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓/card/show
"1.新規登録"の時の遷移先を/signup/finishにしたいが
問題のコントローラーを確認すると/signup/finishに飛んでない!!**card_controller.rb(修正前)def pay Payjp.api_key = ENV["PAYJP_ACCESS_KEY"] [省略] if @card.save//保存できたら redirect_to action: "show"//カード情報を表示する else//保存できなかったら redirect_to action: "pay" end end endやりたいこと
/signup/finishを設定してない遷移元のコントローラーとアクションを指定して条件分岐できないだろうか?
=>会員登録の時とユーザー設定ページのそれぞれでcardコントローラーでnewを使用したした時で分けたい
結論:request.referrerを使用する
request.referrerの例遷移元のコントローラーを取得 Rails.application.routes.recognize_path(request.referrer) {:controller=>"users", :action=>"index"} こちらで遷移元の URL が取得できる request.referrer "http://localhost:3000/users"=========================================
request.referrerを実装する
card_controller.rb(修正後)def pay Payjp.api_key = ENV["PAYJP _ACCESS_KEY"] [省略] path = Rails.application.routes.recognize_path(request.referer) if path[:controller] == "card" && path[:action] == "new" //もしも、"card"コントローラでnewを行ったら、 redirect_to action: "show" //showを行う else //違ったらfinishへ飛ばす redirect_to finish_signup_index_path end [省略]修正した結果
1.新規登録の時(修正版)
/signup/cards
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓/signup/finish
falseで読み込まれるため/signup/finishへ飛ぶ実行したところelse //違ったらfinishへ飛ばす redirect_to finish_signup_index_path2.カード情報を追加登録の時
trueのためこちらの結果は修正前と変わらない
参考記事
https://qiita.com/sayama0402/items/ffe96ff76148231a0c22
http://kawahiro.hatenablog.jp/entry/2014/03/21/164449
- 投稿日:2019-10-28T11:04:39+09:00
Ubuntu18.04 で コマンド`$ rails server` を実行した時にエラーが出た話
目的
- サーバをスタートするコマンド
$ rails serverを実行した時のエラー解決法を知る。- ほぼほぼすでに投稿してある記事と内容は一緒である。
Mac で コマンド$ rails server を実行した時にエラーが出た話エラー内容
$ rails s => Booting Puma => Rails 6.0.0 application starting in development => Run `rails server --help` for more startup options RAILS_ENV=development environment is not defined in config/webpacker.yml, falling back to production environment Exiting Traceback (most recent call last): 68: from bin/rails:4:in `<main>' 67: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `require' 66: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291:in `load_dependency' ・ ・ ・ 2: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:84:in `data' 1: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:87:in `load' /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:91:in `rescue in load': Webpacker configuration file not found /home/miriwo/workspace/aaa/config/webpacker.yml. Please run rails webpacker:install Error: No such file or directory @ rb_sysopen - /home/miriwo/workspace/aaa/config/webpacker.yml (RuntimeError)解決方法
- コマンド
$ rails webpacker:installを実行しようとしたところでエラーがでた。$ rails webpacker:install Yarn not installed. Please download and install Yarn from https://yarnpkg.com/lang/en/docs/install/
- yarnが入っていないためエラーが出たようなのでコマンド
brew install yarnを実行して入れた。$ brew install yarn ==> Installing dependencies for yarn: node ==> Installing yarn dependency: node ==> Downloading https://homebrew.bintray.com/bottles/node-12.12.0.high_sierra.bottle.tar.gz ==> Downloading from https://akamai.bintray.com/0f/0f35e88be5a84c808dba472d053af25639b300c095392f63e85d9ae94cf12b20 ・ ・ ・
- コマンド
$ rails webpacker:installを実行した。$ rails webpacker:install RAILS_ENV=development environment is not defined in config/webpacker.yml, falling back to production environment create config/webpacker.yml Copying webpack core config create config/webpack create config/webpack/development.js create config/webpack/environment.js ・ ・ ・
- コマンド
$ rails serverを実行したところ、正常にローカルサーバが起動した。$ rails s => Booting Puma => Rails 6.0.0 application starting in development => Run `rails server --help` for more startup options Puma starting in single mode... * Version 3.12.1 (ruby 2.6.4-p104), codename: Llamas in Pajamas * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://localhost:3000 ・ ・ ・付録
- コマンド
$ rails serverを実行した時のエラーを記載する。$ rails s => Booting Puma => Rails 6.0.0 application starting in development => Run `rails server --help` for more startup options RAILS_ENV=development environment is not defined in config/webpacker.yml, falling back to production environment Exiting Traceback (most recent call last): 68: from bin/rails:4:in `<main>' 67: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `require' 66: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291:in `load_dependency' 65: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `block in require' 64: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require' 63: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi' 62: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register' 61: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi' 60: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require' 59: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/commands.rb:18:in `<main>' 58: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/command.rb:46:in `invoke' 57: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/command/base.rb:65:in `perform' 56: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/thor-0.20.3/lib/thor.rb:387:in `dispatch' 55: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/thor-0.20.3/lib/thor/invocation.rb:126:in `invoke_command' 54: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/thor-0.20.3/lib/thor/command.rb:27:in `run' 53: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/commands/server/server_command.rb:138:in `perform' 52: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/commands/server/server_command.rb:138:in `tap' 51: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/commands/server/server_command.rb:147:in `block in perform' 50: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/commands/server/server_command.rb:37:in `start' 49: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/commands/server/server_command.rb:77:in `log_to_stdout' 48: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/server.rb:354:in `wrapped_app' 47: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/server.rb:219:in `app' 46: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/server.rb:319:in `build_app_and_options_from_config' 45: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/builder.rb:40:in `parse_file' 44: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/builder.rb:49:in `new_from_string' 43: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/builder.rb:49:in `eval' 42: from config.ru:in `<main>' 41: from config.ru:in `new' 40: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/builder.rb:55:in `initialize' 39: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/builder.rb:55:in `instance_eval' 38: from config.ru:3:in `block in <main>' 37: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:48:in `require_relative' 36: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `require' 35: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291:in `load_dependency' 34: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `block in require' 33: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/zeitwerk-2.2.0/lib/zeitwerk/kernel.rb:23:in `require' 32: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require' 31: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi' 30: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register' 29: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi' 28: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require' 27: from /home/miriwo/workspace/aaa/config/environment.rb:5:in `<main>' 26: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/application.rb:363:in `initialize!' 25: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/initializable.rb:60:in `run_initializers' 24: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:205:in `tsort_each' 23: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:226:in `tsort_each' 22: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:347:in `each_strongly_connected_component' 21: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:347:in `call' 20: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:347:in `each' 19: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:349:in `block in each_strongly_connected_component' 18: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:431:in `each_strongly_connected_component_from' 17: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component' 16: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:228:in `block in tsort_each' 15: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/initializable.rb:61:in `block in run_initializers' 14: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/initializable.rb:32:in `run' 13: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/initializable.rb:32:in `instance_exec' 12: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/railtie.rb:84:in `block in <class:Engine>' 11: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker.rb:27:in `bootstrap' 10: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/commands.rb:14:in `bootstrap' 9: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/manifest.rb:18:in `refresh' 8: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/manifest.rb:83:in `load' 7: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:47:in `public_manifest_path' 6: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:43:in `public_output_path' 5: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:39:in `public_path' 4: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:80:in `fetch' 3: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:84:in `data' 2: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:88:in `load' 1: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:88:in `read' /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:88:in `read': No such file or directory @ rb_sysopen - /home/miriwo/workspace/aaa/config/webpacker.yml (Errno::ENOENT) 67: from bin/rails:4:in `<main>' 66: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `require' 65: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291:in `load_dependency' 64: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `block in require' 63: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require' 62: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi' 61: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register' 60: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi' 59: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require' 58: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/commands.rb:18:in `<main>' 57: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/command.rb:46:in `invoke' 56: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/command/base.rb:65:in `perform' 55: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/thor-0.20.3/lib/thor.rb:387:in `dispatch' 54: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/thor-0.20.3/lib/thor/invocation.rb:126:in `invoke_command' 53: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/thor-0.20.3/lib/thor/command.rb:27:in `run' 52: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/commands/server/server_command.rb:138:in `perform' 51: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/commands/server/server_command.rb:138:in `tap' 50: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/commands/server/server_command.rb:147:in `block in perform' 49: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/commands/server/server_command.rb:37:in `start' 48: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/commands/server/server_command.rb:77:in `log_to_stdout' 47: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/server.rb:354:in `wrapped_app' 46: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/server.rb:219:in `app' 45: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/server.rb:319:in `build_app_and_options_from_config' 44: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/builder.rb:40:in `parse_file' 43: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/builder.rb:49:in `new_from_string' 42: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/builder.rb:49:in `eval' 41: from config.ru:in `<main>' 40: from config.ru:in `new' 39: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/builder.rb:55:in `initialize' 38: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/rack-2.0.7/lib/rack/builder.rb:55:in `instance_eval' 37: from config.ru:3:in `block in <main>' 36: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:48:in `require_relative' 35: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `require' 34: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291:in `load_dependency' 33: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `block in require' 32: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/zeitwerk-2.2.0/lib/zeitwerk/kernel.rb:23:in `require' 31: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require' 30: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi' 29: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register' 28: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi' 27: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require' 26: from /home/miriwo/workspace/aaa/config/environment.rb:5:in `<main>' 25: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/application.rb:363:in `initialize!' 24: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/initializable.rb:60:in `run_initializers' 23: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:205:in `tsort_each' 22: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:226:in `tsort_each' 21: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:347:in `each_strongly_connected_component' 20: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:347:in `call' 19: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:347:in `each' 18: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:349:in `block in each_strongly_connected_component' 17: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:431:in `each_strongly_connected_component_from' 16: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component' 15: from /home/linuxbrew/.linuxbrew/Cellar/ruby/2.6.5/lib/ruby/2.6.0/tsort.rb:228:in `block in tsort_each' 14: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/initializable.rb:61:in `block in run_initializers' 13: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/initializable.rb:32:in `run' 12: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/initializable.rb:32:in `instance_exec' 11: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/railtie.rb:84:in `block in <class:Engine>' 10: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker.rb:27:in `bootstrap' 9: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/commands.rb:14:in `bootstrap' 8: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/manifest.rb:18:in `refresh' 7: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/manifest.rb:83:in `load' 6: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:47:in `public_manifest_path' 5: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:43:in `public_output_path' 4: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:39:in `public_path' 3: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:80:in `fetch' 2: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:84:in `data' 1: from /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:87:in `load' /home/linuxbrew/.linuxbrew/lib/ruby/gems/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:91:in `rescue in load': Webpacker configuration file not found /home/miriwo/workspace/aaa/config/webpacker.yml. Please run rails webpacker:install Error: No such file or directory @ rb_sysopen - /home/miriwo/workspace/aaa/config/webpacker.yml (RuntimeError)
- 投稿日:2019-10-28T08:10:26+09:00
【初心者向け】RailsにRspecを導入してみた話
Rspecとは
Wikipediaから引用すると、Rspecとは
RSpec is a 'Domain Specific Language' (DSL) testing tool written in Ruby to test Ruby code.
自分なりに和訳してみると、
RSpecとはRubyによって書かれた、Rubyによるコードをテストするための'ドメイン固有言語'なテストツールである。
といった感じでしょうか。
つまりは、Ruby用のテストツールでして、Rubyベースのフレームワークのテストに使われています。
ちなみに @jnchito さんのこちらのスライドによると2015年時点では、利用者および情報量の観点ではRSpecが多数派のようです。
Gemfile
今回はこちらの公式ドキュメントを参考にRailsに導入していきます。
手順は簡単で、まずはGemfileを編集し、下記のコードを追加します。
Gemfilegroup :development, :test do gem 'rspec-rails', '~> 3.8' endその後、プロジェクトのディレクトリで
$ bundle install $ rails generate rspec:install create .rspec create spec create spec/spec_helper.rb create spec/rails_helper.rbと入力すれば完了です。
bundle installでRSpecのダウンロードとインストールを行い、
rails generate rspec:installでRSpecに必須な設定ファイルが作成されます。これで準備が完了です。
あとはテストコードを作成し、コンソールにて
$ bundle exec rspecと叩けば、テストが実行されます。
Springによる高速化
ここまでの内容でRSpecを用いてテストを実施することができますが、Springを用いることで、テストの所要時間を短縮することができます。
公式ドキュメントには
Spring is a Rails application preloader. It speeds up development by keeping your application running in the background so you don't need to boot it every time you run a test, rake task or migration.
とありまして、こちらも和訳してみると、
SpringはRailsアプリケーションにおけるプリローダーです。アプリケーション実行時にバックグラウンドで起動し続けることにより、テストやレイクタスク、マイグレーション毎にアプリケーションを起動させる必要がなくなるので、開発の速度があげることができます。
といった感じでしょうか。
ちなみにSpringはRailsのバージョン4.2から
rails newを実行時に自動でインストールされるようになっています。というわけで、今回はRSpecを導入するにあたって、こちらを参考にSpringも利用することにしました。
こちらも利用は簡単です。
まずは、Gemfileに下記のように追加します。
Gemfilegroup :development, :test do gem 'rspec-rails', '~> 3.8' gem 'spring-commands-rspec' end先ほど示したGemfileに
gem 'spring-commands-rspec'を追加しただけです。追加したら、
$ bundle exec spring binstub rspecとコンソールで入力し、スタブファイル(bin/rspec)を作成します。
これで準備は完了です。
あとは
$ bundle exec bin/rspecと叩けばSpringとRSpecを用いたテストが実施されます。
実行時間の調査
準備ができたので、実際にテストコードの所要時間を比較してみます。
まず、テストコードを作成したいので、scaffoldを実行します。(scaffoldについても記事にしているので、参考にしてみてください。)
今回は下記のコマンドを実行しました。
$ rails generate scaffold Task title:string priority:integerこれによりRSpecのテストコードも自動で作成されますので、今回はこのテストコードを用います。
というわけでSpringを使った結果と使わなかった結果がこちらです。
Spring未使用$ bundle exec rspec (省略) Finished in 3.66 seconds (files took 21.22 seconds to load) 27 examples, 0 failures, 13 pendingSpring使用$ bundle exec bin/rspec (省略) Finished in 3.59 seconds (files took 2.29 seconds to load) 27 examples, 0 failures, 13 pending比べてみますとSpring使用時の方が読み込みにかかった時間が圧倒的に短いですし、テスト自体の実行時間もわずかに速いです。
今回の例ですと、テストケースが40ケースですが、テストの数がより増えてくるとより威力が発揮されるのではないかと思います。
まとめ
RSpecを導入する場合は
1. Gemのインストール
2. コマンドの実行
とかなり少ないステップで用いることができます。また、Springを用いることで、テストを高速化することができます。
ちなみにRSpecを導入するタイミングによっては、Minitestによって作られている「test」ディレクトリが残ったままになってしまいますので、削除するのをお忘れなく。
最後までお読みいただきありがとうございました。
参考文献
RSpec基礎情報(Wikipedia)
https://en.wikipedia.org/wiki/RSpecRSpecとMinitest、使うならどっち?
https://speakerdeck.com/jnchito/number-kanrk06RSpec公式リポジトリ
https://github.com/rspec/rspec-railsSpring公式リポジトリ
https://github.com/rails/springspring-commands-rspec公式リポジトリ
https://github.com/jonleighton/spring-commands-rspec
- 投稿日:2019-10-28T01:49:57+09:00
lazysizesでRails画像遅延読み込み
Railsを使った画像遅延読み込み
画像遅延読み込みとは
遅延読み込みという技術は、Webサイトに表示される画像を一度に読み込まず、必要に応じて必要な分だけ読み込むというものです。不必要な画像の読み込みを後回しにして、画像以外のCSSやJSファイルの読み込みが先に行われます。そうすることで、表示速度を速くすることができます。
https://alaki.co.jp/blog/?p=2527
目的
lazysizesを使用し画像遅延読み込みさせることでWebサイトの表示速度向上を図ります
今回使用するのはlazysizesです。
lazysizesの導入
読み込み
app/views/layouts/application.html.erb<%= javascript_include_tag 'https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.1.2/lazysizes.min.js' %>使い方
下記のように遅延させたいimgタグにclass
lazyloadをつけると画像を遅延読み込みし、読み込むとclassがlazyloadからlazyloadedに変わります
data-srcは遅延読み込みさせたい画像パスを入れます<img data-src="画像パス" class="lazyload">ここでrailsで
image_tagのように使えるようにするためにhelperを作成しますhelper作成
app/helpers/application_helper.rbdef lazysizes_image_tag(source, options={}) options['data-src'] = source if options[:class].blank? options[:class] = "lazyload" else options[:class] = "lazyload #{options[:class]}" end image_tag('画像を読み完了してない時の画像パス', options) + ('<noscript><img src=' + source +'></noscript>').html_safe endSEO対策
<noscript>を付け足している理由としてはクローラはスクロールしない=画像が読み込まれないので対象画像がインデックスされません。
そこで<noscript>の中に<img>を入れることでインデックス対象にしています。呼び出し
<%= lazysizes_image_tag '画像パス' %>これで画像の遅延読み込みが可能になりました。
参考記事
jQuery Lazyloadプラグインで遅延読み込み
lazysizesの使い方を通して学ぶ、画像の遅延読み込みとレスポンシブイメージの基本
noscript内のコンテンツをGoogleは無視するが画像は例外的にインデックスする
- 投稿日:2019-10-28T00:12:49+09:00
オリジナルアプリにパートナー申請機能を実装する
概要
- オリジナルアプリ作成にあたり、ユーザ(current_user)が他ユーザに対してパートナー申請をする画面をトップページ(toppages#index)に実装したい。
- 申請手順は以下の通りとなる。
- 自分(ユーザA)がパートナー(ユーザB)に対して招待を送る。その際にユーザAは「秘密の言葉」を設定しておく。
- パートナーのトップページに「招待が届きました」というメッセージが届き、それを「承認」か「拒否」かを選択する。承認する場合にはユーザAが設定した「秘密の言葉」を入力する必要がある。
- 承認された場合はユーザAとユーザBはパートナーとなる。
- ユーザと他ユーザがパートナーである事は中間テーブルrelationshipsに定義する。
手順
パートナー申請フォーム作成
中間テーブルrelationshipsにて多対多の関係(ユーザと他ユーザがパートナーである状態)を表す。
- 中間テーブルrelationshipsのカラム構成
id user_id partner_id status secret_words form_withを用い、relationshipsテーブルにデータが登録されるようにする。
relationshipsのパーシャルでパートナー申請フォームを作成する。relationships/_offer_form.html.erb<div class="row"> <div class="col-sm-6 offset-sm-3"> <%= form_with(model: relationship, local: true) do |f| %> <div class="form-group"> # relationshipテーブルに無いデータの入力の為、"f.~"ではなく"~_tag"を用いる # 初期値をテキストボックスに表示しておきたい場合、""内に値を入れる(今回は不要の為、ブランク) <%= label_tag :name, "パートナー申請先(ユーザ名)" %> <%= text_field_tag :name, "", class: "form-control" %> </div> <div class="form-group"> <%= f.label :secret_words, "秘密の言葉" %> <%= f.text_field :secret_words, class: "form-control" %> </div> <%= hidden_field_tag :status, "承認待ち" %> <%= f.submit "招待する", class: "btn btn-primary btn-block" %> <% end %> </div> </div>パートナー申請画面作成
relationshipsのパーシャルで作成した申請フォームをrenderで読み込む。
views/toppages/index.html.erb<div class="text-center"> <h1>パートナー申請画面</h1> </div> # classを跨ぐ場合はインスタンス変数を用いるとclass間で依存関係が出来てしまうので、使用しないほうが良い <%= render "relationships/offer_form", relationship: @relationship %>toppages controllerの実装
relationshipsのパーシャルで申請フォームを作成した為、インスタンス変数もRelationshipsControllerで定義するものだと勘違いしやすいが、それは誤りである。仮に別クラスのパーシャルであったとしてもviewに表示されているインスタンス変数はそのアクションを定義しているcontrollerに紐づいている為、今回の場合はインスタンス変数(@relationship)はtoppages#indexで定義する。
controllers/toppages_controller.rbclass ToppagesController < ApplicationController def index if logged_in? # インスタンス変数を@relationshipとし、form_withのmodel引数に設定してあげることで # action先をRelationshipsController#createに暗に飛ばすことが出来る @relationship = current_user.relationships.build end end end(補足情報)
current_userとlogged_in?のメソッドはSessionsHelperにて定義している。
helpers/sessions_helper.rbmodule SessionsHelper def current_user @current_user ||= User.find_by(id: session[:user_id]) end def logged_in? !!current_user end endhelperはviewでのみしか機能しないので、controllerで使用したい場合はmix-inをする。
今回、ToppagesControllerで使用したいが、他でも使用する可能性が高い為、全体に適用すべくApplicationControllerにmix-inしておく。controllers/application_contoller.rbclass ApplicationController < ActionController::Base # SessionsHelperをmix-in include SessionsHelper private def require_user_logged_in unless logged_in? redirect_to login_url end end end
- 投稿日:2019-10-28T00:11:04+09:00
RSpec導入方法
環境
- Mac OS
- Ruby 2.6.3
- Rails 5.2.3
- MySQL 8.0
RSpecについて
TDD(テスト駆動開発)で使用される、
Rubyの代表的なテスティングフレームワーク。TDD(テスト駆動開発)とは
- 先にテストコードを書き実行、テストを失敗させる(レッド)
- テストコードが成功するようにコードを書く(グリーン)
- テストコードを実行し、テストを成功させる(リファクタリング)
を繰り返し、ある程度のところでリファクタリングをする
というように開発を進めていく手法。
- バグを開発段階で発見、修正できる
- テストを繰り返すことで実装するシステムへの理解が深まる
- 有効なリファクタリングかどうかの確認がしやすい
などのメリットがある。
Capybaraについて
WebアプリケーションのE2Eテスト
(単体テストとは違い、システム全体を実稼働時に近い状況で動かしつつテストする手法)
用のテストフレームワーク。FactoryBotについて
テスト用のデータの作成をサポートするgem
テスト用のデータを簡単に作成し、テストから呼び出して使用できる。【1】 gemをインストールする
Gemfilegroup :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] endGemfileの上記の部分に
gem 'rspec-rails', '~> 3.7' gem 'factory_bot_rails', '~> 4.11'を追加して下記のようにする。
Gemfilegroup :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] gem 'rspec-rails', '~> 3.7' gem 'factory_bot_rails', '~> 4.11' endその後bundle installを実行する。
$ bundle【2】 RSpecの設定ファイルを作成する
$ rails g rspec:install上記のコマンドを実行しRSpecの設定ファイルを作成する。
その後、元々あったtestディレクトリ(Minitestで使うもの)を削除する。
$ rm -r ./test【3】 Capybaraを使う準備をする
spec_helper.rb# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration RSpec.configure do |config| # rspec-expectations config goes here. You can use an alternate # assertion/expectation library such as wrong or the stdlib/minitest # assertions if you prefer.作成されたspecディレクトリにある
上記のようなspec_helper.rbに対して必要なコードを加え、下記のようにする。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.感じたこと
RSpecはどうやって導入するんだっけ?
と忘れてしまう事もあるので自分用のメモとしてさらっとまとめました!(笑)
まだまだ勉強中の身なのでしっかり学習していきます!!

















