20190503のRailsに関する記事は17件です。

Day002 webエンジニアへの道 - Ruby on Railsの基礎を学ぶ -

こんにちは。
webエンジニアを目指すtomoです。

エンジニアの勉強をしている日々の学びをQiitaに記録しています。

私自身の頭の整理と今後迷った時のリファレンスも兼ねて書き連ねていきますが、同じようにエンジニア転職を考えている方の参考にもなればと考えています。
また、「ここ間違ってる!こっちが正しい!」といったご指摘もあれば頂けると嬉しいです?


前回は仮想マシンの環境設定を行いました。

しかし、実際にRuby on railsを使い始めたところ必要な関連ソフトが足りずエラーが連発しました。

必要な関連ソフトは何かなどちゃんと把握した上で進めたいのですが、それでは時間がいくらあっても足りなさそうなので、関連ソフトの理解は後にしてまずはdot-installのレッスン通りCentOS6を用いた環境で学習を進めることにします。

また、ひとつひとつのコードを全て書き写しているとキリがないので、学習を進める中で調べたことやエラー対応したことに絞って記述していきます。

railsサーバの起動

commandline
rails server -b [ipアドレス] -d

-b オプションでバインドするipアドレスを指定。
-d オプションでデーモンとしてサーバを起動。
デーモンとはメモリ上に常駐し、いつでも処理できるよう待機するプログラムのこと。

[参考]
railsコマンド(rails)
デーモン (daemon)

rails(5.1.4)以降ではリンク先が表示されないため、ブラウザに直接http://[ipアドレス]:3000と入力して動作確認する。

scaffoldで作成したファイルを削除する

commandline
rails destroy scaffold [name]

[name]は削除したいscaffoldの名前。
rails g scaffold [name]で要素を間違えて指定した時に有用

[参考]
scaffoldで作成したファイルを全削除

Modelの作成

rails g model Post title:string body:text

Post → Modelは個々のデータ構造を定義するので単数形で指定する。
string → 1行テキスト
text → 複数行のテキスト

追加した変更が反映されない時の対応

Transmit5を利用して仮想マシンとのファイル転送を行っていたが、エディタで保存したはずの変更がブラウザに反映されなかった。

原因:Transmitとの接続が途中で切れていたため。(Transmit上で「サーバから切断」を行うと、再接続しても既に開いているエディタのファイルとのリンクが切れてしまう)

tips:ブラウザまたはコンソール上で見える簡単な変更(htmlの文章やplaceholderなど)を加えてみると、どこに不具合があるか特定しやすい。目で見て確認しづらい処理の不具合をチェックする場合は処理の内容を簡素化(文字列の出力など)すると特定しやすい。

★メモ

*後日調べること & 気づいたこと
  • kill -9 [プロセス番号] → killコマンドで-9以外の場合どうなる?
  • Convention over Configuration → どのファイルがどこのディレクトリにあるか、指定は単数形か複数形かといった細かいルールがrailsには設定されている。ということらしいので調べる。
  • Active Recordとは何か?
  • MVCのフローを理解するため整理して図に書き出す。
  • 開発環境構築が始めの1歩だと思っていたが、「どのパッケージをどのバージョンで入れるか」というのは難易度が高いので詳しくは後で学んだ方が良い...

さいごに

2日目にして完全に自分用の学習メモと化してきました...

続けていった後で、「うわ、このとき自分はこんな簡単なことで悩んでたのかよ...」ってなれるよう精進します。


twitterもやっているので、宜しければフォローお願いします!
@tomo_tech_

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

docker で rspec の system spec を実行するための設定メモ

はじめに

docker 環境で rspec の system spec を実行させるための設定に手間取ったので、メモ代わりに書いておきます。
railsが動くdocker の image に chrome をインストールするのもちょっとなあと思ったので、 selenium/standalone-chrome-debug
を使う方法です。

確認した Rails 環境は、5.2.2 です。

ちなみに Gemfile でバージョン指定はしていませんが、Gemfile.lock を確認したところ

capybara (3.14.0)
rspec-rails (3.8.2)
selenium-webdriver (3.141.0)

となってました。

docker-compose.yml の編集

chrome が動作するように設定を追加します。
Rails は web で動作します。

docker-compose.yml
version: '3'

services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - bundle:/usr/local/bundle
    tty: true
    environment:
      # この環境変数を追加
      - "SELENIUM_DRIVER_URL=http://selenium_chrome:4444/wd/hub"
  # 以下の4行を追加
  selenium_chrome:
    image: selenium/standalone-chrome-debug
    logging:
      driver: none
  db:
    image: postgres:10.7-alpine
    volumes:
      - pgsqldb:/var/lib/postgresql/data
    environment:
      - "POSTGRES_USER=xxxx"
      - "POSTGRES_PASSWORD=xxxx"
volumes:
  pgsqldb:
  bundle:

chrome を動作させるために、selenium_chrome を追加しています。
logging の設定を driver: none にしているのは、不要なログ出力を抑制するためです。

rspec は web で実行しますが、 chrome は、selenium_chrome で動作させるため、web 側からアクセスできるように
環境変数 SELENIUM_DRIVER_URL を web 側に追加しています。

Gemfile を編集する

gem ファイルに rspec-rails を追加します。
chromedriver-helper を削除します。webdrivers gem は追加しません。

Gemfile
group :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  gem 'rspec-rails'
end

docker 環境で、bundle install を実行する

docker 環境で追加した gem をインストールします。

$ docker-compose up -d
$ docker-compose exec web bash

# 以下は web コンテナ内で実行します。
$ bundle install

rspec の初期設定をする。

続けて、rspec の初期設定をします。

# 以下は web コンテナ内で実行します。
$ bin/rails g rspec:install

system spec の設定をする。

system spec の設定をするために、 spec/rails_helper.rb を編集し、 spec/support/capybara.rb を追加します。

spec/rails_helper.rb
# 以下の1行を有効にします。
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }

# Checks for pending migrations and applies them before tests are run.
# If you are not using ActiveRecord, you can remove these lines.
spec/support/capybara.rb
require 'capybara/rspec'

RSpec.configure do |config|
  config.before(:each, type: :system) do |config|
    driven_by :selenium, using: :headless_chrome, options: {
      browser: :remote,
      url: ENV.fetch("SELENIUM_DRIVER_URL"),
      desired_capabilities: :chrome
    }
    Capybara.server_host = 'web'
    Capybara.app_host='http://web'
  end
end

spec/support/capybara.rb 内で selenium_chrome 側の headless chrome を利用するための設定をしています。
web コンテナ側から selenium_chrome コンテナ の chrome を使用するために、 options の中で、 urlSELENIUM_DRIVER_URL 環境変数の値を設定しています。
headless chrome からは、ローカル環境ではなく、 web コンテナ側の rails アプリを表示してテストする必要があるため、
Capybara.server_hostCapybara.app_host を設定しています。

参考情報

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker で RSpec の System Spec を実行するための設定メモ

はじめに

docker 環境で rspec の system spec を実行させるための設定に手間取ったので、メモ代わりに書いておきます。
railsが動くdocker の image に chrome をインストールするのもちょっとなあと思ったので、 selenium/standalone-chrome-debug
を使う方法です。

確認した Rails 環境は、5.2.2 です。

ちなみに Gemfile でバージョン指定はしていませんが、Gemfile.lock を確認したところ

capybara (3.14.0)
rspec-rails (3.8.2)
selenium-webdriver (3.141.0)

となってました。

docker-compose.yml の編集

chrome が動作するように設定を追加します。
Rails は web で動作します。

docker-compose.yml
version: '3'

services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - bundle:/usr/local/bundle
    tty: true
    environment:
      # この環境変数を追加
      - "SELENIUM_DRIVER_URL=http://selenium_chrome:4444/wd/hub"
  # 以下の4行を追加
  selenium_chrome:
    image: selenium/standalone-chrome-debug
    logging:
      driver: none
  db:
    image: postgres:10.7-alpine
    volumes:
      - pgsqldb:/var/lib/postgresql/data
    environment:
      - "POSTGRES_USER=xxxx"
      - "POSTGRES_PASSWORD=xxxx"
volumes:
  pgsqldb:
  bundle:

chrome を動作させるために、selenium_chrome を追加しています。
logging の設定を driver: none にしているのは、不要なログ出力を抑制するためです。

rspec は web で実行しますが、 chrome は、selenium_chrome で動作させるため、web 側からアクセスできるように
環境変数 SELENIUM_DRIVER_URL を web 側に追加しています。

Gemfile を編集する

gem ファイルに rspec-rails を追加します。
chromedriver-helper を削除します。webdrivers gem は追加しません。

Gemfile
group :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  gem 'rspec-rails'
end

docker 環境で、bundle install を実行する

docker 環境で追加した gem をインストールします。

$ docker-compose up -d
$ docker-compose exec web bash

# 以下は web コンテナ内で実行します。
$ bundle install

rspec の初期設定をする。

続けて、rspec の初期設定をします。

# 以下は web コンテナ内で実行します。
$ bin/rails g rspec:install

system spec の設定をする。

system spec の設定をするために、 spec/rails_helper.rb を編集し、 spec/support/capybara.rb を追加します。

spec/rails_helper.rb
# 以下の1行を有効にします。
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }

# Checks for pending migrations and applies them before tests are run.
# If you are not using ActiveRecord, you can remove these lines.
spec/support/capybara.rb
require 'capybara/rspec'

RSpec.configure do |config|
  config.before(:each, type: :system) do |config|
    driven_by :selenium, using: :headless_chrome, options: {
      browser: :remote,
      url: ENV.fetch("SELENIUM_DRIVER_URL"),
      desired_capabilities: :chrome
    }
    Capybara.server_host = 'web'
    Capybara.app_host='http://web'
  end
end

spec/support/capybara.rb 内で selenium_chrome 側の headless chrome を利用するための設定をしています。
web コンテナ側から selenium_chrome コンテナ の chrome を使用するために、 options の中で、 urlSELENIUM_DRIVER_URL 環境変数の値を設定しています。
headless chrome からは、ローカル環境ではなく、 web コンテナ側の rails アプリを表示してテストする必要があるため、
Capybara.server_hostCapybara.app_host を設定しています。

参考情報

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsのclass_methodsがやっていること

module ModuleA
  extend ActiveSupport::Concern

  class_methods do
    def method_a
       puts "method_a"
    end
  end

end

class ClassA
  include ModuleA
end

ClassA.method_a #=> "method_a"

Moduleのメソッドをクラスメソッドとして使用できるようにするために、class_methodsを使う。
class_methodsで囲んだ箇所をActiveSupportのConcernがextendしてくれる。

class_methodsがないと‥

module ModuleA

  def method_a
     puts "method_a"
  end

end

class ClassA
  include ModuleA
end

ClassA.method_a #=> "NoMethodError: undefined method `method_a' for ClassA:Class"
instance_a = ClassA.new
instance_a.method_a #=> "method_a"

ModuleAのメソッドはClassAのインスタンスメソッドになる。

ちなみに

module ModuleA
  extend ActiveSupport::Concern

  class_methods do
    def self.method_a
      puts "self_method_a"
    end
  end

end

class ClassA
  include ModuleA
end

当たり前だが、ModuleAのself.method_aはあくまでもModuleAの特異メソッドだからClassAからもインスタンスからも呼び出すことはできない。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsでSimStringを使う

概要

  • railsの検索で曖昧な語句を検索するためのモジュール (gem) です。
  • 検索はsimstring_pure をつかっています。

ソース

https://github.com/junara/simstring_searchable

使い方

インストール

gem 'simstring_searchable', github: 'junara/simstring_searchable'
bundle install

使用したいモデルに SimstringSearchable を追加する

your_model.rb
class YourModel < ActiveRecord
  include SimstringSearchable

これで準備完了

検索

インデックス作成

最初にインデックスを作成する必要があります。インデックスの作成は、 create_simstring_index methodでおこないます。
引数には、検索したい(インデックスを作成したい)カラム名を指定してください。
インデックス作成後、追加したデータでインデックスを更新したい場合も同じメソッドを実行してください。(更新のみをおこなうメソッドは用意していません)
作成された、インデックスは後述の remove_simstring_index で破棄するまで有効です。

irb> YourModel.create_simstring_index(:name)

オプションとして 連続したn個の文字で分割するかを第2引数に渡して(整数)設定することができます。デフォルトは3です。

検索

検索は、 simstring_search_result でおこないます。
第1引数に検索したいカラム。第2引数に 検索文字列 を入れてください。」

irb> YourModel.simstring_search_result(:name, '検索文字列')

オプションとして閾値(threshold (0から1。1が最もマッチしていることを示す))とデータ数(limit。上位いくつのデータを表示するか)を設定することができます。閾値のデフォルトは0.5、データ数のデフォルトは10です。

最もマッチしたデータのみ取得する場合は、 simstring_find_by を使ってください。イメージとしては、railsのfind_byに似たかんじのメソッドです。

インデックスの破棄

作成されたインデックスは破棄するまで有効です。メモリを喰うので、使わなくなったら破棄してください。

irb> YourModel.remove_simstring_index(:name)

なお、まとめてインデックスを破棄できるメソッドはこちらです。

irb> YourModel.remove_whole_simstring_indexes

アドバンスド

インデックス作成の際に、ブロックを渡すことで文字列を加工する事ができます。
全角英数字を半角英数字に修正したいとうありましたらこちらを利用してください。

下記では、空白(全角 or 半角)を削除してインデックスを作成する例です。

irb> YourModel.create_simstring_index(:name, gram = 3) {|str| str.gsub(/( | )/, '')} # replace space by ''

その他

検索結果が空 [] or nil の場合はthresholdの値を低く(たとえば 0.1) して検討してください。
また、 結果の順位が印象と合わない場合は、 gram の値を変更すると良くなることがありますので調整してみてください。

以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

windowsでrails + elasticsearch環境を構築する

はじめに

最近、個人的に作っているアプリで全文検索を使ってみたくなり、Elasticsearchの環境を構築しました。

しかし、家のPCのOSはWindowsで、Qiitaや開発ブログなどでは大体Mac(Linux)で書かれていて、Windowsを使っている身としては肩身が狭いです。。。そして、Elasticsearchを取り入れる時にも、エラーが結構出ました。

Windows + Railsでelasticsearchを取り入れた時に躓いた部分などを備忘録的に投稿します。elasticsearch初心者なので、初歩的なエラーが多いです。

アプリにelasticsearchをセットアップ

なお、セットアップにはこちらを参考にさせて頂きました。

gem 'elasticsearch-model', git: 'git://github.com/elasticsearch/elasticsearch-rails.git'
gem 'elasticsearch-rails', git: 'git://github.com/elasticsearch/elasticsearch-rails.git'
class PoolHall < ActiveRecord::Base
  include Elasticsearch::Model
end

以上をGemfileに記載して、bundle installを実行。Elasticsearch::Modelをincludeして、ためしにPoolHall.search 'test'をしてみました。

検索は出来ているように思えましたが、検索結果を出力してみようと思い、resultsのeachやmapを呼び出すと以下のようなエラーが出ました。

Faraday::ConnectionFailed in PoolHallsController#new

Failed to open TCP connection to localhost:9200 (Connection refused - connect(2) for "localhost" port 9200)
Extracted source (around line #6):

調べたところ、elasticsearchをlocalhost:9200で起動しないと駄目だと知りました。

elasticsearchをインストール

elasticsearchはJavaを実行できる環境が必要なので、こちらからJREをダウンロード。

Javaはインストールしていたので、実行できるかと思いきや、elasticsearchを実行するとエラーが出ました。こちらは、Javaのバージョンが古かったので、アップデートしたら実行できました。 Java SE Runtime Environment 8u211のWindows x86 Offlineをダウンロードし、インストールしました。

こちらのDownloadsのWindowsから、elasticsearchをダウンロード。バージョンは7.0.1です。

elasticsearchをダウンロードし、解凍したら、elasticsearch-7.0.1-windows-x86_64.zip\elasticsearch-7.0.1\bin\elasticsearch.batを実行すると、elasticsearchが起動できます。

インデックスを作成

以下のコマンドを実行。

rails c

elasticsearchを起動し、インデックスを作成し、登録。

PoolHall.__elasticsearch__.create_index! force: true
PoolHall.import

いちいち、コンソールを起動してやるのも面倒なので、こちらを参考にタスクを作成。

# rails g task elasticsearchで作成
namespace :elasticsearch do
  desc 'Elasticsearch のindex作成'
  task create_index: :environment do
    PoolHall.__elasticsearch__.create_index! force: true
  end

  desc 'Article を Elasticsearch に登録'
  task import_hall: :environment do
    PoolHall.import
  end
end

これで以下のコマンドでインデックスを作成できる。

rake elasticsearch:create_index
rake elasticsearch:import_hall

検索結果をactiverecordとして扱いたい

これで、検索の準備が整い、検索をしてみました。

@hall = PoolHall.search(params[:word)

viewで、検索結果を表示しようとしたところ、インスタンスメソッドを呼び出すところでメソッドが定義されていないとエラーが発生しました。

thumbnailというメソッドは、PoolHallモデルのインスタンスメソッドで、サムネイルを返すメソッドでした。

<%= @hall.each do |h| %>
  <%= image_tag h.thumbnail %>
<% end %>

調べてみると、検索結果はElasticSearchのオブジェクトとして返ってきていたので、当然の結果でした。activerecordとして扱いたい場合は以下の通り。

@hall = PoolHall.search(params[:word).records

おわりに

elasticsearchは非常に便利ですね。
今後はkibanaなどにも手を出していきたいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

progateの「Ruby on Rails」レッスンを自分のPCで再現したい。が、データベースの構築方法がわかりません。

現在、Progateでプログラミング学習をしている者です。
Webアプリを開発したく、Ruby on Railsのレッスンを学んでいます。

レッスンで学んだSNSアプリを自分のPCにて開発しているのですが、データベースの構築の方法がわからず、同じように開発をすることができません。

開発はatomを使用しております。

お分かりの方、教えていただけますと幸いです。

PCなどの状況は下記の通りです。

OS:macOS Mojave(バージョン10.14.4)
Rails 5.0.3

↑progateのコラム通りに構築をしました。

お分かりの方、教えていただけますと幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

f.collection_selectについて

題記について、Railsドキュメントを見てもあまり良く理解出来なかったので、まとめてみる。

Railsドキュメントより

  1. form_for, form_tagにて使用可
  2. 取ることができる引数について、Railsドキュメントによると、

(プロパティ名, オブジェクトの配列, value属性の項目, テキストの項目 [, オプション])

と記載されており、例では、

<%= f.collection_select(:name, @categories, :id, :name) %>

とコードを書くと、HTMLは、

<select id="page_name" name="page[name]">
  <option value="1">Railsの基礎知識</option>
  <option value="2">Rubyの基礎知識</option>
</select>

にて生成されるらしい。

参考:Railsドキュメント

もう少し詳しく

Railsドキュメントに挙げられている例をもう少し詳しく見てみる。

状況は?

  1. Pageモデル(テーブル)が存在する。
  2. Pagesテーブルは以下のような構成になっている。
id name
1 Railsの基礎知識
2 Rubyの基礎知識

3.

@categories = Page.all

としてすべてのオブジェクトをインスタンス変数に代入しているとする。

引数と生成されるHTMLページの関係性は?

  1. 第一引数(プロパティ名)は、selectタグのid属性とname属性に関係する。
    id="page_" name="page[]"といった具合に設定される。※今回の場合は:nameとしており、pageはモデル名となっている。
  2. 第二引数(オブジェクトの配列)は、何となく理解できるので省略
  3. 第三引数(value属性の項目)は、value=""にて設定したい値のカラム名が入る。そのため、idカラムの値を設定したい場合は、:idとなる。
  4. 第四引数(テキストの項目)は、optionタグ内のテキストに設定したい値のカラム名が入る。そのため、nameカラムの値を設定したい場合は、:nameとなる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

bundle installでmysql2がエラーになる件

背景

とある教材を見ながらプロジェクトを作成していたところ、bundle install を実行したらエラーが発生したのでメモ。

「Mysqlの導入で発生したエラー解消」という内容になりますが、結論としては「」することにより解消できました。

経緯|実行したコマンド

$ rails new myapp --database=mysql --skip-bundle --skip-test
$ cd myapp
$ bundle install

エラー内容

(省略)
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
(省略)
linking shared-object mysql2/mysql2.bundle
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1

make failed, exit code 2

Gem files will remain installed in /var/folders/mj/93db0vd975799gg9w3nnr3_r0000gn/T/bundler20190503-14531-xlyd6cmysql2-0.5.2/gems/mysql2-0.5.2 for inspection.
Results logged to /var/folders/mj/93db0vd975799gg9w3nnr3_r0000gn/T/bundler20190503-14531-xlyd6cmysql2-0.5.2/extensions/universal-darwin-18/2.3.0/mysql2-0.5.2/gem_make.out


An error occurred while installing mysql2 (0.5.2), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.5.2'` succeeds before bundling.

In Gemfile:
  mysql2

考えたこと

  • そういえばプロジェクト作成のときにDBをmysqlで指定したのは始めてだな。
  • mysql2 0.5.2 をインストールできないということかな。
  • gem install mysql2 -v '0.5.2'を実行しなさいと言ってるのかしら?
  • Gemfile でmysql2 のバージョンは何になってる?
  • ひとまずググるか。

やったこと

Gemfile の確認

gem 'mysql2', '>= 0.3.18', '< 0.6.0'

Gemfile 内の記述は以下の通り。

ダメな部分があるか否かが不明のため、ひとまず確認のみ。

エラーログに記載されているコマンドを実行

$ gem install mysql2 -v '0.5.2'
ERROR:  While executing gem ... (Gem::FilePermissionError)
    You don't have write permissions for the /Library/Ruby/Gems/2.3.0 directory.

結果、エラーの解消にはつながらなかった。

ググる!→このコマンドでエラー解消!【解決】

エラーの原因特定、解消方法を調べてみたところ、下記方法で解決した。

$ bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib --with-cppflags=-I/usr/local/opt/openssl/include"
$ bundle install

その後、下記コマンドを実行することで「You’re on Rails」画面を開くことができたので今回のエラーは解決とする。

$ rails db:create
$ rails s

原因・学び

今回のエラー解消に際し、色々と調べる中で学んだことをメモ。

エラーについて

どうやら、今回は下記エラーログがポイントだった模様。

ld: library not found for -lssl

原因を言語化すると、opensslのパスがビルドの時に必要(ビルドのときにLDFLAGSとかCPPFLAGSとかにパスを追加する記述が必要)ということ。

ld とは?

ldはGNUリンカーと呼ばれるコマンドとのこと。$ man ld で内容を確認できる。

-lssl は、mysql2 gemインストール時にldコマンドに与えられたオプションの一つらしい。

ここでは詳細の掘り下げはせずに置いておく。。

解決策について

bundle config とは?

下記ページにて詳細を確認する事ができた。

http://ruby.studio-kingdom.com/bundler/bundle_config/

コマンドbundle configにより、Bundlerの設定システムを操作することができるとのこと。

なお、 Bundlerは自身の設定を下記の優先順位で取得する。

 1. ローカルのアプリケーション(app/.bundle/config)
 2. 環境変数
 3. ユーザーのホームディレクトリ(~/.bundle/config)

また、--localオプションをつけることで、ローカルのアプリケーションに対して設定が可能。つまりプロジェクト単位の設定となる。

宿題

  • bundle config で指定する「LDFLAGS」「CPPFLAGS」についてもう少し調べるべし。
  • ld コマンドについてももう少し。(仮)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails6 のちょい足しな新機能を試す10(year_format(令和ネタ)編)

はじめに

Rails 6 に追加されそうな新機能を試す第10段。 今回のちょい足し機能は、 date_select の year_format 編です。
datetime_select, date_select で year_format オプションを指定することで、年の書式を指定できるようになりました。

記載時点では、Rails は 6.0.0.rc1 です。 gem install rails --prerelease でインストールできます。

今回は、せっかくなので、「令和」に対応した Ruby 2.6.3 を使ってます。

$  rails --version
Rails 6.0.0.rc1

プロジェクトを作成する

rails プロジェクトを作成します。

$ rails new sandbox6_0_0rc1

scaffold で CRUD を作成する

$ cd sandbox6_0_0rc1
$ bin/rails g scaffold User name birth_at:datetime
$ bin/rails db:create db:migrate

app/views/users/_form.html.erb を編集する

:year_format オプションを追加して年の書式を変更してみます。

app/views/users/_form.html.erb
  ...
  <%= form.datetime_select :barth_at, year_format: ->year { "#{Date.new(year, 12, 31).jisx0301.split('.').first}(#{year})" } %>

登録画面を表示

User の登録画面を表示してみると、年の書式が変わっていることがわかります。
year_fmt.png

参考情報

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails6 のちょい足しな新機能を試す9(エラーメッセージのフォーマット編)

はじめに

Rails 6 に追加されそうな新機能を試す第9段。 今回のちょい足し機能は、 full message 編です。
ymlファイルで指定できるエラーフォーマットが拡張されてます。

記載時点では、Rails は 6.0.0.rc1 です。 gem install rails --prerelease でインストールできます。

$  rails --version
Rails 6.0.0.rc1

プロジェクトを作成する

rails プロジェクトを作成します。

$ rails new sandbox6_0_0rc1

model を作る

$ cd sandbox6_0_0rc1
$ bin/rails g model User name email
$ bin/rails db:create db:migrate

model に validation を追加する

app/models/user.rb
class User < ApplicationRecord
  validates :name, presence: true
  validates :email, presence: true
end

何もymlファイルに指定がないとき

何もymlファイルに指定がないときには、今までと同じ Name can't be blankEmail can't be blank になります。

$ bin/rails c
Running via Spring preloader in process 653
Loading development environment (Rails 6.0.0.rc1)
irb(main):001:0> user = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
irb(main):002:0> user.validate
=> false
irb(main):003:0> user.errors.full_messages
=> ["Name can't be blank", "Email can't be blank"]
irb(mail):004:0> exit

yml ファイルでエラーフォーマットを指定

エラーメッセージのフォーマット全体を指定してみます。

config/locales/en.yml
en:
  errors:
    format: '%{message}'

指定されたフォーマット (can't be blank だけ) にエラーメッセージが変わります。

$ bin/rails c
Running via Spring preloader in process 696
Loading development environment (Rails 6.0.0.rc1)
irb(main):001:0> user = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
irb(main):002:0> user.validate
=> false
irb(main):003:0> user.errors.full_messages
=> ["can't be blank", "can't be blank"]
irb(main):004:0> exit

実はここまでは、Rails 5.2.3でも同じです。

yml ファイルで model レベルでエラーフォーマットを指定

ここからが、Rails6のちょい足しです。
エラーメッセージのフォーマットを model レベルで指定してみます。

config/locales/en.yml
en:
  errors:
    format: '%{message}'
  activerecord:
    errors:
      models:
        user:
          format: '%{attribute} : %{message}'

では、エラーメッセージを確認してみましょう。
このとき、 ActiveModel::Errors.i18n_customize_full_message = true にします。

$ bin/rails c
Running via Spring preloader in process 1338
Loading development environment (Rails 6.0.0.rc1)
irb(main):001:0> ActiveModel::Errors.i18n_customize_full_message = true
=> true
irb(main):002:0> user = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
irb(main):003:0> user.validate
=> false
irb(main):004:0> user.errors.full_messages
=> ["Name : can't be blank", "Email : can't be blank"]
irb(main):007:0> exit

なお ActiveModel::Errors.i18n_customize_full_message はデフォルトでは、false です。
ActiveModel::Errors.i18n_customize_full_message = false のときは、modelレベルの設定は無視されます。

$ bin/rails c
Running via Spring preloader in process 1343
Loading development environment (Rails 6.0.0.rc1)
irb(main):001:0> ActiveModel::Errors.i18n_customize_full_message
=> false
irb(main):002:0> user = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
irb(main):003:0> user.validate
=> false
irb(main):004:0> user.errors.full_messages
=> ["can't be blank", "can't be blank"]
irb(main):005:0> exit

yml ファイルで attribute レベルでエラーフォーマットを指定

今度は、attribute レベルでエラーフォーマットを指定してみます。

config/locales/en.yml
en:
  errors:
    format: '%{message}'
  activerecord:
    errors:
      models:
        user:
          format: '%{attribute} : %{message}'
          attributes:
            name:
              format: '%{message} - %{attribute}'

では、試してみましょう。
name は、 '%{message} - %{attribute}' のフォーマットが適用され
email は、 '%{attribute} : %{message}' のフォーマットが適用されます。

$ bin/rails c
Running via Spring preloader in process 1383
Loading development environment (Rails 6.0.0.rc1)
irb(main):001:0> ActiveModel::Errors.i18n_customize_full_message = true
=> true
irb(main):002:0> user = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
irb(main):003:0> user.validate
=> false
irb(main):004:0> user.errors.full_messages
=> ["can't be blank - Name", "Email : can't be blank"]
irb(main):005:0>

i18n_customize_full_message の設定

今回、irb の中で動的に設定しましたが、 i18n_customize_full_message は、 config ファイルで設定できます。

config/application.rb
module Sandbox600rc1
  class Application < Rails::Application
     ...
    config.active_model.i18n_customize_full_message = true
  end
end

参考情報

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails5.2.1】credentials.ymlを使用してアプリをHerokuにデプロイできなかった話

credentials.ymlを使用してアプリをHerokuにデプロイしようとしたら下記エラーが発生した。

NoMethodError: undefined method `[]' for nil:NilClass

解決策

下記コマンドを実行したらデプロイできた。

heroku config:set RAILS_MASTER_KEY=`cat config/master.key`
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【10日間でポートフォリオ作成に挑戦】6日目:テストコードの実装

概要

今回は、2019年のGW期間(10日間)を全て費やして取り組むポートフォリオの製作過程を取りまとめた内容を投稿させて頂きます。(投稿は毎日行う予定)

全体通した取り組みの詳細については、前回までの記事をご参照ください。

【10日間でポートフォリオ作成に挑戦】1日目:要件定義〜記事投稿のCRUD
【10日間でポートフォリオ作成に挑戦】2日目:アクセス制限〜コメントのCRUD機能
【10日間でポートフォリオ作成に挑戦】3日目:ページネーション~CKEditorの導入
【10日間でポートフォリオ作成に挑戦】4日目:テーブル分割〜CKEditorのフォームへの反映
【10日間でポートフォリオ作成に挑戦】5日目:CKEditorへ画像アップロード機能を追加

今日一日の作業内容

ここからは、今日1日で取り組んだ作業内容をご説明します。

テストコードの記述

これまで実装した各機能のテストコードを記述して行きました。

  • アカウント認証機能(devise)
  • 記事のCURD機能(一覧、新規作成、編集、削除)
  • 記事へのコメントのCRUD機能(新規作成、編集、削除)
  • 記事一覧のページネーション(kaminari)
  • 画像のアップロード機能(Shrine)
  • CKEditorによる記事の編集機能

テストで利用したgemは下記の通りです。

group :development, :test do
(中略)
  gem 'rspec-rails'
  gem 'factory_bot_rails'
  gem 'rails-controller-testing'
end

group :test do
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  gem 'chromedriver-helper'
end

なお、テストコードの実装にあたっては、Everyday Railsをかなり参考にさせて貰いました。
Everyday Rails - RSpecによるRailsテスト入門

今日の失敗

ここからは、今日の失敗をまとめます。

テストコードを通す為に無理矢理な処理を記述する

※追記(5/3):こちらのコードは、伊藤さん(@jnchito)がコメントにて、適切な修正案を提示して頂いているので、そちらもご参考にしてください。

まずは、下記のコードをご覧ください。

spec/system/post_spec.rb
require 'rails_helper'

RSpec.describe 'post_comment', type: :system do
  let!(:user) { create(:user) }
  let(:post) { create(:post, id: 1, user_id: 1) }
  let(:post_description) { create(:post_description, post_id: 1) }
  before { login_user(user) }

  it 'creates post' do
    visit posts_path
    click_on(I18n.t('common.button.new'))

    fill_in 'post[title]', with: 'テストタイトル1'
    fill_in 'post[post_description_attributes][description]', with: 'テスト詳細1'
    click_button(I18n.t('common.button.submit'))

    expect(page).to have_content('テストタイトル1', 'テスト詳細1')
  end

  it 'edits post' do
    post
    create(:post_description, post_id: 1)
    visit edit_post_path(post)

    fill_in 'post[title]', with: 'テストタイトル2'
    fill_in 'post[post_description_attributes][description]', with: 'テスト詳細2'
    click_button(I18n.t('common.button.submit'))

    expect(page).to have_content('テストタイトル2', 'テスト詳細2')
  end
end

上記のコードは二つの欠点があります。

I18n

辞書ファイルの名称と一致するかチェックしてsubmitボタンを押す処理ですが、下記の様にI18nを外すと、エラーになってしまいます。

click_button(t('common.button.submit'))
NoMethodError:
undefined method `t' for #<RSpec::ExampleGroups::Post:0x00007fb64b90cac8>

インターネットで調べると、stackoverflowに下記の様な回答があったので、それに沿って、I18nを付与すると、エラーは解消されました。

Use I18n.t instead of just t.
undefined method `t' for Admin::FaqsController:Class

しかし、I18n無しでも本来は実装出来るはずです。
その方法が見当たらなかった為、一旦この方法で実装しています。

editでのpostの定義

editアクションのテストにおいて、post_descriptionを新たに作成していますが、本来であれば、letで事前に作成しているはずなので、不要です。

しかし、このコードを外すとエラーになってしまいます。

Failures:

  1) post edits post
     Failure/Error: fill_in 'post[post_description_attributes][description]', with: 'テスト詳細2'

     Capybara::ElementNotFound:
       Unable to find field "post[post_description_attributes][description]" that is not disabled

こちらも原因が特定できませんでした、テストは正常にできている様なので、一旦はこの状態で実装し、後々対策を調査しようと考えています。

流石に疲れて来た

開発を進めながら、個人ブログとQiitaを両方毎日投稿するのは結構疲れます・・・
(特にQiitaは多く目に触れるので、かなり神経を擦り減らす・・・)

その影響で集中力が持続せず、作業効率がかなり落ちてしまっている様に感じます。
適宜息抜きも必要だと、改めて実感しました。

明日の予定

  • 記事の検索機能(ransack)
  • 記事へのいいね機能(別ユーザーのみ)
  • 記事のストック機能(自身の記事も可)

明日までにここを完成させないと、いよいよ後が無い・・・
デスマーチで乗り切るほかあるまい・・・

おまけ

最後になりますが、現在、私は下記の目標を立てて学習に取り組んでいます。

  • 3年間で「10,000時間」をプログラミングに費やす
  • その間、毎日ブログの投稿を行う

Twitterでは、その過程で学んだ事などを発信しています。
もし宜しければフォローしてみてください。

Twitter:@ryoutaku_jo
ブログ:りょうたくのWEBエンジニア日記

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsのbxsliderのaタグが効かないときの対処法

はじめに

スライドショーのgem「bxslider」を使用していた際に、スライドショー内のリンクをクリックしても遷移しなかったので、直接コードをいじってなんとか解決しました。
そのフローを残しておきたいと思います。

開発環境

  • windows7
  • ruby 2.4.5p335 (2018-10-18 revision 65137) [x64-mingw32]
  • Rails 5.2.3
  • bxslider-rails 4.2.5.1
  • jquery-rails 4.3.3

事象・検証状況

  • スライドショー内のリンクをクリックしても遷移しない
  • aタグをマウスオンすると遷移先URLが表示される
    • aタグを覆う要素は存在しない
  • レンダリング時のエラーなし
    • 自身のコーディングに不備はない可能性が高い
  • デベロッパーツールのコンソール上でもエラーなし
    • JQueryでもエラーはない
  • めっちゃ調べた。
    • これっぽい。

カミナリ|bxSliderのスライド内のリンクが効かなくなった際の対処方
https://kaminarimagazine.com/web/2019/03/29/bxslider%E3%81%AE%E3%82%B9%E3%83%A9%E3%82%A4%E3%83%89%E5%86%85%E3%81%AE%E3%83%AA%E3%83%B3%E3%82%AF%E3%81%8C%E5%8A%B9%E3%81%8B%E3%81%AA%E3%81%8F%E3%81%AA%E3%81%A3%E3%81%9F%E9%9A%9B%E3%81%AE%E5%AF%BE/

解説

原因

スマホのタッチ・スワイプに対応させるためのオプションで、デフォルトが trueである、「touchEnabled」オプションにより、マウスオン(タッチ)時にドラッグ(スワイプ)操作判定となる。つまり、clickイベントとmouseleaveイベントが発火しない。
もう少し詳しく話すと、ページをスライドさせない(ドラッグ(スワイプ)距離がないor短い)とき、クリック処理がされないような記述になっている。

参考サイトの対応策

  1. 「mousedown」で対策する
  2. bxSliderのオプションの「touchEnabled」を’false’に設定する

感想

どっちもやだ。

理由

  1. 操作感が変わる→気持ち悪い
  2. スマホ上でフリックによるスライドはさせたい

解決するにいたった手順

  1. gemのソースからtouchEnabledを探す
  2. initTouch呼び出してた。探す
  3. onTouchStartをbindしてた。探す
  4. いっぱい何か書いてる...。でも、 onTouchStartというよりは onTouchEndみたいな関数が関係してそう。それ、bindされてた。探す
  5. distance計算してるし、ここだ!
  6. 無理矢理クリックイベントを発火させる方法調べる → 発見!(参考サイト参照) → 完成!

onTouchStartあたりから逐次console.log(hoge);で呼び出されている関数を確認していました。

該当コード

app_name\vendor\bundle\ruby\2.4.0\gems\bxslider-rails-4.2.5.1\vendor\assets\javascripts\jquery.bxslider.js
var onTouchEnd = function(e) {
  if (slider.settings.mode === 'fade') {
    #
    # スライドショーのスタイルがfadeの時の処理
    #
  } else {
    #
    # 横スライド(horizontal)か縦スライド(vertical)の判定処理
    #
    if (!slider.settings.infiniteLoop && ((slider.active.index === 0 && distance > 0)|| (slider.active.last && distance < 0))) {
      setPositionProperty(value, 'reset', 200);
    } else {
      if (Math.abs(distance) >= slider.settings.swipeThreshold) {
        #
        # ドラッグ距離 or スワイプ距離がスライド有効距離以上の場合のスライド処理
        #
      } else {
+       document.elementFromPoint(e.clientX, e.clientY).click();
        setPositionProperty(value, 'reset', 200);
      }
    }
  }
};

まとめ

初心者によるChromeのアップデートに対する不具合解消ですので、かなり付け焼刃的な解決法だったのかな、と思っています...。ちなみに、今回はfade形式のスライドショーはを使う予定がなかったので、コードを変更していませんが、# スライドショーのスタイルがfadeの時の処理部分の類似部分を変更すればfadeでも正しく動作するはずです。

参考サイト

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsのActiveModel::Serializerでレスポンスのキー名をキャメルケースにしたい

フロントはTypescriptを使用している場合、レスポンスで受け取るキー名がスネークケースだと、tslintでエラーを吐いてしまいますよね。

基本的にrubyはスネークケースを使用するべきで、Typescriptはキャメルケースを使用するべきなので、両者の基本が違うのがもどかしいです。

なので、Rails(サーバ)側でレスポンスのキー名をキャメルケースにしてやりたいなぁと思ってました。

jbuilderを使っている場合が多いのかな?と思ったりもしますが、私はActiveModel::Serializerを最近好んで使っているので、Serializerでキャメルケースにする便利な設定とかないかなぁと思って探してみたら、ありました。

以下をinitializerに追記するだけでした!

ActiveModelSerializers.config.key_transform = :camel_lower

どこに記述しようか悩むところですが、とりあえずconfig/application.rbに書きました。

まぁ結局パラメータチェックのところとか、変更する箇所が多すぎるので断念しましたが・・・

サーバ側から渡すときはキャメルケースで、フロントから受け取るときはスネークケースで、とか出来たら便利なんですけどね〜
(探してないだけであるかもですが)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ActiveRecordで行値式で検索する方法

以下のように複数カラムをつかってINで検索することを行値式行値構成子と呼ぶそうです。

SELECT * FROM table
WHERE (column1, column2) IN (
  (value1, value2),
  (value3, value4)
);

これをRailsで使用する方法がなさそうだったので、実現する方法を考えました。
ActiveRecord.where

Hoge.where('id = ? OR id = ?', 1, 2)
=> SELECT  `hoges`.* FROM `hoges` WHERE (id = 1 OR id = 2)

のように文字列でWHERE文を使用しつつ、プレースホルダも使えるので、これを利用します。

pluckなどで取得した値をそのまま使えるようにしたかったので、
第1引数にカラム名の配列
第2引数に値の配列
を指定してwhereに渡す値を生成するメソッドを定義します。

# @param [Array] columns 検索に使用するカラム名の配列 ex. [:id, :name]
# @param [Array] values 検索に使用する値の2重配列 ex. [[1, 'hoge'], [2, 'piyo']]
# @return [Array] ActiveRecord.whereで使用できるWHERE句と検索値を持った配列
def row_constructor(columns, values)
  # 1レコード分のプレースホルダを作成
  # ex. [:id, :name] => (?,?)
  placeholder = "(#{(['?'] * columns.size).join(',')})"
  # 検索数分のプレースホルダを作成
  # ex. [[1, 'hoge'], [2, 'piyo']] => (?,?),(?,?)
  placeholders = ([placeholder] * values.size).join(',')
  # 行値式のWHERE句を作成
  # ex. (id,name) IN ((?,?),(?,?))
  sql = "(#{columns.join(',')}) IN (#{placeholders})"
  # ActiveRecord.whereには可変長引数で渡すので2重配列を平坦にして、先頭にクエリ文字列を追加
  values.flatten.unshift(sql)
end

上記のメソッドを以下のように使用します。

columns = [:id, :name]
values = [[1, 'hoge'], [2, 'piyo']]
Hoge.where(*row_constructor(columns, values))
=> SELECT  `hoges`.* FROM `hoges` WHERE ((id,name) IN ((1,'hoge'),(2,'piyo')))

そもそもActiveRecordにメソッドが用意されていたり、
gemがあったら教えてください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails ~会員登録までの道のり~

これまでのあらすじ

前回の記事よりActionMailerの機能でメールを飛ばせることを検証しました。
今回は、メールアドレスを認証させるために仮ユーザ登録させてからユーザ登録させるための仮ユーザ登録機能を作ってみます。
ユーザ認証に関しては、deviseなどのGemの利用がRailsでは、一般的(というか便利)らしいですが、Ruby・Railsの勉強をするために純粋にRuby・Railsで構築してきたいと思います。

Top画面の作成

まずトップ画面を作成します。
top_cotroller.rbを作成します。

terminal
$ rails g cotroller top
top_controller.rb
class TopController < ApplicationController
    def index
    end
end

indexアクションを作成し、/views/top/index.html.erbを作成します。
config/routes.rbにルートを追加する。

rootパスにtop#indexアクションを指定します。

routes.rb
Rails.application.routes.draw do
    root 'top#index'

    # top_controller
    get 'top', to: 'top#index'
end

TOP画面はこんな感じにBootstrapを駆使して作りました。

ezgif.com-video-to-gif.gif

(管理者とかあるのはご愛嬌で...)

背景に動画を埋め込んで「イマドキ」っぽいおしゃれなWebサイトっぽくしました。

仮ユーザのModel作成

仮ユーザ(temp_user)のModel(DBのテーブル)を作成します。

schema.rb
  create_table "temp_users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
    t.string "mail_address", null: false
    t.string "last_name", null: false
    t.string "first_name", null: false
    t.string "token", limit: 64, null: false
    t.datetime "expired_at", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["mail_address"], name: "index_temp_users_on_mail_address", unique: true
    t.index ["token"], name: "index_temp_users_on_token", unique: true
  end

仮ユーザ情報として、ログインに使用するmail_addressとユーザの氏名、仮ユーザを認証するためのtoken、仮ユーザ情報の有効期限のためのexpired_atで構成されています。

仮ユーザ登録までの流れ

  1. TOP画面のsign onボタンを押下し、仮登録画面を表示。
  2. 仮登録画面で氏名・メールアドレスを入力。
  3. メールアドレス登録完了と同時に、本登録画面のurlを記載したメール送信。
  4. 仮登録が完了した旨のメッセージ表示。

1. TOP画面のsign onボタンを押下し、仮登録画面を表示。

以前の記事で紹介したモーダルウィンドウを起動し、仮登録画面を表示しました。

ezgif.com-video-to-gif.gif

top_controller#sign_onで表示しています。
form_with用の@temp_userをnewしている以外は特別なことはしていません。

top_controller.rb
class TopController < ApplicationController
    def sign_on
        @temp_user= TempUser.new
    end
end

2. 仮登録画面で氏名・メールアドレスを入力。

temp_user.rbにバリデーションを追加しました。

temp_user.rb
class TempUser < ApplicationRecord
    VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
    validates :last_name, presence: true
    validates :first_name, presence: true
    validates :mail_address, presence: true
    validates :mail_address, format: { with: VALID_EMAIL_REGEX }
end

氏名は必須。
メールアドレスは必須とメールアドレス正規表現によるフォーマットチェックをしています。

3. メールアドレス登録完了と同時に、本登録画面のurlを記載したメール送信。

top#sign_onでformを表示し、formのsubmitでtop#createを読んでいます。
本処理は

  • mail_addressがすでに使用されている(temp_userに登録済み)の場合は、UPDATE、未使用の場合は、INSERTをする。(UPSERT処理)
  • UPDATE時、入力された姓・名・有効期限は後勝ちとする。
  • tokenはランダム文字列で生成。

find_or_initialize_byで条件にformで入力されたmail_addressを指定しています。
find_or_initialize_byは取得できた場合、取得結果をModelに詰め、できない場合は、ただ単純にnewします。

その後、姓・名をセットします。

tokenですが、SecureRandom.urlsafe_base64でランダム文字列を作成しました。なお、重複登録を防ぐために、token = 生成文字列でtemp_userを検索し、存在した場合、再度生成しています。

有効期限はとりあえず現在日時をセットし、saveしています。

find_or_initialize_byで生成しているため、すでに存在している場合は、UPDATE・新規の場合はINSERTをrailsで判断しています。(便利ですね!!)

top_controller.rb
    def create
        # 入力されたメールアドレスは登録済みか
        @temp_user = TempUser.find_or_initialize_by(mail_address: temp_users_params[:mail_address])
        # 入力された姓・名をセット
        @temp_user.last_name = temp_users_params[:last_name]
        @temp_user.first_name = temp_users_params[:first_name]
        # トークンを生成
        @temp_user.token = create_token
        # 有効期限に現在日時をセットする
        @temp_user.expired_at = DateTime.now

        respond_to do |format|
            # UPSERT実行
            if @temp_user.save
                format.js { @status = "success" }
            else
                format.js { @status = "fail" }
            end
        end
    end

    private
        def create_token
            token = nil
            loop do
                token = SecureRandom.urlsafe_base64
                    break if TempUser.find_by(token: token).nil?
            end
            return token
        end

4. 仮登録が完了した旨のメッセージ表示。

成功した場合は、完了した旨のメッセージを表示しました。
これもModalで表示していますが、formのモーダルを消してから、完了のモーダルをshowするため
遅延実行しています。

create.js.erb
<% if @status == 'success' %>
    $('#top_modal').modal('hide');
    setTimeout(function(){
        $('#top_modal').html('<%= j(render 'completed_sign_on') %>');
        $('#top_modal').modal('show');
    }, 500);
<% elsif @status == 'fail' %>
    $('#sign_on_errors').html('<%= j(render 'layouts/error_messages', model: @temp_user) %>');
<% end %>

こんな感じ...

ezgif.com-video-to-gif.gif

今後は…

これで仮登録までできました。
とりあえず、前回の記事の検証と合わせて、メールを飛ばすところまではつくりたいですね。
(こうしたほうがいいとか、ご意見あったらぜひぜひいただけると嬉しいです。)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む