20200527のRailsに関する記事は19件です。

rails での初めてのページネーション機能の追加

rails での初めてのページネーション機能の追加

参考にした記事(https://qiita.com/residenti/items/1ae1e5ceb59c0729c0b9)

ページネーションとは

長くなってしまったコンテンツを複数のページに分割して情報を読み取ることです。
googleの検索結果などが例に挙げられます。

まずgemのinstall

kaminariというgemを使って実装します。

gemfile
gem'kaminari', '~> 0.17.0'

rails5系ではkaminariのバージョンを上記のように指定しないと動作しないそうです。bundle installします。

コントローラー

topics_controller
 @topics=Topic.page(params[:page]).per(5)

@topics=Topic.all
を上記のように変更しました。perメソッドで1ページに何件まで表示するか決定します。

View

index.html.erb
 <% @topics.each do |a| %>
            問題:<%=a.question %><br><br>
              :<%=a.choice1 %><br>
              :<%=a.choice2 %><br>
              :<%=a.choice3 %><br>
              :<%=a.choice4 %><br>
 <% end %>

<%= paginate @topics %>

<%= paginate @topics %>を書くだけです。
以上でページネーション機能の追加が完了しました。

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

Hello RSpec

新人のRailsエンジニアです。
RailsのTestをするにあたってRSpecを学んだのでまとめてみました。
100日後に1人前になるエンジニアを連載中です。本日は7日目
ちなみにMinitestとRSpecの比較についてはこちら

RSpecとは

RubyやRuby on Railsで作ったクラスやメソッドをテストするためのドメイン特化言語 (DSL)を使ったフレームワーク。
つまりは、テスト専用のプログラム言語とも言えます。

FactoryBot

テスト用のデータの作成をサポートするgem
FactoryBotを利用するとテスト用のデータを簡単に準備できる
Rails標準ではFixtureという仕組みもありますが、
こちらよりもデータの状態やデータ間の関係性を掴みやすい。
ということで今回はこちらも使用。

Capybara

WebアプリケーションのE2E(End-to-End)テスト用フレームワーク。
RSpecなどと組み合わせて使います。Webアプリケーションのブラウザ操作をシュミレーションできる。

RSpecの基本形

RSpecの記述の基本形としては以下の様な形です。

describe [仕様を記述する対象(テスト対象)], type[specの種類] do
  context[ある状況] do
    before do
      [事前準備]
    end
    it[仕様の内容(期待の概要)] do
      [期待する動作]
    end
  end
end

これだけみてもなかなかわからないので分割してみていきます。

describe

describe [仕様を記述する対象(テスト対象)], type[specの種類] do

end

describeには、何について仕様を記述しようとしているのかを書きます。
例えばsystemテストをプロフィール表示機能について仕様を書きたいのであれば

describe 'プロフィール表示機能', type: :system do

と言った具合ですね。

context

こちらはテストの内容を状況、状態のバリエーションごとに分類するために利用します。
例えばユーザーの入力内容が正しいか間違っているか、ユーザーがログインしているか否かなどを
contextに記述していきます。

before

beforeはその領域全体の前提条件を実現するためのコードを記述している
以下のだとプロフィールを表示するための前提条件。
この場合だとログインしていることが前提条件になっている

context 'ユーザーがログインしているとき' do
  before do
    visit login_path
    fill_in 'メールアドレス', with: 'email@example.com'
    fill_in 'パスワード', with: 'password'
    click_button 'ログイン'
  end
end

it

最後のitは期待する動作と文章をブロック内のコードで記述します
expect(page).to have_content 'hoge'
上の記述は画面に"hoge"という内容があるよね??
っていう内容になっています。
expect to have contentなので英語のままといえばそれまでですが。

#プロフィール画面に'ユーザーのプロフィール'って内容があるよね??
it 'ユーザーのプロフィールが表示される' do
  expect(page).to have_content 'ユーザーのプロフィール'
end

以上まとめてみると

describe 'プロフィール表示機能', type: :system do
  context 'ユーザーがログインしているとき' do
    before do
      visit login_path
      fill_in 'メールアドレス', with: 'email@example.com'
      fill_in 'パスワード', with: 'password'
      click_button 'ログイン'
    end
    it 'ユーザーのプロフィールが表示される' do
      expect(page).to have_content 'ユーザーのプロフィール'
    end
  end
end

こう言った形でRSpecの基本形が成り立っています。
いきなり全部理解しようとするとつらいけど、分割してみるとなんとかなりそう。

今回は基本形をどう見るかという点でまとめてみました。
実際はもっとネストがあって、込み入っている様に見えますが、
まずは基本形をおさえてRSpecの理解を深めていきたいですね。

本日は以上です
1人前のエンジニアになるまであと93日

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

Active Record、複雑なクエリ

Active Recordでちょっと複雑な問い合わせを書いた時に、忘れないようにメモとして追記していきます。

関連テーブルのレコード数でソート

class PLine < ApplicationRecord
  has_many :likes, dependent: :destroy
end

class Like < ApplicationRecord
  belongs_to :p_line
end
@p_lines = PLine.select('p_lines.*', 'count(likes.id) AS favs')
                .left_joins(:likes)
                .group('p_lines.id')
                .order('favs desc')
<% @p_lines.each do |p_line| %>
  <p><%= p_line.p_line %></p>
  <p><%= p_line.favs %> points</p>
<% end %>

関連カラムが複数あって、変数の値がどちらかに一致する。関連カラムをすべてincludeしたい。

class Mc < ApplicationRecord
  has_many :videos
end

class Video < ApplicationRecord
  belongs_to :mc1, class_name: 'Mc'
  belongs_to :mc2, class_name: 'Mc'
end
@videos = Video.includes(:mc1, :mc2).where(mc1_id: @mc)
               .or(Video.includes(:mc1, :mc2).where(mc2_id: @mc))
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Cloudflareを使ってみた

Cloudflareとは

DNS + CDN のサービスです。
オリジンサーバーとの間でリバースプロキシのように動作し、画像、CSS、JavaScriptなどをキャッシュしてくれます。

良いところ

  • 無料
  • 設定が簡単
    • やらなきゃいけないことが少なく、情報が多い
  • ルートドメイン(wwwなしのドメイン)でも問題なくCDNが使える
    • 基本的にルートドメインはCNAMEレコードの設定ができないので、他のCDNサービスを使う時は設定が面倒なことが多い
    • CloudflareはCNAME Flatteningという技術でルートドメインでもCNAMEレコードを設定することができる
  • リダイレクトの設定が簡単
    • wwwありなし、http→httpsなど
    • 管理画面上で設定
    • .htaccessRewriteEngine...とか書かなくて良い

設定方法

Herokuで運用しているサイトに導入してみます。
基本的にこちらの記事に沿って設定を進めました。
『Heroku + Cloudflare』でルートドメインかつSSLでサイトを運用する | vdeep

登録

  • Cloudflareのトップページからサインアップ
  • メールアドレス、パスワードを入力
  • サイトのドメインを入力
  • 無料プランを選択
  • メールの受信を確認し、Verify

DNSの設定

  • 管理画面より「DNS」タブを選択
  • 自動で取得されているレコード情報があれば、すべて削除する
  • 「レコードを追加」より以下の2つのレコードを追加
    • 「CNAME」「example.com」「sampleapp.herokuapp.com」「プロキシ済み」
    • 「CNAME」「www.example.com」「sampleapp.herokuapp.com」「プロキシ済み」
  • 同じページ内の「Cloudflare ネームサーバー」という箇所に書いてあるネームサーバーを、ドメインを購入したサイトで登録(ネームサーバーの変更|お名前.com Navi ガイド)

SSLの設定

  • 「SSL/TLS」タブをクリック
  • 「エッジ証明書」をクリック
  • 「常にHTTPSを使用」「HTTPSの自動リライト」をONにする

リダイレクトの設定

Herokuにドメインを登録

まだドメインを登録していない場合は
Heroku管理画面 > 「Settings」 > 「Add domain」でドメインを追加します。

以上で設定完了です。
反映に時間がかかることがあるので、気長に待ちましょう。
私の場合、リダイレクトの設定が反映されるのに時間がかかりました。

CDNにキャッシュされていることを確認

  • 上記の設定が終わってから数時間待つ
  • デベロッパーツールのNetworkタブを開く
  • サイトを表示
  • 画像やCSSファイル等をクリック
  • Response Headersの中に「cache-control: max-age=14400」「cf-cache-status: HIT」などの記載があれば、正常にキャッシュされています。
    • 普通にみたらダメで、シークレットモードで見たら表示されてたことがありました。

ちなみに、キャッシュされたコンテンツが返ってくる時のレスポンスヘッダーは各CDNベンダーが独自に定義しているので、使っているCDNサービスによってヘッダーの名前が微妙に違ったりするらしいです。
キャッシュがHitした情報を示すCacheヘッダの標準化提案 - ASnoKaze blog

終わりに

導入後、Pagespeed Insightsのスコアが84→91くらいに上がりました。これだけいろんなことが出来て無料って最高ですね。

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

Shoryuken の worker を Rails console で実行

SQS への enqueue が何らかの AWS のサービスによるものだった場合、テストがしづらいことがあるので、 Rails console で叩いて動作確認できるようにする方法

name version
shoryuken 5.0.1
rails 5.2.4.1
aws sdk core 3.56.0
aws sdk sqs 1.17.0
$ rails console
[1] pry(main)> worker = SomethingSqsWorker # please change
[2] pry(main)> body = {} # please change
[3] pry(main)> endpoint = "" # config などで設定
[4] pry(main)> client = Aws::SQS::Client.new(endpoint: endpoint)
[5] pry(main)> message = Shoryuken::Message.new(client, Shoryuken::Queue.new(client, worker.shoryuken_options_hash["queue"]), Aws::SQS::Message.new(queue_url: queue.url, receipt_handle: "receipt_handle"))
[6] pry(main)> worker.new.perform(message, body)

receipt_handle は普通特に参照しないのかなと思って適当な文字列にしてあります。適宜変えてください

snippet

worker, body, endpoint を設定したあとの実行部分です。繰り返し使うときは最後の行だけで ok です

client = Aws::SQS::Client.new(endpoint: endpoint)
message = Shoryuken::Message.new(client, Shoryuken::Queue.new(client, worker.shoryuken_options_hash["queue"]), Aws::SQS::Message.new(queue_url: queue.url, receipt_handle: "receipt_handle"))
worker.new.perform(message, body)

一行を長くしたくない人向け

client = Aws::SQS::Client.new(endpoint: endpoint)
queue = Shoryuken::Queue.new(client, worker.shoryuken_options_hash["queue"])
sqs_msg = Aws::SQS::Message.new(queue_url: queue.url, receipt_handle: "receipt_handle")
message = Shoryuken::Message.new(client, queue, sqs_msg)

worker.new.perform(message, body)

一行にこだわりたい人向け

Aws::SQS::Client.new(endpoint: endpoint).instance_eval { worker.new.perform(Shoryuken::Message.new(self, Shoryuken::Queue.new(self, worker.shoryuken_options_hash["queue"]), Aws::SQS::Message.new(queue_url: queue.url, receipt_handle: "receipt_handle")), body) }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

% rails db:createするとmimemagic に起因するLoadErrorががが


% rails db:create
rails aborted!
LoadError: cannot load such file -- mimemagic
/projects/〜〜〜/config/application.rb:7:in `<main>'
/projects/〜〜〜/Rakefile:4:in `<main>'
bin/rails:4:in `<main>'

git hubからとあるファイルをcloneしdb:createをした際に生じたエラー

まいむまじっく.......???
なかなかマイナーなファイルが原因を引き起こしてるっぽいけども・・・

ひとりでは解決困難!!先輩の力を借りてる最中、Qiitaをみてみるとこんな記事が

a.com/zQmjRAb73seN5RM/items/5fa74d2a4d346cdd386e

バージョンの問題っぽい・・・?
その通りにコマンドを実行してみた

$gem list 〇〇 
//〇〇には該当ファイルを入れる(今回だとmimemagic)

結果は......

mimemagic (default: 0.3.5, 0.3.4, 0.3.3)

ではどんなファイルがあるのかを確認してみる

find ~/.rbenv -type f | grep 〇〇
//〇〇には該当ファイルを入れる(今回だとmimemagic)

結果は......

(一部抜粋)
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/test/files/image.png
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/test/files/application.zip
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/CHANGELOG.md
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/script/freedesktop.org.xml
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/script/generate-mime.rb
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/README.md
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/Rakefile
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/mimemagic.gemspec
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/.gitignore
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/lib/mimemagic/tables.rb
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/lib/mimemagic/version.rb
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/lib/mimemagic/overlay.rb
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/lib/mimemagic.rb
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/Gemfile
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/.travis.yml
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/.yardopts
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/LICENSE
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/test/mimemagic_test.rb
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/test/files/application.vnd.openxmlformats-officedocument.spreadsheetml{gdocs}.sheet
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/test/files/application.x-tar
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/test/files/application.gzip
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/test/files/application.x-bzip
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/test/files/application.vnd.openxmlformats-officedocument.spreadsheetml{msoffice}.sheet
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/test/files/image.jpeg
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/test/files/application.x-ruby
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/test/files/image.png
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/test/files/application.vnd.openxmlformats-officedocument.spreadsheetml{rubyxl}.sheet
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/test/files/application.zip
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/CHANGELOG.md
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/script/freedesktop.org.xml
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/script/generate-mime.rb/Users/tech-camp/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/test/files/image.png
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/test/files/application.zip
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/CHANGELOG.md/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/script/freedesktop.org.xml
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/script/generate-mime.rb
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/README.md
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/Rakefile
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/mimemagic.gemspec
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/.gitignore
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/lib/mimemagic/tables.rb
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/lib/mimemagic/version.rb
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/lib/mimemagic/overlay.rb
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/lib/mimemagic.rb
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/Gemfile
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.3/.travis.yml
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/.yardopts
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/LICENSE
/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mimemagic-0.3.4/test/mimemagic_test.rb

みてみると 0.3.3 0.3.4のファイルはあることになっているが、0.3.5がないとのこと
ここが食い違っているから生じたエラー is 濃厚......
この食い違いを解決するには、

% gem install mimemagic -v 0.3.5

結果

Successfully installed mimemagic-0.3.5

そして畳みかけます

% bundle install    
% rails db:create

成功!!!!!!!

LoadErrorのさいはぜひ参考にしてみてください!

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

railsでGoogleMapAPIの導入

このページのコードでできること

・自分のrailsプロジェクトにGoogleMapを埋め込み、表示させる。
・ページを開いたら地図と、初期値のマーカーを表示させる。
・inputボックスと検索ボタンを用意。
・inputボックスに検索したい場所を入力し、検索ボタンを押すことでその場所の地図を表示。

Maps JavaScript API & Geocoding APIの取得

これら記事にお世話になりました。(参考文献より)

コードを書く前に
Google Maps API を使ってみた
Google MAP 名称から場所を検索・特定する
オリジナルアプリ作成 〜RailsでGoogleMap利用検証〜

コード

postsに記述するとします。
@post.locationは一例です。ご自身のアプリケーションにふさわしい初期値を入れてください。

posts/index.html.erb
<div id='target'></div>

<div class='map-btn'>
<input id="address" type="textbox" value="<%= @post.location %>">
<input type="button" value="検索" onclick="codeAddress()">
<div>

<script src="https://maps.googleapis.com/maps/api/js?key=自分のAPIキー&callback=initMap" async defer></script>

style.scss
#target {
  height: 300px;
  width: 300px;
}

Javascriptの記述

post.js
let map
let geocoder
let centerp = {lat: 33.60639, lng: 130.41806}

function initMap(){
  geocoder = new google.maps.Geocoder()

  map = new google.maps.Map(document.getElementById('target'), {
    center: centerp,
    zoom: 12,
  });

  marker = new google.maps.Marker({
    position: centerp,
    map: map
  });
}

function codeAddress(){
  let inputAddress = document.getElementById('address').value;

  geocoder.geocode( { 'address': inputAddress}, function(results, status) {
    if (status == 'OK') {
      map.setCenter(results[0].geometry.location);
      var marker = new google.maps.Marker({
          map: map,
          position: results[0].geometry.location
      });
    } else {
      alert('該当する結果がありませんでした:' + status);
    }
  });   
}

参考文献

大変お世話になりました。感謝。

コードを書く前に
[https://qiita.com/nagaseToya/items/e49977efb686ed05eadb]

Google Maps API を使ってみた
[https://qiita.com/Haruka-Ogawa/items/997401a2edcd20e61037]

Google MAP 名称から場所を検索・特定する
[https://qiita.com/yoshi_yast/items/521c1f36306a180f45dd]

オリジナルアプリ作成 〜RailsでGoogleMap利用検証〜
[https://note.com/daddy0055/n/nddbe8da38bbc]

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

MySQLのモードに関して

自分のローカルで設定されているモード

$ mysql --version
mysql  Ver 14.14 Distrib 5.7.29, for osx10.15 (x86_64) using  EditLine wrapper
$ mysql -uroot -p
mysql> select @@global.sql_mode;
+------------------------------------------------------------------------------------------------------------------------------------------------------+
| @@global.sql_mode                                                                                                                                    |
+------------------------------------------------------------------------------------------------------------------------------------------------------+
| STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
  • STRICT_TRANS_TABLES
  • STRICT_ALL_TABLES
  • NO_ZERO_IN_DATE
  • NO_ZERO_DATE
  • ERROR_FOR_DIVISION_BY_ZERO
  • NO_AUTO_CREATE_USER
  • NO_ENGINE_SUBSTITUTION

なお、これは紛れもなく、TRADITIONALモードである。TRADITIONALモードとは上の7つのモードが全て有効になっている状態を言う組み合わせモードなのだ。

STRICTモード

STRICT_TRANS_TABLESモードとSTRICT_ALL_TABLESモードのいずれかが有効な場合、それはSTRICTモードである。

  • トランザクションストレージエンジン

    • 不正な値が挿入されようとした場合、エラーを発し(不良データ値は調整されない)、ロールバックする
  • 非トランザクションストレージエンジン

    • STRICT_TRANS_TABLES
      • 1行目で不良データを挿入しようとした時はエラーを起こし終了
      • 2行目以降で不良データを挿入しようとした時は不良データを調整して挿入し、(エラーではなく)警告を発する
    • STRICT_ALL_TABLES
      • 1行目でも2行目以降で不良データを挿入しようとした時はエラーを起こし終了(部分更新が行われる)

参考

というかもはや以下の要約
MySQLのSQLモードをstrictモードで設定する。

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

[Rails]collection_selectで都道府県プルダウンを作成する

前置き

他の記事を参考に導入してみましたが、これだけの手順で実装出来ました。
検索も出来たので、備忘録として残します。

前提条件

ransack導入済

1.導入

gem 'active_hash'

まずGemfileに上記のように記述し、bundle install。
再起動も忘れずに。

2.prefectureモデルを作成

こちら手動です。

models/prefecture.rb
class Prefecture < ActiveHash::Base
  self.data = [
      {id: 1, name: '北海道'}, {id: 2, name: '青森県'}, {id: 3, name: '岩手県'},
      {id: 4, name: '宮城県'}, {id: 5, name: '秋田県'}, {id: 6, name: '山形県'},
      {id: 7, name: '福島県'}, {id: 8, name: '茨城県'}, {id: 9, name: '栃木県'},
      {id: 10, name: '群馬県'}, {id: 11, name: '埼玉県'}, {id: 12, name: '千葉県'},
      {id: 13, name: '東京都'}, {id: 14, name: '神奈川県'}, {id: 15, name: '新潟県'},
      {id: 16, name: '富山県'}, {id: 17, name: '石川県'}, {id: 18, name: '福井県'},
      {id: 19, name: '山梨県'}, {id: 20, name: '長野県'}, {id: 21, name: '岐阜県'},
      {id: 22, name: '静岡県'}, {id: 23, name: '愛知県'}, {id: 24, name: '三重県'},
      {id: 25, name: '滋賀県'}, {id: 26, name: '京都府'}, {id: 27, name: '大阪府'},
      {id: 28, name: '兵庫県'}, {id: 29, name: '奈良県'}, {id: 30, name: '和歌山県'},
      {id: 31, name: '鳥取県'}, {id: 32, name: '島根県'}, {id: 33, name: '岡山県'},
      {id: 34, name: '広島県'}, {id: 35, name: '山口県'}, {id: 36, name: '徳島県'},
      {id: 37, name: '香川県'}, {id: 38, name: '愛媛県'}, {id: 39, name: '高知県'},
      {id: 40, name: '福岡県'}, {id: 41, name: '佐賀県'}, {id: 42, name: '長崎県'},
      {id: 43, name: '熊本県'}, {id: 44, name: '大分県'}, {id: 45, name: '宮崎県'},
      {id: 46, name: '鹿児島県'}, {id: 47, name: '沖縄県'}
  ]
end

app/models配下にprefecture.rbを作成し上記のように編集。
Prefecture < ActiveHash::BaseでActiveHash::BaseをPrefectureに継承。

3.検索フォーム作成(ransack導入済)

_search_form.html.haml
.search_form
  = search_form_for @q do |f|
    = f.collection_select :place_cont, Prefecture.all, :name, :name

完了。
以下解説。

:place_contについて、placeはカラム名です。_contは〜を含むというransackのマッチャーというものです。
※詳しくはこちらransack

Prefecture.allは、上記のPrefectureモデル全て持ってきてってことですね〜。
Prefecture < ActiveHash::BaseでActiveHash::BaseをPrefectureに継承したからActive Recordメソッドが使えるってことです。
Active Recordメソッドとは、
・all:テーブルの全てのデータを取得する
・find:テーブルレコードの一つのデータを取得する
・new:クラスのインスタンスの生成
・save:クラスのインスタンスの保存
などのことです。

普段rails g modelで作成しているモデルもActiveHash::Baseを継承していますね。

application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end
post.rb
class Post < ApplicationRecord
end

最後の方は「:name, :name」にしています。
他の記事では「:id, :name」でしたが、これだと検索出来なかったので変えました。

htmlを確認してみると下記のようになっていました。

# 「:id, :name」の場合
<option value="1">北海道</option>

# 「:name, :name」の場合
<option value="北海道">北海道</option>

ありがとうございました!

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

本番画面での画像

はじめに

開発環境で画像が表示されていましたが、本番環境では画像が表示されませんでした。
その時に行ったことを書いていきます!

やったこと

①普通のイメージタグは
before

= image_tag ("assets/xxx.png")

after

= image_tag asset_path("xxx.png")

②link_toとの併用
before

= link_to image_tag("/assets/xxx.png"), "ルートパス"

after

= link_to "ルートパス" do
  = image_tag asset_path("xxx.png") 

③background-umageは
before

 background-image: url("/assets/xxx.jpg");

after

 background-image: image-url("/assets/xxx.jpg");

原因

開発環境ではimagesディレクトリのしたにあったので、パスは/assets/画像でよかった。
アセットパイプラインにより、本番環境ではpublicのしたで管理されるから、書き方を変えるみたいです。
afterの書き方でも開発環境で表示されるので、そちらに統一した方が良いかなと思いました。

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

【Rails】Railsのビューヘルパーのdate,timeとデータベースのdate型time型

概要

ビューヘルパーのdateやtimeの値をparamsから受け取ると次のようになっているため少し面倒だったという内容です。
合わせてこれをデータベースに格納したときのデータについても触れています。

<select id="log_date_1i" name="log[date(1i)]">  # 年
<select id="log_date_2i" name="log[date(2i)]">  # 月
<select id="log_date_3i" name="log[date(3i)]">  # 日
<select id="log_date_4i" name="log[date(4i)]">  # 時
<select id="log_date_5i" name="log[date(5i)]">  # 分

データの取り出し方

dateやtimeは次のように一つを指定しないと取り出すことができません。
パラメーター名に[:date]のように指定してしまうとnilが返ってきます。

通常

params[:パラメーター名]
params[:モデル名][:パラメーター名]

datetime

params["date(1i)"]
params[:モデル名]["date(1i)"]

パラメーター

どのヘルパーでも1i~5iまで値が入ってパラメーターに入っています。
その影響でtimeは時間だけしか入力していなくても次のような値になってしまいます。
dateが年月日だけなのはよく分からないのですが...
これはアクティブレコードの問題らしいですが詳しくはわかりませんでした。

現在時刻をそのまま入れた場合:

# datetime
Wed, 27 May 2020 08:04:50 JST +09:00

# date
Wed, 27 May 2020

# time
Mon, 01 Jan 0001 08:04:50 LMT +09:18

データベースへの格納と表示

時間の場合time型を指定していれば先述のパラメーターの状態でもカラムに「08:04:50」だけが格納されていました。
しかし、そのまま取り出すと「Mon, 01 Jan 0001 08:04:50 LMT +09:18」の形で表示されてしまいます。

なのでフォーマットの必要が出てくるのですが、私は次のようにしています。
localeの設定が事前に必要になりますがここでは省略します。
参考の記事ではメソッドを定義しているので場合によって使い分けられればいいですね。

/config/locales/ja.yml
  time:
    am: 午前
    formats:
      default: "%Y年%m月%d日(%a) %H時%M分%S秒 %z"
      long: "%Y/%m/%d %H:%M"
      short: "%m/%d %H:%M"
      only_time: "%H:%M"
    pm: 午後
view.html.erb
<dd><%= l @form.time, format: :only_time %></dd>

参考

Railsで時刻 time型を扱う

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

自作ポートフォリオを掲げて、Web系自社開発企業に転職したいと考えている人へ

ターゲット

自作ポートフォリオを掲げて、Web系自社開発企業に転職したいと考えている人

結論

トピック1の結論

転職までの最短経路を十分に考え、場合によっては何も掲げずに転職活動すべし。

トピック2の結論

ほぼ未経験からのスタートなら、プログラミングスクールに通うべし。

話すトピック

  1. 友人の転職に心がざわついた
  2. 自力でポートフォリオを作成するときの罠

友人の転職に心がざわついた

先日(2020年5月26日)、大学時代の友人から転職したと連絡がありました。

本来ならおめでとうの言葉が先に出るべきなのでしょうが、現在転職のためにポートフォリオを作成している身ですから、なんとも複雑なわけでした。悲しい・虚しい、、、うーん。この複雑な気持ちの正体を知れば、自分のことをもっと理解できるかもしれない。そんな風に思い、色々思考を巡らせました。

感情の正体は、

3ヶ月で有名企業から内定を獲得した友人と、仕事以外の大半の時間を使用して、半年かかっても現職から離れられないでいる自分に、圧倒的な差を感じ、なんともやるせない気持ちになったということですね。

項目 友人
時間 開始から6ヶ月 開始から3ヶ月
職の状態 転職できていない 転職完了&有名企業

私と友人の差分

時間においても、職の状態においても私の方が劣っています。ではなぜ彼は成功できたのか。

それは、早めに企業の人と連絡を開始したからです。

企業のサイトから採用ページに行き、人事と連絡をとり面接を行い、転職を完了させました。なんともシンプル、でも正しい。

なぜ私は、早めに企業の人と連絡を開始できなかったのか?

彼と違い、私は企業の人とすぐに連絡を取ることをしませんでした。

なぜか?

それは、過去の実績資格経験が乏しいから、ポートフォリオを作成する必要があると判断したためです。これがないと、企業の方に自分の能力を認めてもらえない。

しかし、それは本当でしょうか?
そのためにポートフォリオは絶対に必要なのでしょうか。

確認はしましたか?

ポートフォリオは転職活動を先延ばしにするための言い訳?

私の友人はポートフォリオを持っていたわけではなかったです。
しかし転職に成功させることができました。

彼の素晴らしかったところ、それは、

目的を意識した最短のアプローチをしたということです。

最近の私の心境は、ポートフォリオ作成に時間がかかっているが、自分の作りたい作品が出来上がっていることに、すごく満足を覚えてました。

俺頑張っている

しかし、本当にそれは正しいのだろうか?
彼の結果を見ると、そう思わざるを得ませんでした。

【好きなことで、生きていく】『レペゼン地球-DJ社長-』の8:43あたりを見て下さい。

要約
「遠くに行かなければ行けないレースがあった時、とにかく頑張ろうという人は、目の前の自転車を使って漕ぎ出す。しかし、レースに勝つことが目的の人は、目の前の自転車ではなく、次の日に原付きの免許を取りに行くんだ。」

私は、11月時点で、誕生日である7月には、転職が完了しているだろう思っていました。しかし今この状況ですね。年内が危ういかもしれません。

転職モデルプラン

これらを踏まえ、私の出した転職モデルプランはこれです。

  • 行きたい企業を並べる
  • 連絡を取る(知り合いとか大学の先輩経由のほうが、自分をよくアピールできると思う)
  • 現状を話し、やりたいことも明確に説明する。
    • 例えばRailsを使ってポートフォリオを作成し、転職活動を行いたいと考えています。現状の私では、xxということができますが、御社△△をしたい場合、今の私に不足しているスキルはありますか?と聞くとか。
  • ポートフォリオが必要とわかったら、必要な分だけ勉強し、ポートフォリオを作成する。
  • 面接に挑む。
  • 内定した会社で働く。

自力でポートフォリオを作成するときの罠

トピック1で、転職モデルプランを作りました。
しかし、最終的にポートフォリオを作成する必要が出てきた方、どのように勉強を進めるか迷うところですね。私はズバリ、プログラミングスクールに通うことをオススメします。

なぜか?

自分のことを自分で管理できるわけがない

多くの人間は、自分との約束は破ります。人との約束は守りますが(笑)。皮肉です。

仕事は残業してでも完了させますが、ギターを弾けるようになりたい人の中で、夜中まで頑張っていた人を僕は知りません。

見たいドラマ、この動画見てから、、、無限に他の予定が入ります。どんだけ気合を入れても、次の日には昨日とは違う自分がやってきます。もし本気ならプログラミングスクールに通いましょう。大学受験で塾に行くことを拒む人はいません。

プログラミングスクールに通って、まずはきちんと勉強するリズムを作りましょう。

分からないことを調べるのに、超時間がかかる。

自力での調査は、とにかく時間がかかります。予想の10倍かかることもザラです。

私はAWSのEC2にRails newしたページを表示させるだけに、1週間とかかかっていました。

このスピード感、わかります?
3ヶ月で転職を完了させたい人にとって1週間がどのくらいの価値であるか、ちゃんと考えたほうが良いです。

プログラミングスクールに通って、いつでも質問できる環境を手に入れましょう。

時間が経つと情熱と自信を失う

半年前、私が転職を開始しようと思った時、なんだか凄くワクワクしていました。自分の人生の舵を自分で切っている感覚が、最高に思えました。

しかし、半年たった今、勿論転職したい気持ちはありますが、やはりあの時と全く同じであるかと言われると、少し違うように思います。時間が経つと気持ちは変化します。この変化が大きくなると、人は現場維持を選ぶんだろうなと。物理でいうと、エネルギーは安定方向へ向かうですね。挫折するんだと思います。

あと、自信がなくなります。これは短期間で転職を成功させている方との比較から生まれるものと、自分で立てた目標を達成できていないことから生まれるものと、2つあります。

プログラミングスクールに通って、短期で学習を完了させましょう。

最後に

最後まで読んでいただき、ありがとうございます。誰かの参考になればと思い、書きました。何かコメント等ありましたら、お願いします。

参考

以下はスルーで良いです。これらが自分の仕事に関する思想を形成する上で、非常に役に立ちました。

雑食系エンジニアKENTAさんの動画
SIer系企業とWeb系企業の違い

株式会社アクシアのホームページ
プライベートでは一切勉強したくないと言っていた社員のこと

やりたいことをやろう
トランプ流成功の定義

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

【Rails】フォームのエラーメッセージを入力項目ごとに表示する

実現したいこと

次の画像のようにフォームにある入力項目一つ一つに対してエラーメッセージを表示させます。
スクリーンショット 2020-05-27 6.40.32.jpg

localesでの日本語化もしていますが、こちらのインストールなどについてはカバーしていないので知りたい場合は参考のURLなどから確認してください。

環境

ruby: 2.7.1
rails: 6.0.2.2

コード

エラーメッセージ表示のパーシャルを作成

modelとattributeを変数にすることで使いまわせるようにしています。
errors.full_messages_forを利用して入力項目に対応したエラーメッセージのみを表示します。
/app/views/layouts/_error_messages.html.erb

_error_messages.html.erb
<% if model.errors.any? %>
  <div class="alert alert-warning">
    <ul>
      <% model.errors.full_messages_for(attribute).each do |message| %>
        <li><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>

フォームのパーシャルを作成

これは場合によると思いますが、フォームは基本new、editで使い回すことになると思うのでパーシャルにします。
「model: @form, attribute: :date」で入力項目ごとの値を指定すれば対応したエラーメッセージのみ表示可能です。

/app/views/logs/_form.html.erb

_form.html.erb
<%= form_with model: @form, local: true do |f| %>

  <div class="field">
    <%= f.label :date, "日付" %>
    <%= f.date_select :date, use_month_numbers: true, start_year: Time.now.year - 20, end_year: Time.now.year %>
  <!-- エラーメッセージの呼び出し -->
    <%= render "layouts/error_messages", model: @form, attribute: :date %>
  </div>

<!-- ~略~ -->

エラーメッセージの日本語化

このままではエラーメッセージが「Dateは1文字以上で入力してください」のように表示されるので、対応する日本語を指定して日本語化します。
/config/locales/ja.yml

ja:
  activerecord:
    models:
      form: "フォーム"
    attributes:
      log:
        date:               "日付"
        country:            "国"
        prefecture:         "都道府県"
        area:               "地域"
        point:              "ポイント"

ビューの表示

使用する場所でフォームを呼び出して終了です。
/app/views/logs/new.html.erb

new.html.erb
<h1>フォーム</h1>
<%= render 'form' %>

後書き

この手の表示は皆さんしていることだと思うのでもっと簡単な方法やGemなどあるのかもしれませんが見つけられなかったのでこのような感じに実装してみました。
参考の一つにあるのですが、そのうちajaxでリアルタイムに表示させられるようにしたいですね。

参考

【Rails】バリデーションのエラーメッセージを表示する
バリデーションの日本語表示の仕方
Rails エラーメッセージの表示
rails で日本語化をしているのですが、attributesの日本語化が適用されません
Railsでajax通信時にattribute名とfull_messageの組み合わせでレスポンスを返す

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

【Rails】一つのメソッドをf.selectのオプションとバリデーションで使い回す

前置き

erbのセレクトボックス一つ一つにオプションの値を書いていると、見落としや編集の手間を感じたので1箇所に集めようと思った。
初めはhelperを使用していたが、同じ配列がバリデーションでも流用できるのではと思い今回の形になりました。

しかし、セキュリティの側面からみた場合、バリデーションで同じメソッドの値を使い回すこのやり方はどうなのか?という疑問が残ります。
また、バリデーションで流用するためにmodelにメソッドを定義しましたが、viewで表示するデータの作成は本来のmodelの役割ではない部分も意識する必要がありそうです。

環境

ruby: 2.7.1
rails: 6.0.2.2

コード

model

 class Log < ApplicationRecord

# クラスメソッドの定義
  class << self
    def selectBoxOptions(key)
      if key == "fruits"
        return [ "なし", "りんご", "いちご"]
      elsif key == "vegetables"
        return [ "きゅうり", "とまと", "なす" ]
      end
    end
  end

 # バリデーションの作成。
 validates :fruits, inclusion: { in: selectBoxOptions("fruits") }
 validates :vegetables, inclusion: { in: selectBoxOptions("vegetables") }

end

view

  <div class="field">
    <%= f.label :speciality, "スペシャリティ" %>
    <%= f.select :speciality, Log.selectBoxOptions("fruits") %>
  </div>

  <div class="field">
    <%= f.label :entry_way, "エントリー方法" %>
    <%= f.select :entry_way, Log.selectBoxOptions("vegetables") %>
  </div>

後書き

enumを使用するという方法もあったのですが、それだけだとinputのvalueが数字になってしまうのでlocaleで日本語化する必要があったり、データベース保存は英語になるなどで今回実現したい内容には不向きなようでした。
[Rails] selectタグの選択肢の管理方法についてメリデメ比較をしてみる
【Rails】Enumってどんな子?使えるの?

なんやかんや方法はあるのでやりたいと思ったことはほぼ実現できますが、それが利にかなっているのか?正しい設計なのか?という部分は自分では判断しきれない部分が多々あり難しいですね。。。
もっと勉強しなければ!

参考

Railsのviewのパーシャルで、modelで定義したメソッドを利用すると発生するエラーを解消したい
Railsのモデルに書いたメソッドってどうやってコントローラで使うの?

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

ec2デプロイ、unicorn.logのエラーActiveSupport::MessageEncryptor::InvalidMessage: ActiveSupport::MessageEncryptor::InvalidMessageの解決法

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

EC2デプロイの際のエラーActiveRecord::AdapterNotSpecified: The `production` database is not configured for the `production` environment.

database.ymlに何らかの記述ミスが起こっている。

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

EC2デプロイの際のエラーActiveRecord::AdapterNotSpecified: The `production` database is not configured for the `production` environment.

database.ymlに何らかの記述ミスが起こっている。

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

【CentOS8】CentOS8でrails sをするとlibffi.so.7: cannot open shared object file: No such file or directory

◆エラー

libffi.so.7: cannot open shared object file: No such file or directory

◆解決策

sudo ln /lib64/libffi.so.6 /lib64/libffi.so.7 
sudo ld config

◆効果がなかったこと

●ffiのインストールし直し

gem reinstall ffi

●libffiとlibffi-develが入っているか確認(入ってた)

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

【Ruby/Rails】破壊的メソッドを利用した時にNoMethodErrorが出た時に対処したこと

起きたエラー

filter!の類の破壊的メソッドを使った時にNoMethodErrorが出ました。

対処出来たのでメモがてら残します。(間違ったら優しく教えてください…。)

再現する方法

object_controller.rb
def index
  @object = Object.all
  @object.filter! do |o|
    o.id != 1
  end
end

※命名適当なのは勘弁してください。

オブジェクトをallとかで配列で取得した時に、filterみたいな非破壊的メソッドは使えたのですが、filter!みたいな破壊的メソッドで条件に一致しないオブジェクトを弾いた配列を作ろうとしてました。

ですが、一番最初の見出しの通りNoMethodErrorを吐きました。

対処した方法

object_controller.rb
def index
  @object = Object.all
  @object.to_a.filter! do |o|
    o.id != 1
  end
end

to_aでオブジェクトを配列に変換するとNoMethodErrorを吐かなくなりました。

理由とかは調べて見つけたら追記します。

一旦、忘れないようにメモがてらに残します。(念押し)

既に理由とか知っている人がいて、それくらい当然っしょみたいなノリでしたら、何かにリンクをペタッと貼ってもらえる紳士な方がいてくれると最高に嬉しいです…。

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