20191002のRailsに関する記事は18件です。

【Rspec】attributes_forってなんだ...

はじめに

ポートフォリオの機能を一通り実装し終えたので、Everyday Railsで勉強をしながらRspecでテストを書き始めました。

モデルスペックを書き終え、コントローラスペックを書いている際に「attributes_for」に出会い、ちょっと詰まったので記事にします。

attributes_forとは

Everyday Railsによると、「プロジェクトファクトリからテスト用の属性値をハッシュとして作成します。」、だそうです。

最初の感想としては、「なんのために???buildでよくない???」でした。

まずは見てみよう

buildとattrubutes_forの違いを以下に示します。

まずはFactoryの中身です。

users.rb
FactoryBot.define do
  factory :user do
    name "test"
    sequence(:email) { |n| "test#{n}@test.com"}
    password "password"
  end
end
posts.rb
FactoryBot.define do
  factory :post do
    content 'test content'
    association :user
  end
end

これらを用いたbuildとattributes_forで取得するデータの違いが以下の通りです。

build
> FactoryBot.build(:post)
=> #<Post id: nil, content: "test content", user_id: 8, created_at: nil, updated_at: nil> 
attributes_for
> FactoryBot.attributes_for(:post)
=> {:name=>"test", :email=>"test2@test.com", :password=>"password"}  

buildはモデルオブジェクト、attributes_forはハッシュとなっていますね。(間違えてたら教えてください)

つまり

パラメータとして値を渡す場合、ハッシュを使って渡すことができます。複数のパラメータを送信する場合に、個々にパラメータ名を付けるのではなく、キーと値を組み合わせたハッシュとして渡せます。

これは実際に見てもらったほうがわかりやすいと思います。

posts_controller_spec.rb
#省略

describe "#create" do
    context "ログインユーザーとして" do
      before do
        @user = FactoryBot.create(:user)
      end

      it "投稿ができる" do
          post_params = FactoryBot.attributes_for(:post)
          sign_in @user
          expect{
            post :create, params: { post: post_params}
          }.to change(@user.posts, :count).by(1)
      end
    end
  end

このプログラムの、post :create, params: { post: post_params}に注目してください。
これは、

post :create, params: { post: {:name=>"test", :email=>"test2@test.com", :password=>"password"} }

このプログラムと同義となります。
つまり、POSTメソッドで渡すparamsにpostキーを渡し、そのpostキーのValueをattributes_forの返り値であるハッシュを渡すことで、このように簡潔に書くことができます。(説明下手ですみません...)

上記より、buildではなくattributes_forを使用している意味がわかりました。

最後に

私はまだ業界未経験で、なおかつRspecを書き始めて2日目です。
間違えている部分などありましたら、教えてもらえると非常に助かります。

以上です。

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

rbenvでのruby2.6.1インストール時「Agreeing to the Xcode/iOS license requires admin privileges」で失敗

ruby 2.6.1をrbenvを用いてインストールしようとしたときになぜか落ちたので共有。

落ちた箇所

$ rbenv install 2.6.1                                                                                                                              
Wed Oct  2 15:02:22 2019
Downloading openssl-1.1.0j.tar.gz...
-> https://dqw8nmjcqpjn7.cloudfront.net/31bec6c203ce1a8e93d5994f4ed304c63ccf07676118b6634edded12ad1b3246
Installing openssl-1.1.0j...

BUILD FAILED (OS X 10.14.6 using ruby-build 20190423)

Inspect or clean up the working tree at /var/folders/y4/jzf9wps144x1w4hp2kwp359xrk7xs7/T/ruby-build.20191002150224.4456
Results logged to /var/folders/y4/jzf9wps144x1w4hp2kwp359xrk7xs7/T/ruby-build.20191002150224.4456.log

SIXTY_FOUR_BIT_LONG mode

Configured for darwin64-x86_64-cc.

Agreeing to the Xcode/iOS license requires admin privileges, please run “sudo xcodebuild -license” and then retry this command.

こいつが怪しい。

Agreeing to the Xcode/iOS license requires admin privileges, please run “sudo xcodebuild -license” and then retry this command.

Xcodeのライセンスがどーのと言われているっぽい...

素直にコマンドを実行

エラー文章通りコマンドを実行する。

$ sudo xcodebuild -license

You have not agreed to the Xcode license agreements. You must agree to both license agreements below in order to use Xcode.

すると、ずらーーーーーーーーっとライセンスの情報が出ます(文章を共有するのはやめときます)

q で抜けると、「agree」, 「print」, 「cancel」の3つから操作を求められるので、ターミナル上で「agree」と入力しEnterを押す。

By typing 'agree' you are agreeing to the terms of the software license agreements. Type 'print' to print them or anything else to cancel, [agree, print, cancel]  agree

# agreeを入力してEnter

You can view the license agreements in Xcode's About Box, or at /Applications/Xcode.app/Contents/Resources/English.lproj/License.rtf

すると、インストールできる。

rbenv install 2.6.1                                                                                                                      28.2s  Wed Oct  2 15:03:58 2019
ruby-build: use openssl from homebrew
Downloading ruby-2.6.1.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.1.tar.bz2
Installing ruby-2.6.1...
ruby-build: use readline from homebrew
Installed ruby-2.6.1 to /Users/xxxxxx/.rbenv/versions/2.6.1

なぜライセンス同意をいまさら求められたのかはよくわかりませんが、インストールできたのでOK。

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

初心者のRails失敗談 ~before_action編~

何が起きたか

公開したサイトのトップページで1ヶ月程度、翻訳機能が動作していませんでした。
サイドメニューから英語、中国語、韓国語等が選べる仕様になっていたのですが、全滅・・・

原因

コントローラーでI18n.localeを設定できていませんでした。
というのも、該当のコントローラーの親コントローラーにI18n.localeを取得する処理が書かれていたのですが、それを子コントローラーの方で無きものにしていました。

具体的に

before_action :init

# 初期化
def init
  # I18n.localeを設定
  I18n.locale = get_locale
end

こんな感じで親コントローラー内にbefore_action(アクションの前に呼ばれるフィルタを設定するメソッド)の処理が書いてありました。
にも関わらず、、

before_action :init

# 初期化
def init
  他の処理
end

子コントローラーの方で、新しくinitアクションを作ってしまっていました。
子コントローラーのinitが実行されるので、親コントローラーにあるI18n.locale = get_localeが実行されません。

解決方法

子コントローラーにあるinitを別の名前にする。例えばinit2とか、なんでもOK

振り返り

反省・・・
何かを書き換える時には継承元、継承先をしっかり見る

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

【Rails】ページ内で読み込みたいCSSを�制御する

ソースコードを見ると/app/assets/stylesheets/以下にあるファイルを読み込む記述が自動で書き出されている。
その記述に関してあれこれ変更したかったのでやってみました。

一応環境情報を載せておきます。
ruby:2.6.4
rails:5.2.3

目的

1.ページ内に自動記述されるCSSの読み込み順番を変更したい。
2.SASS使用のためのimportさせるファイルは読み込ませたくない。

方法

自動記述の制御はある程度/app/assets/stylesheets/application.scss内で調整ができる。

application.scss(初期状態)
 /*
  * This is a manifest file that'll be compiled into application.css, which will include all the files |
  * listed below.
  *
  * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's |
  * vendor/assets/stylesheets directory can be referenced here using a relative path. |
  *
  * You're free to add application-wide styles to this file and they'll appear at the bottom of the |
  * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS |
  * files in this directory. Styles in this file should be added after the last require_* statement. |
  * It is generally better to create a new file per style scope. |
  *
  *= require_tree .
  *= require_self
  */

1.ページ内に自動記述されるCSSの読み込み順番を変更したい。

下部にある*= require_tree .から*= require_selfまでを変更する。
アセットパイプラインの仕組みにより、ここで読み込みに関して調整可能。
この仕組みはディレクティブと呼ばれている。
(※デフォルトだとアルファベット順?)

今回は最下部に記述されるapplication.cssを最上部にしたいので以下のように記述しました。

application.scss(変更後)
 *= require_self
 *= require_tree .

変更点は、単純に記述の順番を入れ替えただけ。

*= require_tree .はインクルードさせる記述。
.とあるので/app/assets/stylesheets/を指定していることになる?)

*= require_selfは正直よくわからなかった・・・。勉強します。

例えばhoge01.csshoge02.css...の順で絶対並べたい!という場合は、

application.scss
 *= require_self
 *= require hoge01.css
 *= require hoge02.css
 *= require_tree .

のように書いてあげればOK。

ただし、今の状態だと/app/assets/stylesheets/以下全てのファイルが自動記述されてしまうので、次で調整する。

2.SASS使用のためのimportさせるファイルは読み込ませたくない。

自分はSASSで使用する変数ファイルなどを/app/assets/stylesheets/partial/以下に格納しました。
ひとまずサブディレクトリは読み込まれないようにします。

application.scss(変更後)
 *= require_self
 *= require_directory .

*= require_tree . → *= require_directory .
に変更するだけ。

*= require_directory ./app/assets/stylesheets/pretial/直下にあるファイルだけ読み込むよ、というもの。

自動でやってくれるのはとても便利ですので、なおさら制御方法は知っておかなきゃいけないなと痛感。
まだまだRails開発を始めたばかりなので、今後深掘りしていこうと思います。

参考サイト

RailsでCSSの読み込む順番を制御する方法 - Qiita
Rails 使用するCSSを指定する | | KeruuWeb
Railsのマニフェストファイルを使ったJsとStylesheetの呼び出し - Qiita

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

[質問です。]rubyのapiの叩き方について

rubyでapiを叩きたい

現在プログラミング歴1ヶ月でlinebotを作成しながら勉強しています。

ぐるなびAPIをlinebotに使用したい

ぐるなびAPIをlinebotに使用する所でつまづいており、皆様にご質問があります。

下記エラーが解決出来ません
NoMethodError (undefined method `sample' for nil:NilClass):

該当コードは

linebot_controller.rb
events.each { |event|
      if event.message['text'] != nil
        place = event.message['text'] #ここでLINEで送った文章を取得
        result = `curl -X GET https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=ffb92f0f997a628153ecfa407099fe9b&category_s=RSFST08008&category_s=RSFST08009&#{place}`
      else
        latitude = event.message['latitude']
        longitude = event.message['longitude']

        result = `curl -X GET https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=ffb92f0f997a628153ecfa407099fe9b&category_s=RSFST08008category_s=RSFST08009&latitude=#{latitude}longitude=#{longitude}`#ここでぐるなびAPIを叩く
      end

      hash_result = JSON.parse result  #レスポンスが文字列なのでhashにパースする
      shops = hash_result["rest"] #ここでお店情報が入った配列となる
      shop = shops.sample #任意のものを一個選ぶ

hash_result = JSON.parse result 部分まではしっかり値が入っているのですが、
shops = hash_result["rest"]   ←この部分がnilで返ってきてしまいエラーを吐き出してしまいます。
文法のミス等自分なりにapiを叩く記述を参考にしながら行なったのですが解決出来ません。
皆様のお力をお貸しいただけると幸いです。

以下参考記事
https://qiita.com/NoharaMasato/items/6fb1ac277c965905e019

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

(質問です)rubyのapiの叩き方について

rubyでapiを叩きたい

現在プログラミング歴1ヶ月でlinebotを作成しながら勉強しています。

ぐるなびAPIをlinebotに使用したい

ぐるなびAPIをlinebotに使用する所でつまづいており、皆様にご質問があります。

下記エラーが解決出来ません
NoMethodError (undefined method `sample' for nil:NilClass):

該当コードは

linebot_controller.rb
events.each { |event|
      if event.message['text'] != nil
        place = event.message['text'] #ここでLINEで送った文章を取得
        result = `curl -X GET https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=ffb92f0f997a628153ecfa407099fe9b&category_s=RSFST08008&category_s=RSFST08009&#{place}`
      else
        latitude = event.message['latitude']
        longitude = event.message['longitude']

        result = `curl -X GET https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=ffb92f0f997a628153ecfa407099fe9b&category_s=RSFST08008category_s=RSFST08009&latitude=#{latitude}longitude=#{longitude}`#ここでぐるなびAPIを叩く
      end

      hash_result = JSON.parse result  #レスポンスが文字列なのでhashにパースする
      shops = hash_result["rest"] #ここでお店情報が入った配列となる
      shop = shops.sample #任意のものを一個選ぶ

hash_result = JSON.parse result 部分まではしっかり値が入っているのですが、
shops = hash_result["rest"]   ←この部分がnilで返ってきてしまいエラーを吐き出してしまいます。
文法のミス等自分なりにapiを叩く記述を参考にしながら行なったのですが解決出来ません。
皆様のお力をお貸しいただけると幸いです。

以下参考記事
https://qiita.com/NoharaMasato/items/6fb1ac277c965905e019

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

presence メソッド

presenceメソッドは

def presence
  self if present?
end

で定義されている

使い所

例えば、site_titleというWebページのタイトルを返すメソッドの場合、このような実装になるかと思います。

def site_title(title)
  title.present? ? title : 'サイト名'
end

これをpresenceを使うと下記のようになります。

def site_title(title)
  title.presence || 'サイト名'
end

REFERENCE

http://www.monokoto.xyz/rails-presence/

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

[初心者]Rails6にbootstrap4を導入する

Ruby on railsを学び始めて約2ヶ月、
初めてbootstrapを導入したので、記事を作ってみました。


環境

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.6
BuildVersion:   18G95

$ ruby -v
ruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-darwin18]
$ rails -v
Rails 6.0.0

目次

  1. bootstrapgemを追加
  2. applicationファイルを編集
  3. index.html.erbを編集
  4. bootstrapが導入されているかを確認

1.bootstrap gemを追加

Gemfileに以下を追加

Gemfile
~
gem 'bootstrap', '~> 4.1.1'
gem 'jquery-rails'
~

terminalbundle installを実行
(ローカルでgemを管理している場合は、bundle install --path=vendor/bundleで実行)

これで、プロジェクト内にbootstrapのgemが追加されました。

2.applicationファイルを編集

2.1 application.cssの編集

app>assets>stylesheets>application.cssをエディタで開き、@import "bootstrap";を追加

application.css
~
@import "bootstrap";
~

次に拡張子を.cssから.scssへ変更
application.css → application.scss

2.2 application.jsの編集

app>assets>javascript>application.jsをエディタで開き、//= require bootstrapを追加
(フォルダ、ファイルがなければ作成)
bootstrapはjqueryとpopperに依存しているらしいので導入

application.js
//= require jquery3
//= require popper
//= require bootstrap-sprockets

3.index.html.erb を編集

適当なcontrollerに以下のコードを追加
app>assets>views>コントローラ名>index.html.erb
このコードはbootstrapのサイトにあるテストコードです。

index.html.erb
<a class="btn btn-primary" href="#" role="button">Link</a>
<button class="btn btn-primary" type="submit">Button</button>
<input class="btn btn-primary" type="button" value="Input">
<input class="btn btn-primary" type="submit" value="Submit">
<input class="btn btn-primary" type="reset" value="Reset">

4.動作確認

下準備は整いました。

bundle exec rails sでローカルにサーバーを立ち上げます。
ブラウザにlocalhost:3000/コントローラ名/indexを入力し、画面を確認してください。
以下の表示になっていれば完了です。
スクリーンショット 2019-10-02 19.11.36.png

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

いいね機能の実装

やりたいこと

投稿に対してユーザーがいいねする機能を実装したい!
今やどのWebサービスにも搭載している機能ですね。
Rails勉強中の方は是非この記事を読んで、
やり方を理解して実装できるようになれるようになってください!!
わからないことがあればコメントお願いします!!

やり方

前提

userとpostテーブルがあり、userが親、postが子の親子関係です。

モデル、ルーティング、コントローラー、ビューをそれぞれ説明していきます。

モデル

モデル作成

まずFavoriteモデルを作成します
ターミナルから作成しましょう

ターミナル
rails g model Favorite

モデル編集

その作成されたモデルのファイルにアソシエーションの関係を追記していきましょう

app/models/user.rb
class User < ApplicationRecord
    has_many :posts, dependent: :destroy
    has_many :favorites, dependent: :destroy
end

has_many :posts, dependent: :destroy
has_many :favorites, dependent: :destroyを追記しましょう

has_manyは1つのuserは複数のpost、favoriteを持っているような時に記載します

dependent: :destroyは親のレコードを削除した時に
関連している子供のレコードも全て削除するための記述です。
この記述がある時は、あるuserが削除されるとそのuserが持っているpostを全て削除されます。

app/models/post.rb
class Post < ApplicationRecord
    belongs_to :user
    has_many :favorites, dependent: :destroy
end

belongs_to :user
has_many :favorites, dependent: :destroyを追記しましょう。

belongs_toは1つのpostは1つはuserを持っているような時に記載します。

app/models/favorite.rb
class Favorite < ApplicationRecord
    belongs_to :user
    belongs_to :post
end

belongs_to :user
belongs_to :postを追記しましょう

マイグレーションファイルの編集

次は、モデルを編集した後はテーブルを作成しましょう
以下の3つのマイグレーションファイルにそれぞれ追記していきましょう

db/migrante/******_create_favorites.rb
class CreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      t.integer :user_id
      t.integer :post_id
      t.timestamps
    end
  end
end

t.integer :user_id
t.integer :post_idを追記しましょう。

マイグレーションファイル編集後はbundle installをしましょう。

ターミナル
bundle install

bundle installが成功するとテーブルが作成されます。

ルーティング

まず、ルーティングを以下を追記しましょう。

config/routes.rb
    resources :posts do
        resource :favorites, only: [:create, :destroy]
    end

ターミナル上でrails routesを行いルーティングが通っているか確認しましょう

コントローラー

まずコントローラーを作成しましょう

ターミナル
rails generate controller Favorites

favorites_controller

作成されたコントローラーを編集していきます
いいねボタンが押された時に繋がるアクションを記述していきましょう

createアクション

app/controllers/favorites_controller
def create
    @post_favorite = Favorite.new(user_id: current_user.id,post_id: params[:post_id])
    @post_favorite.save
    result = [done: "save",user_id: current_user.id, post_id: params[:post_id]]
    redirect_to post_path(params[:post_id])
end

destroyアクション

app/controllers/favorites_controller
def destroy
    @post_favorite = Favorite.find_by(user_id: current_user.id, post_id: params[:post_id])
    @post_favorite.destroy
    result = [done: "destroy",user_id: current_user.id, post_id:params[:post_id]]
    redirect_to post_path(params[:post_id])
end

ビュー

いいねボタンを投稿の詳細画面に実装していきます
まず、ログインしているユーザーが投稿に対していいねしているかどうかで表示内容を変更します。

app/models/post.rb
def favorited?(user)
    favorites.where(user_id: user.id).exists?
end

モデルにいいねしているかどうかを判定するメソッドを記入します

if @post.favorite?(current_user)
    #ユーザーがいいねしていた時の処理(destroyアクションへのリンク)
else
    #ユーザーがいいねしていない時の処理(createアクションへのリンク)
end

実際にビューファイルに以下の記述を追加していきましょう

app/views/posts/show.html.erb
<%if @post.favorite?(current_user)%>
    <%= link_to post_favorites_path(@post), method: :delete do %>
        <span style="color:red;">❤︎</span>
    <%end%>
<%else%>
    <%= link_to post_favorites_path(@post), method: :post do %>
        <span>❤︎</span>
    <%end%>
<%end%>

疑問、気になるところございました、コメントください!!

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

cloud9 環境 で rails 5.2.3を初めて設定してみた。

概要

Rubyを学び始めた初学者です。clou9でruby開発環境を整えるまで2日かかってしまいました。rails6.0.0をインストールしてもrailsサーバーが起動できなかった(yarnインストールができず、諦めました。)ため、rails5.2.3で構築してみましたよ。初投稿。
間違っている所などありましたら、ご指摘頂けると嬉しいです。

前提条件

amazon web serviceアカウントを持っている方
cloud9環境での開発を考えている方

環境

ruby 2.6.5
rails 5.2.3
sqlite3 3.7.17

ruby 2.6.5 のインストール

environmentディレクトリにて、コードの実行をする。

インストール可能なruby一覧情報

rvm list know

rubyのインストール

rvm install 2.6.5

複数インストールしたrubyから、選択する

rvm use 2.6.5

インストールされているrubyの内、どれが使われているか確認

rvm list

インストールされているrubyを、選択して削除

rvmsudo rvm remove 2.6.5

インストールした複数のrubyから、デフォルトとして設定

rvm --default use 2.6.5

rails 5.2.3のインストール

environmentディレクトリにて、コードの実行をする。
```gem install rails --version="5.2.3"

railsプロジェクトの作成

『プロジェクト名』のフォルダを作成。
以下、コマンドでディレクトリ移動。

cd 『プロジェクト名』

rails _5.2.3_ new フォルダ名 を入力。
『フォルダ名』ディレクトリへ移動。
cd 『フォルダ名』

bundleのインストール

bundle install

sqlite3の更新設定

gemfile→の中→9行目あたりの
sqlite3の後に,'~>1.3.6'と入力

ターミナルにて、
bundle update
rails db:createと入力

サーバーの起動

ターミナルにて、
rails sと入力

上部タブ『preview』から『preview runnning applecation』を選択
URLを確認。

rails スタートの画面になっていれば成功。

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

Deviseを入れた後、コンソールからのUser.firstやUser.all等がArgmentErrorになる

結論

Userモデルから
password_digestカラム
を削除すると解消する。

起こったこと

Deviseを入れた後、コンソールからのUser.firstやUser.all等が下記のようにArgmentErrorになる

irb(main):001:0> User.all
  User Load (1.8ms)  SELECT  "users".* FROM "users" LIMIT ?  [["LIMIT", 11]]
Traceback (most recent call last):
ArgumentError (wrong number of arguments (given 0, expected 1))
irb(main):002:0> User.find(1)
  User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
Traceback (most recent call last):

下記のissueにある通り、DeviseでUserモデルをセットアップした時に、既にUserモデルに
password_digestカラム
が存在すると、上記のエラーが出ます。

参考
https://github.com/plataformatec/devise/issues/

スクリーンショット 2019-10-02 15.56.22.png

今回は既にUserモデルを作っていて、後からDeviseを導入したのでおそらくDeviseの
encrypted_passwordカラム
とバッティングして発生していると思われる。

なので、Userモデルから
password_digestカラム
を削除すると解消しました。

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

Rails スクレイピングでデータを取得(getメソッド・searchメソッド編)備忘録

スクレイピングとは

  • 例えば、以下のようなHTMLのサイトがあった場合
index.html
<ul>
  <li>TEST1</li>
  <li>TEST2</li>
  <li>TEST3</li>
</ul>

<ul><li>の中にある「TEST1, TEST2, TEST3」等の値を取り出すことを言う。(ウェブサイト上のHTMLからある特定のデータを抜き出す処理のこと)

Mechanize

  • Mechanizeはスクレイピングを行うためのGemである。
  • Mechanizeクラスが使えるようになる。
  • Mechanizeクラスにはスクレイピングするための様々なメソッドが用意されている。

GemfileにMechanizeを追記(Railsの場合)

Gemfile
# 省略

gem 'mechanize'

bundle installすればOK

Mechanizeクラスで使うメソッドの紹介

HTML情報から指定のタグ要素の情報を検索する

searchメソッド

  • getメソッドで取得したページの情報が入ったオブジェクトに対して使用する。
  • 該当するHTMLのタグ要素が1つでも、返り値は配列の形式で返ってくる。

使い方

elements = Mechanize::Pageオブジェクト.search('セレクタ')

あるウェブページからh2要素のHTMLの情報を取得する場合

scraping.rb
agent = Mechanize.new
page = agent.get("http://sample.com/")
elements = page.search('h2') # h2要素を検索
puts elements
  • 出力結果(例)
<h2 class="entry-title index-entry-title">
<a href="/products/1" title="Single Post">sample1</a>
            </h2>
<h2 class="entry-title index-entry-title">
<a href="/products/2" title="Single Post">sample2</a>
            </h2>
<h2 class="entry-title index-entry-title">
<a href="/products/3" title="Single Post">sample3</a>
            </h2>
#以下略

h2要素の下のa要素のHTML情報を取得してみる

scraping.rb
agent = Mechanize.new
page = agent.get("http://sample.com/")
elements = page.search('h2 a') # h2要素の下のa要素を検索
puts elements
  • 出力結果(例)
<a href="/products/1" title="Single Post">sample1</a>
<a href="/products/2" title="Single Post">sample2</a>
<a href="/products/3" title="Single Post">sample3</a>
<a href="/products/4" title="Single Post">sample4</a>
# 以下略

このように、該当するHTMLのタグ要素全てが取得される。

  • 以下のようにするとsearchメソッドの返り値が配列の形式になっていることが確認できる。
test_scraping.rb
require 'mechanize'

agent = Mechanize.new
page = agent.get("http://sample.com/")
elements = page.search('h2 a') # h2要素の下のa要素を検索
puts elements[0]
  • 出力結果
ターミナル
<a href="/products/1" title="Single Post">Sample1</a>

以上のように返ってきた値の1番目の要素を取り出すことができるので配列の形式で返ってきていることがわかる。

まとめ

以上でmechanizeを使用したメソッドのうちgetメソッドsearchメソッドの2つを紹介しましたが今日は時間切れなので後日、他の使える便利なメソッドを紹介したいと思う。

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

bundle install時にインストール先のpathを変える

bundle install時にインストール先のpathを変える

(anyenv, rbenv利用)

deviseインストール。

ログを見ると、.anyenv/envs/rbenv/以下へdeviseがインストールされ、実行されている。

スクリーンショット 2019-10-02 14.52.07.png

bundle install時にpathを指定しないと、rbenvを利用している場合は.anyenv/envs/rbenv/以下にインストールされる。

参考
https://qiita.com/chro96/items/35f67767d0b511939fea

deviseのファイルを編集するのに.anyenv/envs/rbenv/以下だとやりづらいため、プロジェクト以下にインストールしたい。

そのため、bundle install時にpathを指定する。

-j4は bundle install を並列処理するコマンド。
bundle install が早くなる。
https://qiita.com/camelmasa/items/5ca27ab398f105f86c76

$ bundle install -j4 --path .bundle

これでプロジェクト内に、.bundleというディレクトリが作成され、gemがインストールされ、.bundle/以下にあるファイルで実行されることを確認。

スクリーンショット 2019-10-02 14.52.39.png

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

Rails6 のちょい足しな新機能を試す87(Time#advance編)

はじめに

Rails 6 に追加された新機能を試す第87段。 今回は、 Time#advance 編です。
Rails 6 では、 1001/03/07 以前の Time#advance の計算が正確になりました。

Ruby 2.6.4, Rails 6.0.0 Rails 5.2.3 で確認しました。

$ rails --version
Rails 6.0.0

今回は、ちょっとわざとらしいですが、2009年4月1日の1200年前に即位した天皇を検索してみましょう。

プロジェクトを作る

rails new rails_sandbox
cd rails_sandbox

Emperor モデルを作る

nameenthroned_at (即位した年) をもつ Emperor モデルを作ります。

bin/rails g model Emperor name enthroned_at:datetime

seed データを作る

seed データを作ります。

db/seeds.rb
Emperor.create(
  [
    { name: '桓武天皇', enthroned_at: Time.utc(781, 4, 3) },
    { name: '平城天皇', enthroned_at: Time.utc(806, 3, 17) },
    { name: '嵯峨天皇', enthroned_at: Time.utc(809, 4, 1) },
    { name: '淳和天皇', enthroned_at: Time.utc(823, 4, 16) },
    { name: '仁明天皇', enthroned_at: Time.utc(833, 2, 28) }
  ]
)

マイグレーションを行い seed データを登録する

$ bin/rails db:create db:migrate db:seed

rails console で確認する

enthroned_at が 2009年4月1日の 1200年前に即位した天皇を検索してみます。

「2009年4月1日の 1200年前」は、 Time.utc(2009, 4, 1).advance(years: 1200) で求めることができます。

irb(main):001:0> Emperor.where(enthroned_at: Time.utc(2009, 4, 1).advance(years: -1200))
  Emperor Load (0.3ms)  SELECT "emperors".* FROM "emperors" WHERE "emperors"."enthroned_at" = $1 LIMIT $2  [["enthroned_at", "0809-04-01 00:00:00"], ["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<Emperor id: 3, name: "嵯峨天皇", enthroned_at: "0809-04-01 00:00:00", created_at: "2019-09-21 21:49:24", updated_at: "2019-09-21 21:49:24">]>

嵯峨天皇が検索できました。

Rails 5.2.3 では

「2009年4月1日の 1200年前」が 809年4月5日になってしまうため、期待した結果が得られません

irb(main):001:0> Emperor.where(enthroned_at: Time.utc(2009, 4, 1).advance(years: -1200))
  Emperor Load (0.5ms)  SELECT  "emperors".* FROM "emperors" WHERE "emperors"."enthroned_at" = $1 LIMIT $2  [["enthroned_at", "0809-04-05 00:00:00"], ["LIMIT", 11]]
=> #<ActiveRecord::Relation []>

試したソース

試したソースは以下にあります。
https://github.com/suketa/rails_sandbox/tree/try087_time_advance

参考情報

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

Railsアプリ〜デプロイへの道〜その②Ruby・MySQLインストール編【ConoHa VPS・CentOS・Capistrano3・Nginx・Unicorn】

Railsアプリケーションをデプロイした時の手順をまとめた記事の第2弾です。

今回はRubyおよびMySQLのインストール・設定の手順をまとめました。

前回同様こちらの記事がベースとなっています。
https://qiita.com/ryo2132/items/f62690f0b16ec11270fe

〈前回記事〉
Railsアプリ〜デプロイへの道〜その①リモートサーバーへのSSH接続編

開発環境

・Mac OS
・Rails 5.2.3
・Ruby 2.5.1
・ConoHa VPS
・CentOS 7.6
・Capistrano3
・Nginx
・Unicorn

Rubyのインストール

ConoHa VPSにRubyをインストールしていきます。

1.Gitインストール

まずGitをインストールします。

$ sudo yum -y install git

$ git --version
# version名出力されればOK

2.rbenvインストール

続いてrbenvをインストール。
rbenvはRubyのバージョン管理ツールです。

$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv

ruby-burildインストール

こちらもRubyをインストールするために必要になります。

$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build

3.rbenv設定

rbenvコマンドを使えるようにするためにbash_profileに以下の内容を追加します。

# PATHにrbenvコマンドを追加
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
# rbenvの初期化
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
# bashの再読込
$ source ~/.bash_profile
# rbenvのバージョン確認 バージョンが出ればOK
$ rbenv -v

これでRubyインストールの準備は完了です。
いよいよRubyをインストールします。

4.Rubyインストール

ローカルで使用中のRubyバージョンを確認
サーバーにインストールする前に、開発で使用したRubyのバージョンを確認します。

ローカル

$ ruby -v

ローカルと同じバージョンのRubyをインストール

サーバー

$ rbenv install 2.5.1 
# globalで使用するrubyの設定
$ rbenv global 2.5.1
# rbenvの再起動?
$ rbenv rehash
# rubyのバージョン確認
$ ruby -v

5.bundleインストール

Gemの管理ツールであるbundlerをインストールします。

bundlerのバージョンを開発したRailsアプリのGemfile.lockのものと合わせる必要があります。
バージョンが合っていないとデプロイ時にエラーが発生します。
参考:https://qiita.com/MotohiroSiobara/items/c0d343a160cffc2902ef

RailsアプリのGemfile.lockを確認

BUNDLED WITH 2.0.1

サーバー
同じバージョンのbundlerをインストール。

$ gem install bundle -v 2.0.1

6.関連パッケージインストール

必要なパッケージを諸々インストール
これらがないとデプロイ時にエラー起こします。

<参考>
https://teratail.com/questions/13430
https://qiita.com/jaxx2104/items/2277cec77850f2d83c7a

サーバー

#gcc-c++インストール
$ sudo yum install gcc-c++

#node.jsインストール
$ sudo yum install nodejs npm --enablerepo=epel 

#yarnインストール
$ sudo npm install -g yarn

MySQL

1.事前準備:MariaDBの削除

CentOS7系では標準でMariaDB(MySQL互換のDB)がインストールされている場合があるので、MySQLと競合しないようMariaDBを削除します。

参考:https://qiita.com/miqpim/items/5c519a9979d9b269d47e

サーバー

$ rpm -qa | grep maria     # mariaDBが存在するか確認
$ sudo yum remove mariadb-libs  # 本体削除
$ sudo rm -rf /var/lib/mysql  # データ削除

rmコマンドのオプションについてはこちらをご覧ください。
参考:https://eng-entrance.com/linux_command_rm

2.MySQLのリポジトリを登録

Mysql公式のYumリポジトリをインストールします。
最新版はMysql公式で確認できます。

サーバー

〈参考〉
https://qiita.com/rutko/items/56a33d1ecd70c0480202
https://qiita.com/nooboolean/items/7efc5c35b2e95637d8c1

CentOSのバージョンの確認

$ cat /etc/redhat-release

リポジトリのインストール

yumコマンドのlocalinstallオプションを使うことでリモートにあるrpmファイルをインストールすることができます。
rpmコマンドを使ってのインストールも可能ですが、依存関係とかを考慮したインストールまではしてくれないので、yumでインストールしましょう。
URLはリモートにあるrpmファイルをインストールするためのもので、公式サイトのリポジトリを、 http://dev.mysql.com/get/の後に付け加えて完成です。(お使いのOSに合わせたものを選んでください)

詳しくはこちらの記事をご覧ください。
https://qiita.com/nooboolean/items/7efc5c35b2e95637d8c1

$ sudo yum localinstall http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm

リポジトリの確認

/etc/yum.repos.d配下に、mysql-community-source.repoとmysql-community.repoというリポジトリが作成されてるはずです。

$ cd /etc/yum.repos.d/
$ ls
mysql-community-source.repo  mysql-community.repo

このリポジトリが作成されて入れば、リポジトリの追加の確認は完了

インストールできたか確認

$ yum repolist all | grep mysql

mysql-connectors-community/x86_64 MySQL Connectors Community      有効:
mysql-connectors-community-source MySQL Connectors Community - So 無効
mysql-tools-community/x86_64      MySQL Tools Community           有効:
mysql-tools-community-source      MySQL Tools Community - Source  無効
mysql55-community/x86_64          MySQL 5.5 Community Server      無効
mysql55-community-source          MySQL 5.5 Community Server - So 無効
mysql56-community/x86_64          MySQL 5.6 Community Server      無効  <-ここ注目
mysql56-community-source          MySQL 5.6 Community Server - So 無効
mysql57-community/x86_64          MySQL 5.7 Community Server      有効: <-ここ注目
mysql57-community-source          MySQL 5.7 Community Server - So 無効

(環境によっては有効がenabled、無効がdisabledと表示される)
上記の例では、5.7が有効、5.6が無効になっています。
このままインストールすると、有効になっている5.7がインストールされてしまうので、5.6をインストールするには有効無効の切り替えをします。
この切り替えをするためにはyumの設定変更用のyum-utilsパッケージが必要なので、インストールされていない場合はインストールします。

$ yum list installed | grep yum-utils  #yum-utilsがインストールされているか確認
$ yum -y install yum-utils #入ってなければyum-utilsをインストールする
$ yum-config-manager --disable mysql57-community     #5.7を無効に設定
$ yum-config-manager --enable mysql56-community       #5.6を有効に設定

設定ができているか再度確認。

$ yum repolist all | grep mysql

mysql-connectors-community/x86_64  MySQL Connectors Community       有効:    
mysql-connectors-community-source  MySQL Connectors Community - Sou 無効
mysql-tools-community/x86_64       MySQL Tools Community            有効:     
mysql-tools-community-source       MySQL Tools Community - Source   無効
mysql55-community/x86_64           MySQL 5.5 Community Server       無効
mysql55-community-source           MySQL 5.5 Community Server - Sou 無効
mysql56-community/x86_64           MySQL 5.6 Community Server       有効:    
mysql56-community-source           MySQL 5.6 Community Server - Sou 無効
mysql57-community/x86_64           MySQL 5.7 Community Server       無効
mysql57-community-source           MySQL 5.7 Community Server - Sou 無効

5.6が有効になっていればOK。

#バージョン確認
$ yum info mysql-community-server
# インストール
$ sudo yum install mysql-community-server mysql-devel

mysql-develは必要です。
ないとデプロイ時にエラーが出ます。
参考:https://teratail.com/questions/181707

# 確認。バージョン出ればOK
$ mysqld --version

Mysqlの起動/自動起動設定

起動

$ sudo systemctl start mysqld.service   #起動

自動起動設定

$ sudo systemctl enable mysqld.service   #自動起動 ON
$ systemctl disble mysqld   #自動起動 OFF

自動起動になっているか確認

$ systemctl is-enabled mysqld

mysqld.service is not a native service, redirecting to /sbin/chkconfig.
Executing /sbin/chkconfig mysqld --level=5
enabled

enabledになっていれば自動起動 ONに設定されています。

基本操作

$ sudo systemctl start mysqld.service   #起動
$ systemctl stop mysqld    #停止
$ systemctl status mysqld  #ステータス確認
$ systemctl restart mysqld #再起動

ちなみに、mysqldのdはデーモン (daemon)のdらしいです。
デーモンについてはこちらの記事をご覧ください。
https://wa3.i-3-i.info/word11000.html

簡単に言うと「いつでも動けるようにスタンバイしてる常駐プログラム」だそうです。

3.パスワード、セキュリティ設定

続いてMySQLの設定をしていきます。
今回の山場です。
参考:https://weblabo.oscasierra.net/mysql-57-init-setup/

ログインするために、まず自動生成された初期パスワードを確認します。

$ sudo cat /var/log/mysqld.log | grep password
2017-12-31T11:31:07.946947Z 1 [Note] A temporary password is generated for root@localhost: .7ogGO4yokDh
# 「.7ogGO4yokDh」の部分が初期パスワードです

確認できたらmysql_secure_installationで初期設定を行います。
以下対話形式で進むので適宜コマンド入力してください。

$ mysql_secure_installation


Securing the MySQL server deployment.

Enter password for user root: # ログファイルから取得した初期パスワードを入力します

The existing password for the user account root has expired. Please set a new password.

New password: # root ユーザの新規パスワードを入力します

Re-enter new password: # 確認用にもう一度入力します
The 'validate_password' plugin is installed on the server.
The subsequent steps will run with the existing configuration
of the plugin.
Using existing password for root.

Estimated strength of the password: 100
Change the password for root ? ((Press y|Y for Yes, any other key for No) : y

By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : y # 匿名ユーザーアカウントを削除
Success.


Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y # ローカルホスト以外からアクセス可能な root アカウントを削除
Success.

By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.


Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y # test データベースの削除
 - Dropping test database...
Success.

 - Removing privileges on test database...
Success.

Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y
Success.

All done!

4.日本語化

日本語を扱うために文字コードを設定します。
日本語の文字コードはutf8に設定すると思いますが、utf8mb4は絵文字に対応した文字コードなので、僕はutf8ではなくutf8mb4で設定しています。

現状、問題なく使えています。

〈参考〉
https://qiita.com/okamu_/items/5eb81688849fbe351350
https://qiita.com/jkr_2255/items/74fc79e764378b59355a

$ sudo vi /etc/my.cnf

#ファイル内の末尾に以下を追記
[mysqld]
character-set-server=utf8mb4

[client]
default-character-set=utf8mb4

#再起動
$ sudo systemctl restart mysqld.service

#文字コード確認
$ mysql -u root -p

$ show variables like "chara%";

utf8mb4になってたらOK!

5.Time-zone設定

〈参考〉
https://dev.mysql.com/doc/refman/8.0/en/time-zone-support.html
https://agohack.com/mysql-change-timezone/

現在のタイムゾーンを確認

$ show variables like '%time_zone%';

system_time_zone : UTC
time_zone : SYSTEM

タイムゾーンデータの確認

$ select * from mysql.time_zone;

空の場合は、データをインポートする。

タイムゾーンのインポート

$ /usr/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo > ~/timezone.sql
# passwordを聞かれるのでmysqlのパスワードを入力
$ mysql -u root -p -Dmysql < ~/timezone.sql

設定の追加

$ sudo vi /etc/my.cnf

# 末尾に以下を追加
[mysqld]
default-time-zone = 'Asia/Tokyo'

再起動

$ sudo systemctl restart mysqld.service

確認

mysql > show variables like '%time_zone%';

# 以下表示が出ればOK
+------------------+------------+
| Variable_name    | Value      |
+------------------+------------+
| system_time_zone | JST        |
| time_zone        | Asia/Tokyo |
+------------------+------------+
2 rows in set (0.00 sec)

MySQLの自動起動設定
サーバーの再起動の際にも、mysqlが自動的に起動するよう設定します。

chkconfig mysqld on

まとめ

以上、Railsアプリ〜デプロイへの道〜その②Ruby・MySQLインストール編でした。

次回はいよいよCapistrano3・Nginx・Unicornの設定です。(予定)

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

canvasで描いた絵のURLをDBに保存する

概要

私は9月ごろから独学でRuby on Railsを始めたのですが、題名の通りcanvasで描いた絵をURLに変換してDBに保存する際に数日詰まったので自分への戒めのために今回の記事を書く運びとなりました。

詰まったところ

ArgumentError (When assigning attributes, you must pass a hash as an argument.):

ハッシュにしてから受け渡してください的なエラーが出る。

受け渡したデータ

JavaScriptでcanvasのデータをURL化しているため、そのままJavaScriptでPOSTしました。
こんなかんじ

//変数imageにはcanvasのURLが入っています
function send_url(image){
                var form = document.createElement('form');
                var request = document.createElement('input');

                form.method = 'POST';
                form.action = 'save';

                request.type = 'hidden';
                request.name = 'text';
                request.value = image;

                form.appendChild(request);
                document.body.appendChild(form);

                form.submit();
}

受け取り側はこのようになっています

private
    def post_params
          params.require(:text)
    end
end

この形式で受け取るとpost_paramsは送信されてきた文字列だけをデータに持ちます。

修正後

先ほどの関数post_paramsを次のように書き換えました

def post_params
      img = params.require(:text)
      hash_url = {"image_url" => img}
      return hash_url
end

力技です。

最後に

セキュリティなどの観点で見てこれが大丈夫なやり方なのかはわかりませんが、とりあえずこのハッシュにしたデータを渡すことで無事URLをDBに渡すことができました。

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

【Rails on Docker on Heroku】ActiveStorage + Cloudinaryで画像を管理するメモ

はじめに

この記事はRuby on RailsのActiveStorageとCloudinaryを使って画像を管理するアプリを作るためのメモです。PaaSとしてHerokuを使います。

ActiveStorageはRails 5.2以上で動作するクラウドストレージサービスへのファイルのアップロードやActiveRecordオブジェクトへのファイルのアタッチをやってくれる便利なモデルです。

Cloudinaryは画像や動画のCDNや編集の機能を有するSaaSです。Herokuのadd-onsとしても存在しています。

この記事のゴール

この記事では、Heroku上でユーザー名とプロフィール写真を管理するRuby on Railsアプリケーション(on Docker)をHeroku上で動作させることをゴールにします。DB/StorageはHerokuのadd-onsからPostgres/Cloudinaryを使います。
Untitled Diagram.png

前提

メモ

1. ActiveStorageのアプリを作る

こちらの記事が参考になりました。
【Rails 5.2】 Active Storageの使い方 - Qiita

まずファイルをアタッチするモデルとしてUserモデルをscaffoldで作っておきます。

$ docker-compose run --rm web rails g scaffold user name:string
$ docker-compose run --rm web rails db:migrate

続いて、ActiveStorageをインストール。

$ docker-compose run --rm web rails active_storage:install
$ docker-compose run --rm web rails db:migrate

ActiveStorageはモデルにhas_one_attachedを定義するだけでファイルを扱えるようになる優れものです。

app/models/user.rb
class User < ApplicationRecord
  has_one_attached :photo
end

これでphotoという名前のファイルをActiveStorageが勝手に管理してくれます。
ファイルのアップロードと参照ができるようにview/controllerも手直ししておきます。

app/controllers/users_controller.rb
def user_params
  # photoの登録を許可
 params.require(:user).permit(:name, :photo)
end
app/views/users/_form.html.erb
<!-- 以下をいい感じのところに追加 -->
<div class="field">
  <%= form.label :photo %>
  <%= form.file_field :photo %>
</div>
app/views/users/show.html.erb
<!-- 以下をいい感じのところに追加 -->
<div>
  <% if @user.photo.attached? %>
    <%= image_tag @user.photo %>
  <% end %>
</div>

これでUserモデルでphotoとしてファイルを管理できるようになりました。
この段階ではphotoとして登録されるファイルはstorage/に保存されていきます。これは

config/environments/development.rb
config.active_storage.service = :local
config/storage.yml
local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

で定義されています。

2. Herokuの準備

HerokuはHeroku CLIで操作していきます。まずはadd-onsでpostgresとcloudinaryの準備が必要です。まずHerokuにログインしてアプリを作成します。

$ heroku login
$ heroku create app-name

このアプリに対してpostgresとcloudinaryのadd-onsを追加してきます。postgresは無料のhobby-dev、cloudinaryも無料のstarterというプランを使っていきます。cloudinary:starterはクレカ登録してないと使えないみたいですね。

$ heroku addons:create heroku-postgresql:hobby-dev
$ heroku addons:create cloudinary:starter

3. ActiveStorageとCloudinaryを連携させる

ActiveStorageとCloudinaryを連携させるためにGitHub - 0sc/activestorage-cloudinary-serviceを利用します。

READMEの通りにやっていけばOKです!

Gemfile
gem 'cloudinary', require: false
gem 'activestorage-cloudinary-service'
$ docker-compose build

Cloudinaryと連携するためのcloud_nameapi_keyapi_secretの情報をRailsアプリに登録してきます。これらの情報はHerokuサイトでOverviewのところから各アドオンのサイトにリンクされているんですが、リンク先のCloudinaryのDashboardに情報が載ってます。
Rails5.2以降であればcredentialsを利用しているかと思いますので、そちらの方法で。

$ docker-compose run --rm -e EDITOR="vim" web rails credentials:edit
cloudinary:
  cloud_name: xxxxxxxxxx
  api_key: xxxxxxxxxx
  api_secret: xxxxxxxxxx

※vimがないとか言われる場合は【Rails 5.2.2】Rails on Dockerでcredentialsをeditしたい - Qiitaあたりを参考にしていただけますと!
この設定をconfig/storage.ymlから呼び出します。

config/storage.yml
# 以下を追加
cloudinary:
  service: Cloudinary
  cloud_name: <%= Rails.application.credentials.dig(:cloudinary, :cloud_name) %>
  api_key: <%= Rails.application.credentials.dig(:cloudinary, :api_key) %>
  api_secret: <%= Rails.application.credentials.dig(:cloudinary, :api_secret) %>

そして、config/environments/development.rbで指定されているconfig.active_storage.serviceも書き換えます。

config/environments/development.rb
# config.active_storage.service = :local
config.active_storage.service = :cloudinary

本当はproduction.rbを書き換えて、heroku側のconfigもRAILS_ENV=productionとするべきなのですが、今回のメモはお試しなのでdevelopmentで進めますね。

ここまででRailsアプリ、Herokuのadd-onsの準備は完了になりますので、あとはこのアプリをdeployしていくだけです。

4. Rails on DockerをHerokuにDeployする

Rails on DockerのHerokuへのDeploy方法は以下の記事でもまとめています。
Rails on DockerをHerokuでDeployするまで - Qiita

この記事ではpostgresのadd-ons追加などが完了しているので必要なところだけ書いていきます。

$ heroku container:login
$ heroku container:push web
$ heroku container:release web
$ heroku run rails db:migrate

これでアプリのデプロイが完了するはずなので、あとはサイトを開いてみます。

$ heroku open

ローカルでテストしてみた時と同じようにファイルをアップロードできるはずです。
また、Cloudinaryのサイトの「Media Library」にその画像ファイルが登録されているのみ見れるはずです。

ちなみにActiveStorageはそのモデルが削除されるときに画像ファイルも一緒にdeleteしてくれるのもすごい便利ですね。

あとがき

ということで、Rails on Docker on HerokuでActiveStorage + Cloudinaryの画像管理ができました。
Carrier Waveとかなしで画像扱えるのは便利でした〜。herokuも1コマンドでアドオンが追加できて便利!

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

[Rails]ローディング機能の実装

はじめに

今回動画を投稿した後など読み込む時間がかかったりして、待つ時間があったのが気になったので以下のようなローディングのアニメーションの実装をしました。
6aa53b09fa53faa9eba3cd90fe6d5b59.gif

環境

Rails 5.2.3
Ruby 2.5.1

実装方法

様々な方法がありますが、私の場合は以下を参考にしてCSSでアニメーションを作成しました。

参考資料

https://recooord.org/loading-animation/

ビューファイル

先ずapplication.html.hamlファイルにローディングアニメーション用のクラスをbody下に記述します。

application.html.haml
%body
 .loader-wrap
   .loader

SCSSファイル

次にSCSSにローディングアニメーション用のレイアウトを記述します。
色々記述してますが、先程の参考資料の中にあるサイトの内容を殆どコピペするだけで実装出来ます。
後は色や大きさなどを変更したりして自分の好みのレイアウトにして下さい。

使用サイト:Single Element CSS Spinners

https://projects.lukehaas.me/css-loaders/
スクリーンショット 2019-10-02 0.34.40.png

loading.scss
.loader-wrap {
    position: fixed;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
}


.loader,
.loader:before,
.loader:after {
  border-radius: 50%;
}
.loader {
  color: black;
  font-size: 11px;
  text-indent: -99999em;
  margin: 55px auto;
  position: relative;
  width: 10em;
  height: 10em;
  box-shadow: inset 0 0 0 1em;
  -webkit-transform: translateZ(0);
  -ms-transform: translateZ(0);
  transform: translateZ(0);
}
.loader:before,
.loader:after {
  position: absolute;
  content: '';
}
.loader:before {
  width: 5.2em;
  height: 10.2em;
  background: white;
  border-radius: 10.2em 0 0 10.2em;
  top: -0.1em;
  left: -0.1em;
  -webkit-transform-origin: 5.2em 5.1em;
  transform-origin: 5.2em 5.1em;
  -webkit-animation: load2 2s infinite ease 1.5s;
  animation: load2 2s infinite ease 1.5s;
}
.loader:after {
  width: 5.2em;
  height: 10.2em;
  background: white;
  border-radius: 0 10.2em 10.2em 0;
  top: -0.1em;
  left: 5.1em;
  -webkit-transform-origin: 0px 5.1em;
  transform-origin: 0px 5.1em;
  -webkit-animation: load2 2s infinite ease;
  animation: load2 2s infinite ease;
}
@-webkit-keyframes load2 {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
@keyframes load2 {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}

後は今回はSCSSを使用している為、@importapplication.scssにSCSSファイルを読み込むのを忘れないようにします。

application.scss
@import "loading";

jQuery

後はアニメーションの設定をJSファイルに記述するだけです。
使用部分は「ページの読み込みが完了したらアニメーションの非表示の部分」まででも問題ありません。

loading.js
$(document).on('turbolinks:load', function() {
  $(function(){
    var loader = $('.loader-wrap');

    //ページの読み込みが完了したらアニメーションを非表示
    $(window).on('load',function(){
      loader.fadeOut();
    });

    //ページの読み込みが完了してなくても2秒後にアニメーションを非表示にする
    setTimeout(function(){
      loader.fadeOut();
    },2000);
  });
});

最後に

画像を使用する方法も他にありましたが、私は今回こちらの方で実装しました。
結構簡単に実装出来るので気になった方は試してみて下さい。

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