20190415のRailsに関する記事は30件です。

model内のインスタンスメソッドの中でインスタンスの属性値を取得する

経緯

  • 自分が書いた過去のコード(Ruby書き始めだった頃のもの)を見ていると、「今はとりあえずこのようにしか書けないけど、本当はもっとよりよく書けるはずだ」と思っていた部分が目に入ったので、直します。
  • 表題の件について、誰か同じように詰まった方の参考になれればいいのですが。。。

修正前

  • 以下のようなコードです。しかしすごい書き方していますね。。。
game.rb
  def get_gameset_msg
    gameset_msg = "試合中"
    if self[:gameset_flag]
      gameset_msg = "試合終了"
    end
    return gameset_msg
  end

修正後

  • カラム名は修正していませんが、「gameset_flag」は「is_gameset」とかの方がいいんでしょうか。。。
game.rb
  def get_gameset_msg
    self.gameset_flag ? "試合終了" : "試合中"
  end

ポイント

  • 基本的な取得方法(修正後と同じコード)
    • model内のインスタンスメソッドの中では、selfでインスタンス本体を指します。self.xxxで属性値を取得できます。(こういう書き方って、あんまり載ってない気がするのですが。。。)
game.rb
  def get_gameset_msg
    self.gameset_flag ? "試合終了" : "試合中"
  end
  • 属性名を動的に生成する場合
    • イニングごとの得点を合計した値が欲しい場合などは、動的にカラム名を生成することでコード量を減らせますが、この場合はハッシュのvalueを取得するように書きます。self.xxxのようには書けません。
game.rb
  def get_sum_top
    sum_top = 0
    9.times {|n|
      str_top = "top" << (n + 1).to_s
      sum_top += self[str_top].to_i
    }
    sum_top
  end
  • 属性名を動的に生成する場合(その2)
    • 上記のコードは、以下のようにsendメソッドを使って書くこともできます。メソッド名を文字列で指定して実行する場合に使えるメソッドです。ただ、今回のような場合は上記のようにself[str_top]の方が短くていいですかね。
game.rb
  def get_sum_top
    sum_top = 0
    15.times {|n|
      str_top = "top" << (n + 1).to_s
      sum_top += self.send(str_top).to_i
    }
    sum_top
  end

参考

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

rails devise name login

はじめに

deviseでログイン機能を作成するときに名前とパスワードでログイン機能を作成したい方向けに記事を書きます。
基本的にコピペのみで完成します。
コードを理解してください。

環境

  • macOS mojave
  • rbenv 1.1.1
  • ruby 2.5.3p105
  • Rails 5.2.3

実装

email, passwordで新規登録、ログインする機能の作成

$ rails new devise_name
$ cd devise_name
$ rails g controller home top after_login
config/routes.rb
  Rails.application.routes.draw do
    root 'home#top'
    get 'home/after_login'
  end
Gemfile
  ...追記
  gem 'devise'
$ bundle
$ rails g devise:install
$ rails g devise User
$ rails db:migrate
app/views/home/top.html.erb
  <%= link_to '新規登録', new_user_registration_path %>
  <%= link_to 'ログイン', new_user_session_path %>
app/controllers/application_controller.rb
  class ApplicationController < ActionController::Base

    def after_sign_in_path_for(resource)
      home_after_login_path
    end
  end
app/views/home/after_login.html.erb
  <%= link_to "ログアウト", destroy_user_session_path, method: :delete %>

name, email, passwordで新規登録、name, passwordでログインする機能の作成

  1. nameカラムの作成 & emailのバリデーション系を全て外す
$ rails g migration AddNameToUsers name:string
$ rails g migration ChangeColumnToUsers
$ rails g migration remove_index_email_from_users
db/migrate/日時_change_column_to_users.rb
  class ChangeColumnToUsers < ActiveRecord::Migration[5.2]
    # 変更内容
    def up
      change_column :users, :email, :string, null: true, default: ""
    end

    # 変更前の状態
    def down
      change_column :users, :email, :string, null: false, default: ""
    end
  end
db/migrate/日時_remove_index_email_from_users.rb
  class RemoveIndexEmailFromUsers < ActiveRecord::Migration[5.2]
    def change
      remove_index :users, column: :email, unique: true
    end
  end
$ rails db:migrate
config/initializers/devise.rb
  ...編集
  config.authentication_keys = [:name]
app/models/user.rb
  ...追記
  def email_required?
    false
  end
  def email_changed?
    false
  end
  1. 新規登録フォーム, ログインフォームの編集
$ rails g devise:views
app/views/devise/registrations/new.html.erb
  ...追記
  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name, autofocus: true, autocomplete: "name" %>
  </div>
app/views/devise/sessions/new.html.erb
  ...編集
  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name, autofocus: true, autocomplete: "name" %>
  </div>
  1. パラメータの許可
app/controllers/application_controller.rb
  class ApplicationController < ActionController::Base
    before_action :configure_permitted_parameters, if: :devise_controller?

    def after_sign_in_path_for(resource)
      home_after_login_path
    end

    protected

    def configure_permitted_parameters
      devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :email])
      devise_parameter_sanitizer.permit(:sign_in, keys: [:name])
    end
  end

以上。

完成コード

devise_name

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

[Ruby on Rails] devise name(名前)でログイン

はじめに

deviseでログイン機能を作成するときに名前とパスワードでログイン機能を作成したい方向けに記事を書きます。
基本的にコピペのみで完成します。
コードを理解してください。

環境

  • macOS mojave
  • rbenv 1.1.1
  • ruby 2.5.3
  • Rails 5.2.3

実装

email, passwordで新規登録、ログインする機能の作成

$ rails new devise_name
$ cd devise_name
$ rails g controller home top after_login
config/routes.rb
  Rails.application.routes.draw do
    root 'home#top'
    get 'home/after_login'
  end
Gemfile
  ...追記
  gem 'devise'
$ bundle
$ rails g devise:install
$ rails g devise User
$ rails db:migrate
app/views/home/top.html.erb
  <%= link_to '新規登録', new_user_registration_path %>
  <%= link_to 'ログイン', new_user_session_path %>
app/controllers/application_controller.rb
  class ApplicationController < ActionController::Base

    def after_sign_in_path_for(resource)
      home_after_login_path
    end
  end
app/views/home/after_login.html.erb
  <%= link_to "ログアウト", destroy_user_session_path, method: :delete %>

name, email, passwordで新規登録、name, passwordでログインする機能の作成

  1. nameカラムの作成 & emailのバリデーション系を全て外す
$ rails g migration AddNameToUsers name:string
$ rails g migration ChangeColumnToUsers
$ rails g migration remove_index_email_from_users
db/migrate/日時_change_column_to_users.rb
  class ChangeColumnToUsers < ActiveRecord::Migration[5.2]
    # 変更内容
    def up
      change_column :users, :email, :string, null: true, default: ""
    end

    # 変更前の状態
    def down
      change_column :users, :email, :string, null: false, default: ""
    end
  end
db/migrate/日時_remove_index_email_from_users.rb
  class RemoveIndexEmailFromUsers < ActiveRecord::Migration[5.2]
    def change
      remove_index :users, column: :email, unique: true
    end
  end
$ rails db:migrate
config/initializers/devise.rb
  ...編集
  config.authentication_keys = [:name]
app/models/user.rb
  ...追記
  def email_required?
    false
  end
  def email_changed?
    false
  end
  1. 新規登録フォーム, ログインフォームの編集
$ rails g devise:views
app/views/devise/registrations/new.html.erb
  ...追記
  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name, autofocus: true, autocomplete: "name" %>
  </div>
app/views/devise/sessions/new.html.erb
  ...編集
  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name, autofocus: true, autocomplete: "name" %>
  </div>
  1. パラメータの許可
app/controllers/application_controller.rb
  class ApplicationController < ActionController::Base
    before_action :configure_permitted_parameters, if: :devise_controller?

    def after_sign_in_path_for(resource)
      home_after_login_path
    end

    protected

    def configure_permitted_parameters
      devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :email])
      devise_parameter_sanitizer.permit(:sign_in, keys: [:name])
    end
  end

以上。

完成コード

devise_name

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

rails aborted! StandardError: An error has occurred, this and all later migrations canceled:

初心者がrails tutorialでscaffoldでUserモデルを生成後、rails db:migrateを入力したときに遭遇したエラー処理について共有します。

mac-no-MacBookPro:toy_app mac$ ./qs rails db:migrate
Starting toy_app_db_1 ... done
== 20190413154520 CreateUsers: migrating ======================================
-- create_table(:users)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::DuplicateTable: ERROR:  relation "users" already exists
: CREATE TABLE "users" ("id" bigserial primary key, "name" character varying, "email" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)

migrateした後にusers tableが既に存在すると表示されました。
そこで

$ rails db:migrate:reset
$ rails db:migrate

resetのコード入力後、再度migrateを試みるも状況は変わらず。

最終的には下記のようにエディタから直接いじり、解決できました。DBのmigrateファイルの中の今回DBに反映させたかった部分を一度コメントアウト。

class CreateMicroposts < ActiveRecord::Migration[5.2]
  def change
    #create_table :microposts do |t|
      #t.text :content
      #t.integer :user_id

      #t.timestamps
    #end
  end
end

その後

$ rails db:migrate

そして、この後はコメントアウトした「#」の文字を消します。

class CreateMicroposts < ActiveRecord::Migration[5.2]
  def change
    create_table :microposts do |t|
      t.text :content
      t.integer :user_id

      t.timestamps
    end
  end
end

そして最後に以下のコードを打ち込み、解決しました。

$ rails db:migrate:down VERSION= <該当のmigrateファイル名>
$ rails db:migrate
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

「heroku run」で発生するETIMEDOUTの原因と解決方法について

Macのローカル環境でRailsチュートリアルを進めていると,Herokuでマイグレーションが失敗してしまい,次のエラーが発生してしまいました。

〔ターミナル〕
 $ heroku run rails db:migrate
  ▸ETIMEDOUT: connect ETIMEDOUT 50.19.103.36:5000

〔Herokuログ抜粋〕
 Error R13 (Attach error) -> Failed to attach to process

 解決方法は「heroku run:detached」を使用することであり,原因も「5000番ポートが使えない」ということであることが,調べると簡単に出てくると思います。

 ただ,「何故使えないのか」という背景が日本語で中々見つからず,このコマンドを使用することの不安感の高まりから,英語に向き合って調べたら安心を得るに至りましたので,同じ不安を抱えている方の参考になれば幸いです。

<原因>

 初めに「heroku run」の仕組みは,クライアントの5000番ポートでHerokuに接続することにより,クライアント側のコンソールに対してコマンドの入出力を実行可能にするものである。

 しかし,クライアント側において,ファイアウォール等のローカルネットワークに原因があり,Herokuからクライアントのコンソールに接続できない場合は,当該エラーが発生する。

<解決方法>

 「heroku run:detached」を使用することにより,コマンドがバックグラウンドで実行されることから,Herokuからの標準出力を受け取らないことで。5000番ポートに接続される必要がなくなるため,本問題が解決される。

 ただし,クライアント側のコンソールに実行結果が出力されなくなることから,正常に実行されたか表示されないため,「heroku logs」によりログ情報を確認する必要がある。

 〔参考入力結果〕
 $ heroku run:detached rails db:migrate
  >Running rails db:migrate on ⬢ [Heroku登録のアプリ名]... done, run.5930 (Free)
  >Run heroku logs --app [Heroku登録のアプリ名] --dyno run.5930 to view the output.
 $ heroku logs --app [Heroku登録のアプリ名] --dyno run.5930
  >・
  >・ #「heroku run:detached rails db:migrate」実行結果のログが表示される
  >・

<結論>

 「run:detached」を使用しても,アプリの本番環境等に影響は無いでしょう。
 注意事項として,ローカルのコンソール上で実行結果が出力されないことにより,失敗時にエラーを見落とす可能性が残りますので,使用後は必ずHerokuのログで実行結果を確認しましょう。

 ただ,この解決方法では,根本の原因を解決しないことになり「heroku logs」の追加作業が発生し,解決するには「5000番ポート」の解放か,ファイアウォールの設定か,又はHeroku側の問題なのか…次の原因のための追加調査をする必要があります。
 しかし,追加作業と追加調査の作業労力を比較すると,私の現在の知識では「run:detached」を使用する方が費用対効果が高いため,ここで調査を終了します。
 今後,技術知識が増えたら適宜更新したいと思います。

※追伸
 私の英語力及び技術知識不足による言葉の誤用の可能性も考えられますので,記載内容に誤りがありましたら,ご指摘いただけると大変嬉しいです。

<参考情報>

○失敗したログ情報

〔コンソールの実行結果〕
  $ heroku run rails db:migrate
   ▸ETIMEDOUT: connect ETIMEDOUT 50.19.103.36:5000
  $ heroku run bash
   ▸ETIMEDOUT: connect ETIMEDOUT 50.19.103.36:5000
  $ heroku run console
   ▸ETIMEDOUT: connect ETIMEDOUT 50.19.103.36:5000
〔Herokuログ(コマンドに対応したログ情報に加工)〕
  $ heroku run rails db:migrate
    : Awaiting client
    : State changed from starting to up
    : State changed from up to complete
    : Error R13 (Attach error) -> Failed to attach to process
    : Process exited with status 128

  $ heroku run bash
    : Awaiting client
    : State changed from starting to up
    : State changed from up to complete
    : Error R13 (Attach error) -> Failed to attach to process
    : Process exited with status 128

  $ heroku run console
    : State changed from starting to up
    : Awaiting client
    : State changed from up to complete
    : Error R13 (Attach error) -> Failed to attach to process
    : Process exited with status 128

○参考サイト

・Heroku公式サイト1:R13 - Attach error

 「heroku run」で開始されたDynoが,呼び出し側のクライアントに接続できなかった。

・Heroku公式サイト2:Timeout awaiting process

 「heroku run」は5000番ポートで接続するが,ローカルネットワーク等の理由で接続できない場合は,エラーが発生する。
 telnetを使用して5000番ポートで接続することにより,Herokuへの接続をテストできるが,出力が得られない場合,クライアント側でHerokuへのアクセスをブロックしている。
 この問題を解決するには,IT部門,ISP,又はファイアウォールの製造元に連絡することをお勧めする。

・Heroku公式サイト3:Running tasks in background

 「heroku run:detached」を使用することによりバックグラウンドでDynoを実行可能である。 「heroku run」とは異なり,これらのdynosはクライアント側に出力する代わりにHeroku側のログに出力を送る。これらのコマンドからの出力を表示するには,「heroku logs」を使用する必要がある。

・Stack Overflow:Heroku rake db:migrate results in Error R13 (Attach error) -> Failed to attach to process

※内容は,概ね公式サイト通りです。

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

RailsプロジェクトへのVue.js導入

Rails × Vueのセットアップ

導入方法は以下の4つが考えられそうだが今回は1.で導入

  1. デフォルトのRailsプロジェクトの中にVue.jsを導入
  2. APIモードのRailsプロジェクトの中にVue.jsを導入
  3. RailsコンテナとVueのコンテナに分けてコンテナ同士で接続
  4. Rails用サーバーとVue用のサーバーでそれぞれ構築して、エンドポイントで接続
Gemfile
gem "webpacker"
# gemのインストール
bundle install
# webpackerインストール
bin/rails webpacker:install
# コンパイル
bin/webpack
# vueインストール
bin/rails webpacker:install:vue
# Top作成
rails g controller Home index --no-assets --no-helper --no-test-framework
# vue読み込み
sed -ie '10i \    <%= javascript_pack_tag "hello_vue" %>' app/views/layouts/application.html.erb

雑感

何も開発していないのに最初から色々1つのプロジェクトにたくさん入っちゃっている感

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

Rails6 のちょい足しな新機能を試す3(rails server -u編)

はじめに

Rails 6 に追加されそうな新機能を試す第3段。 rails server-u オプション機能です。
記載時点では、Rails は 6.0.0.beta3 です。 gem install rails --prerelease でインストールできます。

$  rails --version
Rails 6.0.0.beta3u``

単純なCRUD機能をscaffold で作る

新機能を試すために、scaffold で単純なCRUD機能を作ってみます。

$ rails new sandbox_6_0_0b3
$ cd sandbox_6_0_0b3
$ rails g scaffold User name

従来の機能

rails server のオプションを調べてみます。

$ rails s --help
Usage:
  rails server [puma, thin etc] [options]

Options:
  -p, [--port=port]                        # Runs Rails on the specified port - defaults to 3000.
  -b, [--binding=IP]                       # Binds Rails to the specified IP - defaults to 'localhost' in development and '0.0.0.0' in other environments'.
  -c, [--config=file]                      # Uses a custom rackup configuration.
                                           # Default: config.ru
  -d, [--daemon], [--no-daemon]            # Runs server as a Daemon.
  -e, [--environment=name]                 # Specifies the environment to run this server under (development/test/production).
  -P, [--pid=PID]                          # Specifies the PID file.
                                           # Default: tmp/pids/server.pid
  -C, [--dev-caching], [--no-dev-caching]  # Specifies whether to perform caching in development.
      [--early-hints], [--no-early-hints]  # Enables HTTP/2 early hints.

-u オプションはありません。

新機能

Rails 6.0.0beta3 で試してみます。

$ rails s --help
Usage:
  rails server [thin/puma/webrick] [options]

Options:
  -p, [--port=port]                            # Runs Rails on the specified port - defaults to 3000.
  -b, [--binding=IP]                           # Binds Rails to the specified IP - defaults to 'localhost' in development and '0.0.0.0' in other environments'.
  -c, [--config=file]                          # Uses a custom rackup configuration.
                                               # Default: config.ru
  -d, [--daemon], [--no-daemon]                # Runs server as a Daemon.
  -e, [--environment=name]                     # Specifies the environment to run this server under (development/test/production).
  -u, [--using=name]                           # Specifies the Rack server used to run the application (thin/puma/webrick).
  -P, [--pid=PID]                              # Specifies the PID file.
                                               # Default: tmp/pids/server.pid
  -C, [--dev-caching], [--no-dev-caching]      # Specifies whether to perform caching in development.
      [--early-hints], [--no-early-hints]      # Enables HTTP/2 early hints.
      [--log-to-stdout], [--no-log-to-stdout]  # Whether to log to stdout. Enabled by default in development when not daemonized.

-u オプションで rack サーバーを指定するようになってます。

では、試してみましょう。

$ rails s -u puma
=> Booting Puma
=> Rails 6.0.0.beta3 application starting in development
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 3.12.1 (ruby 2.6.2-p47), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://localhost:3000
Use Ctrl-C to stop

webrickも試してみます。

$ rails s -u webrick
=> Booting WEBrick
=> Rails 6.0.0.beta3 application starting in development http://localhost:3000
=> Run `rails server --help` for more startup options
[2019-04-15 10:47:39] INFO  WEBrick 1.4.2
[2019-04-15 10:47:39] INFO  ruby 2.6.2 (2019-03-13) [x86_64-linux-musl]
[2019-04-15 10:47:39] INFO  WEBrick::HTTPServer#start: pid=977 port=3000

せっかくなので、 thinfalcon も試してみます。 Gemfile に thinfalcon を追加します。

Gemfile
gem 'thin'
gem 'falcon'

bundle install を実行した後、 thin を試してみます。

$ rails s -u thin
=> Booting Thin
=> Rails 6.0.0.beta3 application starting in development http://localhost:3000
=> Run `rails server --help` for more startup options
Thin web server (v1.7.2 codename Bachmanity)
Maximum connections set to 1024
Listening on localhost:3000, CTRL+C to stop

最後は falcon です。

$ rails s -u falcon -b 0.0.0.0
=> Booting Falcon
=> Rails 6.0.0.beta3 application starting in development http://0.0.0.0:3000
=> Run `rails server --help` for more startup options

falcon-b オプションを指定しないとエラーになりました。 falcon もそのまま使えるとわかったのは収穫でした。

参考情報

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

【Rails】オラ自作のブックマークシェアWebアプリで『作業が捗るおやつ・ドリンク集』を紹介すっぞ!

オッス(Z戦士)

突然ですが、作業中の"おやつ"と"飲み物"って生きてく上での酸素と同じくらい大切だと思うんですよね。


(おやつを食べると思わず)笑っちゃうんすよね。

ぼくは大量のコードと長時間向き合ってもビクともしない超(スーパー)エンジニア人ではないので、
作業中は仙豆に相当する"おやつ"と"飲み物"で都度回復しないと、

「hassoubeat(ぼく)は置いてきた...ハッキリ言ってこれからの業務にはついていけない...」

tyaozu.gif
餃子かわいそう。

といった具合に、天さん(上司)に見捨てられること請け合いです。
そんなぼくをギリギリ戦いに参加できるヤムチャレベルまで引き上げてくれるドーピングアイテム。

それが、作業中の"おやつ"と"飲み物"なのです。

今回はそんなぼくが愛好する"おやつ"、"飲み物"を...

オラが作ったRailsのWebアプリで『作業が捗るおやつ・ドリンク集』をいっちょ紹介してみっか!!!(唐突)

作業が捗るおやつ・ドリンク集 by hassoubeat LinkS


赤枠の箇所をクリック・タッチしてもらえればブックマークに対して一言コメントが読めるゾ

個人的に"きかんしゃトーマスとなかまたちチューイングキャンディ」と「マテ茶」は実力はあるのに、あまり知られていないのが残念で仕方ないです。
もし興味を持っていただけたら、リンク先からポチってお試しいただけると嬉しいです。






...。
Webアプリ側にコメントを書いているので当たり前なのですが、おやつに関して書くことがなくなってしまいました。

このまま終わるのも寂しいという皆様のためにぃ(ねっとり)


ここから先は今回開発したWebアプリの話でもしようかと思います。


(おやつの話以外)興味ないね(魔晄中毒者)という方は、
オススメの"おやつ"と"飲み物"をコメントに書いてからブラウザバックしてもらえたら嬉しいゾ

cloud.jpeg
FF7リメイクはいつ...?

自作Webアプリの紹介

今回開発したWebアプリ『LinkS(リンクス)』の紹介にイクゾー!

LinkS_login.png
安直なネーミング恥ずかしくないのかよ

そもそもこのアプリはなんなの?

コメントを付けたブックマーク集をワンクリックで公開してSNSにも簡単に共有できるブックマークシェアWebアプリです。

yaruo2.png

実際にシェアするまでの流れを見てもらいましょう。

1.フォルダー作成
LinkS_create_folder.png
ブックマークの公開・共有はフォルダー単位で行われるため、まずフォルダーを。
公開に設定しない限り、自分だけのブックマーク集としても利用できます。

2.ブックマーク登録
LinkS_create_link.png
さっき作ったフォルダーにブックマークを登録します。Just Monika.

3.フォルダー公開
LinkS_folder_edit.png
フォルダーの公開設定を公開に変更することで、ログインしている本人以外にもURLを叩けばそのフォルダーが見れるように。

4.シェア
LinkS_share_line.png
LinkS_share_twitter.png
おすすめゲームのPV集 by hassoubeat LinkS
URLを直接シェアする以外にも、LinkSからSNSに直接シェアすることもできます。

ちなみにスマホでもちゃんと使えます

LinkS_sm_login.png LinkS_sm_sidebar.png LinkS_sm_TOP.png

...。
機能がシンプル過ぎるので、話すことがなくなりました。
一応申し訳程度にいいね機能、管理機能とかも実装してます。

現在β版ですが、もし気になる人がいたら捨てアドでアカウント登録して使ってみてくれたら嬉しいゾ。

なんで作ろうと思い立ったワケ?

理由は2つありますねぇ!

1.RubyOnRailsのポートフォリオを作りたかった
2.弟がHTMLの勉強を始めるにあたって何をしたらいいか聞いてきた

1.RubyOnRailsのポートフォリオを作りたかった

Webアプリケーション開発のフレームワークとしての知名度が高いRubyOnRailsの学習の成果として、
何かポートフォリオ作りてぇな...。と考えていたのですが、なかなかピンとくる題材がなく...
(あんまり手の混んだやつは作るのがめんでぇぞ!の意)

2.弟がHTMLの勉強を始めるにあたって何をしたらいいか聞いてきた

ある日弟が「HTMLの勉強をしたいのだが、まず何から手を付けたらよいのか?」と聞いてきました。
入門者向けのテキスト読んでもいいし、活字が苦手なやつだしドットインストールみたいなサイトで動画で動きを見ながらやったほうがいいかな...。
みたいなことを考えてHTML初学者が手を付けるべきサイトやテキストのAmazonのリンクに補足のコメントを付けてまとめていました。

こんな感じの一言コメントを付けたリンク集を簡単に共有できるWebアプリとかねーかな...

amro.jpeg
この感覚...!残業か!!!

そんな感じのコメント付きのリンク集を簡単にシェアできるWebアプリ...。
Railsのポートフォリオの題材としてちょうどいい...!

という渡りに船な出来事があって、LinkSは誕生しました。(ガイドのお姉さん風)

これいる?

Q.(ブラウザがブックマークをクラウド管理してくれるこのご時世に)これいる?

A.
yaruo.jpg

文字制限があるTwitterで自分のオススメ〇〇集!みたいなのを共有したい人に需要があるかもしれない(希望的観測)

Q.(似たようなサービスがあるのに)これいる?

A.
(作ったのは)おれじゃない
(超エンジニア人の)あいつらがつくった
(おれはそんなサービス)しらない
(実装が)すんだこと



既に似たようなサービスがあることを気にしていたらポートフォリオなんて作れないんだよぉぉぉぉ!


vegita.png
開発中しょうもないミスで一時間くらい詰まっていた時、心の中で叫ぶセリフ第一位。

使ったフレームワーク

RubyOnRails

説明不要のWebアプリケーションフレームワーク。
いずれRubyの仕事もしたいなーってことで勉強を始めたけど、ほんとに生産性上がってMAX大草原。
あんまりによかったのでRailsを参考にしているらしいPHPのLaravelも近々触ってみようかと思った(小並感)

Haml


テンプレートエンジン。
Haml か Slimがよく採用されているらしいけど、なんとなくHamlを採用。
はじめは「書きにくいな...全部ERBで書いた後にerb2hamlでhamlに変換してやろうか...くそったれぇ...!(本末転倒)」なんてその気になっていたお前の姿はお笑いだったぜ。
慣れれば慣れるほどコードの見通しが良くなって、結果的に生産性向上に大きく貢献してくれました。

Bootstrap

説明不要のCSSフレームワーク。
デザイン面がクソザコナメクジ過ぎていっつもこればっかり使っているので、今度違うWebアプリ作る時は頼らないで作りたい(猛省)

jQuery

い つ も の (JavaScriptフレームワーク)
まだオワコンフレームワーク使ってんのかよ?」と思った貴方。

いきなりvue.jsかよ。モダンッパリらしいな。

世界最高フレームワークjQueryを侮辱した罪...軽くねーぜ?



ごめんなさい。慣れてるからっていっつもなんとなくで使っちゃうんです...。
jQueryからvue.jsのステップアップ記事とか見てると、凄い良さそうなんで今度使います...。
(すぐ使うとは言ってない)

改修、機能追加したい部分

1. ブックマークのURL入力時に自動でページタイトルをスクレイピングして、タイトルの入力の手間軽減
クロスドメインでのスクレイピングを跨げるライブラリが利用しているYahoo!のYQLが完全に死んだらしく、
どうにかして実現できないかなと模索中。

2. GoogleChromeの拡張機能で、ブラウザのブックマークからのインポート処理機能
そもそも普段使ってるブラウザのブックマークからインポートできたら一番ラクだよねってこと。
GoogleChrome拡張機能開発の勉強をやってみたいので、割とモチベ高し。

3. SPA化
RailsをAPIモードにして、ページ表示はクライアントからAPIを叩くだけの構成を実装してみたい。
このアプリでは作り直すのがめんどくさいので多分やらない(屑)

(ポートフォリオ作成を)完走した感想

まずRubyOnRailsの生産性の高さに驚きました。
使わなくても分かるシンプル構成のシステムなのもあり、ほとんどサーバ側のコードは書いてないです。
全体工数の7割はクライアント側のUI作成に時間が取られてます。

...。
これもうRubyOnRailsのポートフォリオとして成立してるかわかんねぇな(屑)

でもやっぱり設計、製造、テスト、リリース : 俺は気軽に色々やれて楽しいですね。
実務だとなかなかそうはいかないので、みんなも気軽にポートフォリオ作成して...見せ合いっこしよっ!!!
俺もやったんだからさ(同調圧力)

あっ(唐突)、作業中に良さげな"おやつ"と"飲み物"があったら、コメント欄で教えてください。
LinkSで教えてくれたらもっと嬉しいです

余談:他のおすすめリンク集

せっかく作ったアプリなので、他のぼくセレクトも公開します。

RubyOnRailsの学習に役立ったリンク集 by hassoubeat LinkS

RubyOnRailsの学習を始めるにあたって参考になったリンク集です。

おすすめゲームのPV集 by hassoubeat LinkS

ハードウェア問わずおすすめのゲーム集です。

落ち込んでいる時に元気が出る動画集 by hassoubeat LinkS

落ち込んでいる時に見ると元気を貰える動画集です。
※ ぼくセレクトなので、効果の保証はできません

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

【Rails】【ポートフォリオ】自作のブックマークシェアWebアプリで『作業が捗るおやつ・ドリンク集』を紹介します

オッス(Z戦士)

突然ですが、作業中の"おやつ"と"飲み物"って生きてく上での酸素と同じくらい大切だと思うんですよね。


(おやつを食べると思わず)笑っちゃうんすよね。

ぼくは大量のコードと長時間向き合ってもビクともしない超(スーパー)エンジニア人ではないので、
作業中は仙豆に相当する"おやつ"と"飲み物"で都度回復しないと、

「hassoubeat(ぼく)は置いてきた...ハッキリ言ってこれからの業務にはついていけない...」

tyaozu.gif
餃子かわいそう。

といった具合に、天さん(上司)に見捨てられること請け合いです。
そんなぼくをギリギリ戦いに参加できるヤムチャレベルまで引き上げてくれるドーピングアイテム。

それが、作業中の"おやつ"と"飲み物"なのです。

今回はそんなぼくが愛好する"おやつ"、"飲み物"を...

オラが作ったRailsのWebアプリで『作業が捗るおやつ・ドリンク集』をいっちょ紹介してみっか!!!(唐突)

作業が捗るおやつ・ドリンク集 by hassoubeat LinkS


赤枠の箇所をクリック・タッチしてもらえればブックマークに対して一言コメントが読めるゾ

個人的に"きかんしゃトーマスとなかまたちチューイングキャンディ」と「マテ茶」は実力はあるのに、あまり知られていないのが残念で仕方ないです。
もし興味を持っていただけたら、リンク先からポチってお試しいただけると嬉しいです。






...。
Webアプリ側にコメントを書いているので当たり前なのですが、おやつに関して書くことがなくなってしまいました。

このまま終わるのも寂しいという皆様のためにぃ(ねっとり)


ここから先は今回開発したWebアプリの話でもしようかと思います。


(おやつの話以外)興味ないね(魔晄中毒者)という方は、
オススメの"おやつ"と"飲み物"をコメントに書いてからブラウザバックしてもらえたら嬉しいゾ

cloud.jpeg
FF7リメイクはいつ...?

自作Webアプリの紹介

今回開発したWebアプリ『LinkS(リンクス)』の紹介にイクゾー!

LinkS_login.png
安直なネーミング恥ずかしくないのかよ

そもそもこのアプリはなんなの?

コメントを付けたブックマーク集をワンクリックで公開してSNSにも簡単に共有できるブックマークシェアWebアプリです。

yaruo2.png

実際にシェアするまでの流れを見てもらいましょう。

1.フォルダー作成
LinkS_create_folder.png
ブックマークの公開・共有はフォルダー単位で行われるため、まずフォルダーを。
公開に設定しない限り、自分だけのブックマーク集としても利用できます。

2.ブックマーク登録
LinkS_create_link.png
さっき作ったフォルダーにブックマークを登録します。Just Monika.

3.フォルダー公開
LinkS_folder_edit.png
フォルダーの公開設定を公開に変更することで、ログインしている本人以外にもURLを叩けばそのフォルダーが見れるように。

4.シェア
LinkS_share_line.png
LinkS_share_twitter.png
おすすめゲームのPV集 by hassoubeat LinkS
URLを直接シェアする以外にも、LinkSからSNSに直接シェアすることもできます。

ちなみにスマホでもちゃんと使えます

LinkS_sm_login.png LinkS_sm_sidebar.png LinkS_sm_TOP.png

...。
機能がシンプル過ぎるので、話すことがなくなりました。
一応申し訳程度にいいね機能、管理機能とかも実装してます。

現在β版ですが、もし気になる人がいたら捨てアドでアカウント登録して使ってみてくれたら嬉しいゾ。

なんで作ろうと思い立ったワケ?

理由は2つありますねぇ!

1.RubyOnRailsのポートフォリオを作りたかった
2.弟がHTMLの勉強を始めるにあたって何をしたらいいか聞いてきた

1.RubyOnRailsのポートフォリオを作りたかった

Webアプリケーション開発のフレームワークとしての知名度が高いRubyOnRailsの学習の成果として、
何かポートフォリオ作りてぇな...。と考えていたのですが、なかなかピンとくる題材がなく...
(あんまり手の混んだやつは作るのがめんでぇぞ!の意)

2.弟がHTMLの勉強を始めるにあたって何をしたらいいか聞いてきた

ある日弟が「HTMLの勉強をしたいのだが、まず何から手を付けたらよいのか?」と聞いてきました。
入門者向けのテキスト読んでもいいし、活字が苦手なやつだしドットインストールみたいなサイトで動画で動きを見ながらやったほうがいいかな...。
みたいなことを考えてHTML初学者が手を付けるべきサイトやテキストのAmazonのリンクに補足のコメントを付けてまとめていました。

こんな感じの一言コメントを付けたリンク集を簡単に共有できるWebアプリとかねーかな...

amro.jpeg
この感覚...!残業か!!!

そんな感じのコメント付きのリンク集を簡単にシェアできるWebアプリ...。
Railsのポートフォリオの題材としてちょうどいい...!

という渡りに船な出来事があって、LinkSは誕生しました。(ガイドのお姉さん風)

これいる?

Q.(ブラウザがブックマークをクラウド管理してくれるこのご時世に)これいる?

A.
yaruo.jpg

文字制限があるTwitterで自分のオススメ〇〇集!みたいなのを共有したい人に需要があるかもしれない(希望的観測)

Q.(似たようなサービスがあるのに)これいる?

A.
(作ったのは)おれじゃない
(超エンジニア人の)あいつらがつくった
(おれはそんなサービス)しらない
(実装が)すんだこと



既に似たようなサービスがあることを気にしていたらポートフォリオなんて作れないんだよぉぉぉぉ!


vegita.png
開発中しょうもないミスで一時間くらい詰まっていた時、心の中で叫ぶセリフ第一位。

使ったフレームワーク

RubyOnRails

説明不要のWebアプリケーションフレームワーク。
いずれRubyの仕事もしたいなーってことで勉強を始めたけど、ほんとに生産性上がってMAX大草原。
あんまりによかったのでRailsを参考にしているらしいPHPのLaravelも近々触ってみようかと思った(小並感)

Haml


テンプレートエンジン。
Haml か Slimがよく採用されているらしいけど、なんとなくHamlを採用。
はじめは「書きにくいな...全部ERBで書いた後にerb2hamlでhamlに変換してやろうか...くそったれぇ...!(本末転倒)」なんてその気になっていたお前の姿はお笑いだったぜ。
慣れれば慣れるほどコードの見通しが良くなって、結果的に生産性向上に大きく貢献してくれました。

Bootstrap

説明不要のCSSフレームワーク。
デザイン面がクソザコナメクジ過ぎていっつもこればっかり使っているので、今度違うWebアプリ作る時は頼らないで作りたい(猛省)

jQuery

い つ も の (JavaScriptフレームワーク)
まだオワコンフレームワーク使ってんのかよ?」と思った貴方。

いきなりvue.jsかよ。モダンッパリらしいな。

世界最高フレームワークjQueryを侮辱した罪...軽くねーぜ?



ごめんなさい。慣れてるからっていっつもなんとなくで使っちゃうんです...。
jQueryからvue.jsのステップアップ記事とか見てると、凄い良さそうなんで今度使います...。
(すぐ使うとは言ってない)

改修、機能追加したい部分

1. ブックマークのURL入力時に自動でページタイトルをスクレイピングして、タイトルの入力の手間軽減
クロスドメインでのスクレイピングを跨げるライブラリが利用しているYahoo!のYQLが完全に死んだらしく、
どうにかして実現できないかなと模索中。

2. GoogleChromeの拡張機能で、ブラウザのブックマークからのインポート処理機能
そもそも普段使ってるブラウザのブックマークからインポートできたら一番ラクだよねってこと。
GoogleChrome拡張機能開発の勉強をやってみたいので、割とモチベ高し。

3. SPA化
RailsをAPIモードにして、ページ表示はクライアントからAPIを叩くだけの構成を実装してみたい。
このアプリでは作り直すのがめんどくさいので多分やらない(屑)

(ポートフォリオ作成を)完走した感想

まずRubyOnRailsの生産性の高さに驚きました。
使わなくても分かるシンプル構成のシステムなのもあり、ほとんどサーバ側のコードは書いてないです。
全体工数の7割はクライアント側のUI作成に時間が取られてます。

...。
これもうRubyOnRailsのポートフォリオとして成立してるかわかんねぇな(屑)

でもやっぱり設計、製造、テスト、リリース : 俺は気軽に色々やれて楽しいですね。
実務だとなかなかそうはいかないので、みんなも気軽にポートフォリオ作成して...見せ合いっこしよっ!!!
俺もやったんだからさ(同調圧力)

あっ(唐突)、作業中に良さげな"おやつ"と"飲み物"があったら、コメント欄で教えてください。
LinkSで教えてくれたらもっと嬉しいです

余談:他のおすすめリンク集

せっかく作ったアプリなので、他のぼくセレクトも公開します。

RubyOnRailsの学習に役立ったリンク集 by hassoubeat LinkS

RubyOnRailsの学習を始めるにあたって参考になったリンク集です。

おすすめゲームのPV集 by hassoubeat LinkS

ハードウェア問わずおすすめのゲーム集です。

落ち込んでいる時に元気が出る動画集 by hassoubeat LinkS

落ち込んでいる時に見ると元気を貰える動画集です。
※ ぼくセレクトなので、効果の保証はできません

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

【Rails】 flash時にメッセージにリンクを埋め込む

flashで通知させるときにどうすれば文字列にリンクを貼るのか悩んだので書きます。

html_safeを使う

html_safeを使えば解決します。

if @user.save
  link = "<a href=#{edit_user_path(:id)}>こちら</a>"
  flash[:success] = "ユーザー登録に成功しました。変更は#{link}でできます。".html_safe
  redirect_to user_path
end

「こちら」がURLになってますね。
html_safeを末尾に記入すれば解決!

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

Railsのエラーが何なのか辿り着くまでの思考プロセス

●●のエラーだなこれ・・・と正しい推測まで到達するために・・・

undefined hogehoge_method

まずこんな感じでRailsサーバーと立ち上げても長いエラーが出るばかりで、画面が出てこない状況になります。
ここからバトルスタートですね。

やりたいこと

エラーがなんなのかを特定する。例えば、DBなのか、リダイレクト関係なのか、ルーティングミスなのかなどのタイポとかと比べて、根の深そうなエラー周りなのかどうかを先ず知りたい

手順

1. こけているメソッドのインスタンスを見てみる
メソッドに問題がない場合、そのさらに先で定義されているかコールされているものがこけているので、そのインスタンスが宣言されているファイルを探しに行きます。

2.ファイルを探す

$ find ./探したいディレクトリ -type f -print | xargs grep '検索文字列'

findコマンドでファイルを特定し、xargsコマンドに渡して検索文字列がヒットしたファイルを弾きだします。
ここでページが多く作成されていたりすると、あちこちで同名インスタンスが呼ばれているので分からなくなりそうですが、表示できていないページがどこに当たるのかと、ファイルの命名規則が合致していれば、探しやすいはずです。ここで、、viewの名前が分かり易いもの、(Restfullに作られていると、このファイル探査がしやすいですね。)

そうやってネストしているメソッドを伝っていくと、最終的に落ちているメソッドがなんなのか理解できる。
後は、そこを修正するだけ。

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

Rails version update 覚書 その3

前回 https://qiita.com/takakuda/items/f7ea279778971b71cd9b

依存関係のあるgemを一通りupdateし終えたらrails自体のupdateをする

rails update

Gemfileを編集する

- gem "rails", "5.1.~"
+ gem "rails", "5.2.~"

--conservative optionを使って依存関係のあるgemのupdateを行わないようにする

bundle update  --conservative rails

その1 https://qiita.com/takakuda/items/895bd6e776e8e7ec08bf
こちらの手順を実行していく。
依存関係のあるgemの更新が終了していればbundle update自体は成功するはず

bundle updateが成功したらちゃんとrailsが起動できるかを確認していく

たぶん起動しないので起動しない原因を調査し、1つずつ修正していく
今回は実際に自分がupdateしたときに発生した修正箇所もろもろ

ArgumentError: Passing string to be evaluated in :if and :unless conditional options is not supported. Pass a symbol for an instance method, or a lambda, proc or block, instead.

:if, :unless を使っている時にstringがサポートされなくなりました

☓ if: 'first_name.blank?'
○ if: proc { |s| s.first_name.blank? }

error messageに書いてある通りに対応すれば大丈夫です

undefined method halt_callback_chains_on_return_false= for ActiveSupport:Module (NoMethodError)

halt_callback_chains_on_return_falseはRails 4との後方互換のためのメソッド。
5.2よりhalt_callback_chains_on_return_falseは削除されたため、config/initializers/new_framework_defaults.rbの中のhalt_callback_chains_on_return_falseの行をコメントアウトすればおっけー。

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

where後に配列に入っている値をハッシュ形式にする方法。(レコード1件のみ時)

whereで値を取得した後は配列に入っています。
下記のコードですが、Entryモデル中の1つのroom_idには送信者、受信者のuser_idがある。
(1つのroom_idにつき最小、最大2名のみ)
したがって自分以外のuser_idを残すためにwhere.notで自分のuser_idを取得しないようにしている。

@room_idには1つのuser_idしかないのがわかっている中で、
each文での取り出しはスマートではない。

コード
    28:   @room_id = Entry.where(room_id: params[:id]).where.not(user_id: current_user.id)
    29:   @room_id.each do |user|
    30:   @reception_user = User.find(user.user_id)
 => 31:   binding.pry
    32:   end
    33:   link "#{@reception_user.name}さんとのチャットルーム", user_room_path

@room_idに入っている値です。

> @room_id
=> [#<Entry:0x00007ff76be33a40
  id: 2,
  user_id: 2,
  room_id: 1,

試したこと

配列からハッシュにするto_hメソッドを見つけて試したが、無理な様子。

@room_id = Entry.where(room_id: params[:id]).where.not(user_id: current_user.id)
@room = @room_id.to_h

エラー内容

wrong element type Entry (expected array)

解決法

レコードが1件しかないのがわかっているので、firstで配列を展開から展開されハッシュ形式で@entryに渡っている。

@room_id = Entry.where(room_id: params[:id]).where.not(user_id: current_user.id).first
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

case文での条件分岐方法

滞在しているページごとにサイドバーに表示させるリストの内容を変更したかったので
if文を使い行っていたが、条件が多くなるに連れて可読性が悪くなってきたため、
case文でコードを書き直したが条件分岐が行われなかった。

if文でviewに書いたコード

- if params[:controller] == 'users' && params[:action] == 'show'

case文を使い書き直したコード

- case params[:controller]
- when 'users' && params[:action] == 'show'

teratailで質問し解決したのでメモ。
https://teratail.com/questions/184492
下記のようにすることでコントローラーのアクションごとに異なるviewの切り替えを実現できた。

- case params.values_at :controller, :action
- when ['rooms', 'show']
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

delayed_job再起動手順

ローカル開発環境でdelayed_jobを利用してメール送信などの実装をしている場合、delayed_jobが起動していないせいでメールが確認できないということがある。
そのような場合はdelayed_jobを再起動してあげる必要がある。

### delayed_jobの再起動
$ bin/delayed_job restart

なお、キューがたくさん溜まっているとdelayed_jobを再起動したタイミングで一気にメールが飛ぶので、全部削除しておくとよい

$ bundle exec rails c

### 現在溜まっているジョブ数の確認
pry(main)> Delayed::Job.count

### キューの削除
pry(main)> Delayed::Job.delete_all
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Payjpに登録したクレジットカードで商品購入を実装する(Rails)

この記事を読む前に

↓前回の投稿内容が実施されていることを前提に記載しています。
Payjpでクレジットカード登録と削除機能を実装する(Rails)

実装する機能と前提条件

Payjp(Pay.jp)から既に顧客IDとカードIDを取得済みでの購入を想定しています。
実装するものとしては下記のとおりです。

  • 自作のカード登録フォーム(前回)
  • カード情報とユーザーの紐づけ(前回)
  • ユーザーとカードの登録と削除(前回)
  • 商品の購入(←今回)

「購入する」ボタンを押して購入!
image.png

バージョン情報

ruby 2.3.1
Rails 5.0.7

前提条件

  • deviseが導入済みでログインができている(current_userを使うため)
  • hamlでの記載(gem 'haml-rails')
  • payjpのアカウントが既に取得できていて、ユーザーとカードの登録が完了している(前回実施)
  • cardテーブルに以下の情報が登録されている(前回実施)
    • user_id → UserテーブルのID
    • customer_id → payjpの顧客ID
    • card_id → payjpのデフォルトカードID

顧客IDとデフォルトカードIDは以下の画面で顧客ごとに確認できます。
もしDBを作成していなかったり可動しなかったりする場合はID直打ちでトライしてみましょう。
顧客詳細確認画面
image.png

1.コントローラーを作成しよう

app/controllers/purchase_controller.rb
class PurchaseController < ApplicationController

  require 'payjp'

  def index
    card = Card.where(user_id: current_user.id).first
    #Cardテーブルは前回記事で作成、テーブルからpayjpの顧客IDを検索
    if card.blank?
      #登録された情報がない場合にカード登録画面に移動
      redirect_to controller: "card", action: "new"
    else
      Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
      #保管した顧客IDでpayjpから情報取得
      customer = Payjp::Customer.retrieve(card.customer_id)
      #保管したカードIDでpayjpから情報取得、カード情報表示のためインスタンス変数に代入
      @default_card_information = customer.cards.retrieve(card.card_id)
    end
  end

  def pay
    card = Card.where(user_id: current_user.id).first
    Payjp.api_key = ENV['PAYJP_PRIVATE_KEY']
    Payjp::Charge.create(
    :amount => 13500, #支払金額を入力(itemテーブル等に紐づけても良い)
    :customer => card.customer_id, #顧客ID
    :currency => 'jpy', #日本円
  )
  redirect_to action: 'done' #完了画面に移動
  end

end

2.購入画面と完了画面を作成しよう

購入画面
app/views/purchase/index.html.haml
%h2 購入を確定しますか?
%p Apple MacBook Pro 13インチ
%p ¥135,000(送料込み)
%br
%h3 支払い方法
- if @default_card_information.blank?
  %br /
- else
  -#以下カード情報を表示
  = "**** **** **** " + @default_card_information.last4 
  - exp_month = @default_card_information.exp_month.to_s
  - exp_year = @default_card_information.exp_year.to_s.slice(2,3)
  = exp_month + " / " + exp_year
%br
= form_tag(action: :pay, method: :post) do
  %button 購入する

image.png
ちなみにexp_monthはカードの期限月、exp_yearは期限年、last4はカードの下4桁を取得します。
https://pay.jp/docs/api/#顧客のカード情報を取得

完了画面
app/views/purchase/done.html.haml
%h2 購入が完了しました!
%p Apple MacBook Pro 13インチ
%p ¥135,000(送料込み)

image.png

3.ルートを設定しよう

config/routes.rb
  #今回設定分
  get 'purchase', to: 'purchase#index'
  post 'purchase/pay', to: 'purchase#pay'
  get 'purchase/done', to: 'purchase#done'

本当に購入されているのだろうか…

実装はこれで完了です!
画面変遷はできてても登録ができているか不安な場合は
売上一覧の画面で確認できます!
image.png

参考

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

Railsの勉強を初めて、基本的な内容をメモ

はじめに

rails tutorialを終えて、整理するためにアウトプットします。
Qiitaに投稿するのも初めてなので、Markdownもよくわかりませんが、練習して見ようと思います。

アプリケーション作成

rails _5.1.6_ new app

1.「5.1.6」はバージョン
2.「app」はアプリ名

Gemfileを修正して「bundle install」を実行し、gemをインストール
(Gemfileの内容は今後理解する必要あり)
エラーになった場合は「bundle update」する必要あり
(エラーのログに記載されている)

ローカル環境にインストールしないようにするためには下記の特殊なフラグを使用する
(HerokuでSQLiteはサポートされていないため、必要になるみたいだがよくわからない)

bundle install --without production

Heroku CLIのインストール(Herokuのコマンドラインインターフェイスを利用可能にする)

$ source <(curl -sL https://cdn.learnenough.com/heroku_install)

正しくインストールされたかは下記コマンドを実行

$ heroku --version

herokuに新しいアプリケーションの実行場所を作成する

$ heroku create

git&heroku コマンド

$ git add -A
$ git commit -m "コミットのメッセージ"
$ git checkout master
$ git merge 「ブランチ名」
$ git push
$ git push heroku
$ rails db:migrate
$ heroku pg:reset DATABASE
$ heroku run rails db:migrate
$ heroku run rails db:seed
$ heroku restart

Rails コマンド

フォルダやファイルの自動生成

home_controller.rbapp/controllersに生成され、このファイルの中身にtopメソッドがある
generateはgに省略が可能

$ rails generate controller home top

config/routes.rb内で「get "URL", to: 'コントローラ名#アクション名'」を記述することで top.html.erbの内容がブラウザで表示可能

get 'home/top', to: 'home#top'

アクションの追加方法

generateは生成するという意味なのでrails g ~ は使えません
ルーティングを追加し、アクションを追加する必要があります。

routes.rbにルーティングの設定

get 'about', to: 'home#about'

home_controller.rbにアクションの追加

def about
end

ビューを追加
app/views/homeabout.html.erbを追加

初期表示の変更

ルートURLを設定

root 'コントローラ名#アクション名'

コード

繰り返し処理

<% オブジェクト.each do |変数| %>

<% end %>

link_toメソッド

リンクをメソッド

<%= link_to "リンクの名前", URLまたはルーティングヘルパー %>

findメソッド

引数にidの値を指定することでそのidのレコードを取得する
Postテーブルの2レコード目を取得

post = Post.find(2)

redirect_toメソッド

更新処理等でページを移動する場合に使用
リダイレクトするときはpathではなくurlを使用する

redirect ヘルパー名_url

DB

データベースの操作

テーブル作成

マイレグレーションファイルを作成

$ rails g model Post content:text

Post・・・テーブル(モデルは単数形)
content:text・・・「カラム名:データ型」

ルーティングの確認方法

1.ターミナル
$ rails routers
2.ブラウザ
ブラウザのアドレスの末尾に/rails/infoと入力

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

仮想マシンの構築からRailsプロジェクト作成まで半自動で実行してくれるスクリプトをつくってみた【MacOS対応】

手軽に作ったり壊したりできるのが仮想環境で開発するメリットのひとつです。

手軽とはいえ、仮想環境の構築からRailsプロジェクトの作成まで行うなると、そこそこの量のコマンドを実行する必要があるのでそれなりに面倒です。

ということで、仮想マシンの構築からRailsプロジェクトの作成までを半自動で実行してくれるシェルスクリプトをつくってみました。

今回つくったスクリプトはドットインストールのローカル開発環境の構築 [macOS編] というレッスン内容を元にしています。ローカル開発環境や仮想環境の概要、仮想環境への接続方法などが分からないという方は、まずこちらのレッスンを受けることをおすすめします。

動作環境

下記の環境で動作を確認しています。ただ、あくまで自分用につくったスクリプトなので必ずしも正しく動作するとは限りません。各コマンドを理解した上で使用してください。

  • MacOS Mojave 10.14.4
  • VirtualBox 5.2.20
  • Vagrant 2.0.3

実行ファイル

以下の3つです。

  • virtual_env_setup.command
  • rails_setup1.sh
  • rails_setup2.sh

GitHubで公開しています。$ git cloneするなどして入手してください。

$ git clone https://github.com/Tatehito/rails-dev-setup.git

何ができるのか

このスクリプトを実行すると、以下の環境が完成します。

  • VirtualBox(vagrant)を使った仮想開発環境
  • CentOS 7.3
  • Ruby(任意のバージョンを指定可)
  • Rails(任意のバージョンを指定可)
  • 任意の名前のRailsプロジェクト(DBはSQLite)

使い方

事前準備

  • VirtualBoxのインストール
  • Vagrantのインストール
  • Cyberduckのインストール
  • ホームディレクトリ配下にworkspaceという名前のディレクトリを作成する

ホームディレクトリ配下のworkspaceディレクトリに仮想環境用のディレクトリを作成するようにしているため、事前にworkspaceディレクトリを作成しておいてください。※workspace以外のディレクトリを指定する方法は後述します。

各種ツールのインストール方法はドットインストールのレッスンがわかりやすいです。ローカル開発環境の構築 [macOS編]

スクリプトを実行する

1.virtual_env_setup.commandをMacOSで実行する

「virtual_env_setup.command」は、仮想環境の構築から起動までを実施します。

MacOS上でダブルクリックで実行します。実行すると、仮想マシン用に作成するディレクトリ名を尋ねられるので、任意の名前を入力してEnterを押してください。

Please Enter Virtual-Environment Directory Name.
$ 作成するディレクトリ名

最後に赤字で下記のようなメッセージが出ますが、問題ありません。

Vagrant was unable to mount VirtualBox shared folders. This is usually
because the filesystem "vboxsf" is not available. This filesystem is
made available via the VirtualBox Guest Additions and kernel module.
(以下略)

処理が完了すると、ホームディレクトリ配下のworkspace/入力したディレクトリ/Vagrantfileが作成されているはずです。なお、この時点で仮想マシンは起動状態になっています。

2.構築された仮想環境にシェルを配置する

CyberduckなどのFTPクライアントソフト使って、「rails_setup1.sh」「rails_setup2.sh」を仮想環境のホームディレクトリにアップロードします。

Cyberduckの使い方はドットインストールのレッスン(ローカル開発環境の構築 [macOS編] )が分かりやすいです。

配置したら、ターミナルからvagrant sshで仮想マシンにログインし、配置したシェルの実行権限を下記コマンドで付与します。

$ chmod 755 *.sh

3.rails_setup1.shを仮想環境で実行する

「rails_setup1.sh」を実行します。「rails_setup1.sh」では、Git、rbenv、ruby-buildのインストールを実施します。

実行したらやることはないので、処理が終わるまで待ちます。

4.rails_setup2.shを仮想環境で実行する

続いて「rails_setup2.sh」を実行します。「rails_setup2.sh」ではRuby、Ruby on Railsのインストール、Railsプロジェクトの作成を実施します。

実行すると、以下のようにRuby、Railsのバージョン、Railsプロジェクト名を入力するよう促されるので、入力します。

Please enter the version of "Ruby" to install.
$ 2.5.5

Please enter the version of "Rails" to install.
$ 5.2.2

Please enter Rails Project Name.
$ sample_project

処理が進んでいくと、SQLiteインストール時に以下のメッセージが表示されて処理が一時停止するので、yを入力して処理を進めます。

総ダウンロード容量: 104 k
インストール容量: 366 k
Is this ok [y/d/N]: 

5.Railsサーバー起動、アクセス

処理がすべて終了すると、以下のメッセージがコンソールに出力されます。

Command to start the Rails server:rails s -b 192.168.33.10
URL:http://192.168.33.10:3000/

このメッセージにある通り、$ rails s -b 192.168.33.10でRailsサーバーを起動し、ブラウザからhttps://192.168.33.10:3000でRailsアプリケーションに接続できたら完了です。

スクリーンショット 2019-04-11 23.59.46.png

スクリプト内容のちょっとした解説

virtual_env_setup.command

virtual_env_setup.command
echo "Please Enter Virtual-Environment Directory Name."
read vspace_name

cd ./workspace
mkdir $vspace_name

# VagrantFileを作成
cd ./${vspace_name}
vagrant init bento/centos-7.3

cd ./workspaceでホームディレクトリ配下のworkspaceディレクトリに移動し、仮想環境用のディレクトリを作成するようにしています。

workspace以外のディレクトリを指定したければ、cd ./workspace で指定している移動先のディレクトリを任意のディレクトリに変更すればOKです。

virtual_env_setup.command
# 仮想マシンを起動
vagrant up

初回起動は時間がかかるので、処理の最後に起動のコマンドを実行するようにしています。スクリプトの実行が終わったら仮想マシンが起動状態になっているので注意してください。

仮想マシンの状態は$ vagrant statusで確認できます。

rails_setup1.sh

rails_setup1.sh
# rbenvのパスを通す
echo '# rbenv' >> ~/.bash_profile
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile

# ログインシェルを再起動し設定を反映
exec $SHELL --login

rails_setup1.shの最後に、ログインシェルの再起動を行っています。これはrbenvのパスの設定を反映させるためです。

rails_setup2.sh

必要なライブラリを順番にインストールし、最後にRailsプロジェクトを作成します。ちなみに、Node.jsをインストールしておかないとRailsサーバー起動時にエラーになります。

rails_setup2.sh
# ExecJSランタイム(Node.js)のインストール
curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash -
sudo yum -y install nodejs

改善したいポイント

前述したように$ rails s -b 192.168.33.10コマンドでRailsサーバーを起動し、http://192.168.33.10:3000/で接続します。

が、本来は$ rails sコマンドで起動、http://localost:3000/で接続できるはずです。(本来と言うか、以前仮想環境つくったときはこれで接続できてました)

今回作成したスクリプトではlocalhostで繋げないようになってしまっているので、その点を改善したいと考えています。

おわりに

自分用につくったため汎用的なスクリプトではないですが、複雑なことをやっているわけではないので理解するのは難しくないと思います。

仮想環境の構築に慣れてきて、いちいち手で作るのが面倒だという方はぜひ参考にしてみてください。
 

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

No route matches [DELETE] "/users/sign_out" エラー(Rails)

はじめに

初学者の学習アウトプット用記事です。
ご指摘訂正アドバイスは是非お願いします。

で、今回のテーマは!!!!!!

エラー!!!!です。

内容としては、deviseでログイン機能を実装してログインはできるのにログアウトするとエラーが起きてしまうということでした。

No route matches [DELETE] "/users/sign_out"

エラー文が

No route matches [DELETE] "/users/sign_out"

なんとなくなんですが、

「DELETEのルーティングされてねぇぞ!!ごらぁああ!!!!」

と言われてる気がしました。

ターミナルにてrake routesコマンド実行してみると、

destroy_user_session  GET    /users/sign_out(.:format)            devise/sessions#destroy 

#メソッドがGETになってる???

ビューファイルのログアウトボタンのリンクのパスは問題なく記述できてました。
sign_outログアウトのメソッドってDELETEじゃないの???????

ってことでルーティング確認!!

routes.rb
Rails.application.routes.draw do
  devise_for :users
  root 'groups#index'

  resources :users, only: [:index,:edit, :update]
  resources :groups, only: [:new, :create, :edit, :update] do
    resources :messages, only: [:index, :create]
   end
end

あれ???問題なくね????

どこがおかしいんだ?・・・・・

ってことでメンターさんに質問。

メンターさんも??????あれ????なんだろう???とrake routesで確認。
するとやはりGETになってる。

試しにroutes.rbファイルのdevise_for :usersの記述を削除

routes.rb
Rails.application.routes.draw do

  root 'groups#index'

  resources :users, only: [:index,:edit, :update]
  resources :groups, only: [:new, :create, :edit, :update] do
    resources :messages, only: [:index, :create]
  end
end

そしてターミナルでrake routesコマンド!!!!

すると!!!!!

destroy_user_session DELETE /users/sign_out(.:format)            devise/sessions#destroy

GETがDELETEに変わってる!!!!

そのまま再度、devise_for :usersを記述。

routes.rb
Rails.application.routes.draw do
  devise_for :users
  root 'groups#index'

  resources :users, only: [:index,:edit, :update]
  resources :groups, only: [:new, :create, :edit, :update] do
    resources :messages, only: [:index, :create]
   end
end

そんで再度ターミナルでrake routesで確認したらDELETEになっていました。

無事、その後rails sでサーバー再起動させたら問題なくログアウトできました。

とりあえず解決はできたのですが、
今回の件はバグ?みたいなものと説明されましたが真相は謎です。

他にも

記事を調べたら

[Rails 4.x] Devise で Sign Out が Routing Error になる際の対応。(method の delete が get になる場合)
https://qiita.com/colorrabbit/items/5545fce7e5cd4e494396

の記事がでてきました。
上記の記事の内容を試したのですがこちらは特に変化がなくエラーのままでした。

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

【3分入門】コピペで導入 railsでgraphql

【3分入門】コピペで導入 ooo シリーズ第一弾です。

rails に graphqlを導入していきます。

https://github.com/nishisuke/graphql-rails-minimum-sample

graphql とは?
https://graphql.org/learn/

install

# Gemfile

gem 'graphql'
$ bundle

models

users type
name String
age Integer
app/models/user.rb
class User < ApplicationRecord
  def friends
    %i[user mate_user].inject(Friend.none) do |friends_query, column_name|
      friends_query.or(Friend.where(column_name => self))
    end
  end
end
friends type
user_id Integer
mate_user_id Integer
app/models/friend.rb
class Friend < ApplicationRecord
  belongs_to :user
  belongs_to :mate_user, class_name: :User

  def pairs
    [user, mate_user]
  end
end

friend model has two users.

setup

app/graphql/graphql_rails_minimum_sample_schema.rb
class GraphqlRailsMinimumSampleSchema < GraphQL::Schema
  query(GqlTypes::Query)
end
app/graphql/gql_types.rb
module GqlTypes
  class Query < GraphQL::Schema::Object
    field :users,   [UserType],   null: false
    field :friends, [FriendType], null: false do
      argument :user_id, Int, required: true, camelize: false
    end

    def users
      User.all
    end

    def friends(user_id:)
      User.find(user_id).friends
    end
  end
end
app/graphql/gql_types/base_object.rb
module GqlTypes
  class BaseObject < GraphQL::Schema::Object
  end
end
app/graphql/gql_types/friend_type.rb
module GqlTypes
  class FriendType < BaseObject
    field :pairs, [UserType], null: false
  end
end
app/graphql/gql_types/user_type.rb
module GqlTypes
  class UserType < BaseObject
    field :name,       String,       null: false
    field :age,        String,       null: true
    field :created_at, String,       null: false
    field :friends,    [FriendType], null: false
  end
end

execute query!!

注意点

  1. created_atなどsnake caseのデータ名はデフォルトでcamel caseで指定する
  2. camelize false を指定すればsnake caseで指定できる
  3. argumentはvariablesに渡す
  4. トップレベルの{}に注意(以下)
# queryには{}をつけない
query get_friends($user_id: Int!) {
  # camelize falseなためuserIdではない(:point_up_2: :point_down: )
  friends(user_id: $user_id) {}
}
{
  users {}
}

try

rails c
> GraphqlRailsMinimumSampleSchema.execute('{ users { name createdAt age friends { pairs { name } } } }').to_h
=> {"data"=>{
  "users"=>[{
    "name"=>"nishi",
    "createdAt"=>"2019-04-14 04:01:37 UTC",
    "age"=>"9",
    "friends"=>[{
      "pairs"=>[{"name"=>"nishi"}, {"name"=>"tarou"}]
    }]
  }, {
    "name"=>"suke",
    "createdAt"=>"2019-04-14 04:01:37 UTC",
    "age"=>"19",
    "friends"=>[{
      "pairs"=>[{"name"=>"suke"}, {"name"=>"tarou"}]
    }]
  }, {
    "name"=>"tarou",
    "createdAt"=>"2019-04-14 04:01:37 UTC",
    "age"=>"20",
    "friends"=>[
      {"pairs"=>[{"name"=>"nishi"}, {"name"=>"tarou"}]},
      {"pairs"=>[{"name"=>"suke"},  {"name"=>"tarou"}]}
    ]
  }]
}}
> GraphqlRailsMinimumSampleSchema.execute('query get_friends($user_id: Int!) { friends(user_id: $user_id) { pairs { name } } }', variables: { user_id: User.last.id } ).to_json
=> {"data"=>{"friends"=>[
  {"pairs"=>[{"name"=>"nishi"}, {"name"=>"tarou"}]},
  {"pairs"=>[{"name"=>"suke"}, {"name"=>"tarou"}]}
]}}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】find_or_initialize_byメソッドを使ってインスタンスを作成する時のポイント

現在、amazonAPIを利用した口コミの共有サービスを作成中です。

その中で、「商品を検索し表示させる」という処理があるのですが、その際に役立ったfind_or_initialize_byメソッドについて簡単に整理します。

find_or_initialize_byメソッドとは

find_or_initialize_byメソッドとは、条件に合致したインスタンスがデータベースに保存されているかどうかをチェックしています。

この際、

  • データベースに保存されている場合はfindメソッド
  • データベースに保存されていない場合は'new'メソッド

として、インスタンスの状況によって適用されるメソッドが異なることがポイントです。インスタンスが保存されている場合、findメソッドが適用されるのでインスタンスに保存済みのデータ(idなど)を含めることができます。

インスタンス = persisted?インスタンス = new_record?でデータベースの保存状況を真偽値で取得できます。

find_or_initialize_byメソッドの使い道

前述の通り、find_or_initialize_byは条件分岐がポイントとなるので、データベースの保存状況でインスタンスに変化を与えたい場合に有用となります。

例えば私の場合ですと、APIから商品データを取得し一覧表示しています。

その際に、データベース保存済みなら「商品削除ボタン」を表示、データベースに保存していない新規のインスタンスなら「商品登録ボタン」を表示したいケースで、find_or_initialize_byを使用しています。

products_controller.rb
def create
  @product = Product.find_or_initialize_by(asin: params[:product_asin])
  unless @product.persisted?
    # @product が保存されていない場合、先に @product を保存する
    products = Amazon::Ecs.item_lookup(
      params[:product_asin],
      response_group: 'Medium',
      country: 'jp'
    )

    products.items.each do |item|
      @product = Product.new(
        title: item.get('ItemAttributes/Title'),
        image_url: item.get('LargeImage/URL'),
        url: item.get('DetailPageURL'),
        asin: item.get('ASIN'),
        brand_amazon_name: item.get('ItemAttributes/Brand'), 
        price: item.get('OfferSummary/LowestNewPrice/Amount'), 
      )
    @product.save
    end
  end  
end
_products.html.erb
<!--商品登録削除ボタン-->
<div class="buttons text-center">
<% if product.persisted? %>
  <%= form_tag(product_path(product.id), method: :delete) do %>
    <%= hidden_field_tag :product_id, product.id %>
    <%= submit_tag '削除', class: 'btn btn-danger' %>
  <% end %>
<% else %>
  <%= form_tag(products_path) do %>
    <%= hidden_field_tag :product_asin, product.asin %>
    <%= submit_tag '登録', class: 'btn btn-primary' %>
  <% end %>
<% end %>

(+α)find_or_create_byメソッドについて

find_or_create_byメソッドは、find_or_initialize_byと似た内容のメソッドなので、今後のために簡単に整理。

条件に合致したインスタンスがデータベースに保存されているかどうかをチェックしている点は、両者とも同じです。

その際に、find_or_create_byメソッドは、

  • データベースに保存されている場合はfindメソッド
  • データベースに保存されていない場合は'create'メソッド

となることがポイントです。「データベースに保存されていない場合は'create'メソッド」となるのですね。

条件に合致した情報をゴリゴリとデータベースに保存していくというケースに適しているのでしょう。

まとめ

find_or_initialize_byメソッドは、「APIを利用して情報取得→整形しインスタンス作成」のようなケースで役立つことがわかりました。

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

Ruby on Rails: Google Mapをレスポンシブに対応する

実現したいこと

Wepアプリ開発していると、Google mapを使う時があるかと思います。
そんな時に、ただただマップコードを埋め込むとせっかくのレスポンシブデザインを意識したサイトが崩れてしまいます。
なので、今回はレスポンシブデザインに対応させる方法を共有したいと思う。

解決方法

<iframe><div class="gmap">でカッコって上げることで解決できる。

<div class="gmap"><%== @user.map %></div>
.gmap{
position: relative;
padding-bottom: 56.25%;
padding-top: 30px;
height: 0;
overflow: hidden;
}
.gmap iframe,
.gmap object,
.gmap embed {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

macOS Mojave, Nokogiriインストールできない問題 解決メモ

macOS MojaveでNokogiriがインストールできない問題解消のメモ

概要

macOSのアップデート後から、Nokogiri Gemのインストールが痛恨の失敗!!

初心者の私には正直理解不能だったが頑張ってエラーを見てググる、を繰り返してみた。

発生したエラー

" clang -o conftest -I/Users/user_name/.rbenv/versions/2.6.2/include/ruby-2.6.0/x86_64-darwin17
 -I/Users/user_name/.rbenv/versions/2.6.2/include/ruby-2.6.0/ruby/backward
 -I/Users/user_name/.rbenv/versions/2.6.2/include/ruby-2.6.0
 -I. -I/Users/user_name/Desktop/app/app/vendor/bundler/ruby/2.6.0/gems/nokogiri-1.10.2/ports/x86_64-apple-darwin17.7.0/libxslt/1.1.33/include
 -I/Users/user_name/Desktop/app/app/vendor/bundler/ruby/2.6.0/gems/nokogiri-1.10.2/ports/x86_64-apple-darwin17.7.0/libxml2/2.9.9/include/libxml2
 -I/Users/user_name/Desktop/app/app/vendor/bundler/ruby/2.6.0/gems/nokogiri-1.10.2/ports/x86_64-apple-darwin17.7.0/libxml2/2.9.9/include/libxml2
 -I/Users/user_name/.rbenv/versions/2.6.2/include 
 -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT   "-DNOKOGIRI_LIBXML2_PATH=\"/Users/user_name/Desktop/app/app/vendor/bundler/ruby/2.6.0/gems/nokogiri-1.10.2/ports/x86_64-apple-darwin17.7.0/libxml2/2.9.9\""
 "-DNOKOGIRI_LIBXML2_PATCHES=\"0001-Revert-Do-not-URI-escape-in-server-side-includes.patch 0002-Remove-script-macro-support.patch 0003-Update-entities-to-remove-handling-of-ssi.patch\""
 "-DNOKOGIRI_LIBXSLT_PATH=\"/Users/user_name/Desktop/app/app/vendor/bundler/ruby/2.6.0/gems/nokogiri-1.10.2/ports/x86_64-apple-darwin17.7.0/libxslt/1.1.33\"" "-DNOKOGIRI_LIBXSLT_PATCHES=\"\""  -O3 -Wno-error=shorten-64-to-32  -pipe 
 -I /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/libxml2 -DNOKOGIRI_USE_PACKAGED_LIBRARIES conftest.c 
 -L. -L/Users/user_name/.rbenv/versions/2.6.2/lib -L/Users/user_name/Desktop/app/app/vendor/bundler/ruby/2.6.0/gems/nokogiri-1.10.2/ports/x86_64-apple-darwin17.7.0/libxml2/2.9.9/lib -L/Users/user_name/Desktop/app/app/vendor/bundler/ruby/2.6.0/gems/nokogiri-1.10.2/ports/x86_64-apple-darwin17.7.0/libxslt/1.1.33/lib
 -L/usr/local/Cellar/xz/5.2.4/lib
 -L. -L/Users/user_name/.rbenv/versions/2.6.2/lib 
 -fstack-protector-strong -L/usr/local/lib/Users/user_name/Desktop/app/app/vendor/bundler/ruby/2.6.0/gems/nokogiri-1.10.2/ports/x86_64-apple-darwin17.7.0/libxslt/1.1.33/lib/libexslt.a
 -lm -liconv -lpthread -llzma -lz /Users/user_name/Desktop/app/app/vendor/bundler/ruby/2.6.0/gems/nokogiri-1.10.2/ports/x86_64-apple-darwin17.7.0/libxml2/2.9.9/lib/libxml2.a/Users/user_name/Desktop/app/app/vendor/bundler/ruby/2.6.0/gems/nokogiri-1.10.2/ports/x86_64-apple-darwin17.7.0/libxslt/1.1.33/lib/libxslt.a
 -lm -liconv -lpthread -llzma -lz /Users/user_name/Desktop/app/app/vendor/bundler/ruby/2.6.0/gems/nokogiri-1.10.2/ports/x86_64-apple-darwin17.7.0/libxml2/2.9.9/lib/libxml2.a
 -llzma -lruby.2.6-static -framework Security -framework Foundation -lpthread -ldl -lobjc /Users/user_name/Desktop/app/app/vendor/bundler/ruby/2.6.0/gems/nokogiri-1.10.2/ports/x86_64-apple-darwin17.7.0/libxslt/1.1.33/lib/libexslt.a -lm -liconv -lpthread
 -llzma -lz /Users/user_name/Desktop/app/app/vendor/bundler/ruby/2.6.0/gems/nokogiri-1.10.2/ports/x86_64-apple-darwin17.7.0/libxml2/2.9.9/lib/libxml2.a /Users/user_name/Desktop/app/app/vendor/bundler/ruby/2.6.0/gems/nokogiri-1.10.2/ports/x86_64-apple-darwin17.7.0/libxslt/1.1.33/lib/libxslt.a -lm -liconv -lpthread
 -llzma -lz /Users/user_name/Desktop/app/app/vendor/bundler/ruby/2.6.0/gems/nokogiri-1.10.2/ports/x86_64-apple-darwin17.7.0/libxml2/2.9.9/lib/libxml2.a -llzma   "
checked program was:
/* begin */
 1: #include "ruby.h"
 2: 
 3: /*top*/
 4: extern int t(void);
 5: int main(int argc, char **argv)
 6: {
 7:   if (argc > 1000000) {
 8:     int (* volatile tp)(void)=(int (*)(void))&t;
 9:     printf("%d", (*tp)());
10:   }
11: 
12:   return 0;
13: }
14: extern void xmlSchemaSetParserStructuredErrors();
15: int t(void) { xmlSchemaSetParserStructuredErrors(); return 0; }
/* end */

解決方法

bundle configでビルド時のオプションとして、--use-system-libraries--with-xml2-includeを設定しておくといいらしい!

$ bundle config build.nokogiri --use-system-libraries --with-xml2-include=$(brew --prefix libxml2)/include/libxml2

解決しました!

参考

An error occurred while installing nokogiri (1.10.0), and Bundler cannot continue.

nokogiriが(また)インストールできない

macOS SierraでNokogiriがインストールできない問題の解決方法

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

気付いたこと備忘録

気付いたこと備忘録

ひたすら気付いたことをいったん書きなぐる記事

AWSCloud9関連

gitの変更内容はなぜか、runを押さないと反映されない。

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

Payjpでカード情報登録 と削除機能を実装する(Rails)

実装する機能と前提条件

Payjp(Pay.jp)を利用してページ内に直接フォームを設置する場合を想定しています。
実装するものとしては下記のとおりです。
- 自作のカード登録フォーム
- カード情報とユーザーの紐づけ
- ユーザーとカードの登録と削除
- 商品の購入(次回の記事で記述)

イメージとしてはこんな感じの入力画面です。
image.png

もしSDKを使う場合は別記事をご覧いただくかPAY.JP API 利用ガイド | PAY.JPを触るとイメージをつかみやすいと思います。

バージョン情報
ruby 2.3.1
Rails 5.0.7

前提条件
- deviseが導入済みでログインができている(current_userを使うため)
- hamlでの記載(gem 'haml-rails')
 

1.Payjpのアカウントを作成しよう

Payjpのサイトでアカウントを作成します。

2.APIを確認しよう

ダッシュボードのAPIより確認ができます。
今回はテストモードでの実装なので、テスト秘密鍵テスト公開鍵を使用します。
スクリーンショット 2019-04-14 16.31.04.png

3.payjpのgemを設置しよう

下記をgemfileに記載しbandle installを実施します。

gem 'payjp'

4.payjp.jsを読み込めるようにしよう

下記の通りに追記します。

app/views/layouts/application.html.haml
%html
  %head
    %meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
    %title payjptest
    %script{src: "https://js.pay.jp/", type: "text/javascript"}
    -# このscriptを記載
    = csrf_meta_tags
    = stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload'
    = javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
  %body
    = yield

5.データベースを作成しよう

下記内容でpayjpのデータを保管するデータベースを作成します。nullはお好みで。
尚、紐づけは以下のとおりです。
- user_id -> Userテーブルのid
- customer_id -> payjpの顧客id
- card_id -> payjpのデフォルトカードid
(デフォルトカードidはトークンとは違います。ここの理解で結構時間をとってしまいました…)

db/migrate/20190400000000_create_cards.rb
class CreateCards < ActiveRecord::Migration[5.0]
  def change
    create_table :cards do |t|
      t.integer :user_id, null: false
      t.string :customer_id, null: false
      t.string :card_id, null: false
      t.timestamps
    end
  end
end

ちなみにカード情報そのものを保存することは禁止されていますので、
payjpに保管されている情報を顧客idやカードidで呼び出すことで情報取得や支払いなどに対応します。
カード情報非通過化対応のお願い

6.コントローラーを作成しよう

下記内容でコントローラーを作成します。
ENV["PAYJP_PRIVATE_KEY"]は環境変数でテスト秘密鍵を設定し読み込みます。

app/controllers/card_controller.rb
class CardController < ApplicationController

  require "payjp"

  def new
    card = Card.where(user_id: current_user.id)
    redirect_to action: "show" if card.exists?
  end

  def pay #ここでpayjpとCardのデータベース作成を実施します。
    Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
    if params['payjp-token'].blank?
      redirect_to action: "new"
    else
      customer = Payjp::Customer.create(
      description: '登録テスト', #なくてもOK
      email: current_user.email, #なくてもOK
      card: params['payjp-token'],
      metadata: {user_id: current_user.id}
      ) #念の為metadataにuser_idを入れましたがなくてもOK
      @card = Card.new(user_id: current_user.id, customer_id: customer.id, card_id: customer.default_card)
      if @card.save
        redirect_to action: "show"
      else
        redirect_to action: "pay"
      end
    end
  end

  def delete #PayjpとCardデータベースを削除します
    card = Card.where(user_id: current_user.id).first
    if card.blank?
    else
      Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
      customer = Payjp::Customer.retrieve(card.customer_id)
      customer.delete
      card.delete
    end
      redirect_to action: "new"
  end

  def show
    card = Card.where(user_id: current_user.id).first
    if card.blank?
      redirect_to action: "new" 
    else
      Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
      customer = Payjp::Customer.retrieve(card.customer_id)
      @default_card_information = customer.cards.retrieve(card.card_id)
    end
  end
end

7.カードの登録画面を作成しよう

今回は登録画面と確認兼削除画面の2つを作成します。デザインはアレンジしてください。

登録画面

app/view/card/new.html.haml
= form_tag(card_pay_path, method: :post, id: 'charge-form',  name: "inputForm") do
  %label カード番号
  = text_field_tag "number", "", class: "number", placeholder: "半角数字のみ" ,maxlength: "16", type: "text", id: "card_number"
  %br
  %label 有効期限
  %select#exp_month{name: "exp_month", type: "text"}
    %option{value: ""} --
    %option{value: "1"}01
    %option{value: "2"}02
    %option{value: "3"}03
    %option{value: "4"}04
    %option{value: "5"}05
    %option{value: "6"}06
    %option{value: "7"}07
    %option{value: "8"}08
    %option{value: "9"}09
    %option{value: "10"}10
    %option{value: "11"}11
    %option{value: "12"}12
  %span 月/
  %select#exp_year{name: "exp_year", type: "text"}
    %option{value: ""} --
    %option{value: "2019"}19
    %option{value: "2020"}20
    %option{value: "2021"}21
    %option{value: "2022"}22
    %option{value: "2023"}23
    %option{value: "2024"}24
    %option{value: "2025"}25
    %option{value: "2026"}26
    %option{value: "2027"}27
    %option{value: "2028"}28
    %option{value: "2029"}29
  %span%br
  %label セキュリティコード
  = text_field_tag "cvc", "", class: "cvc", placeholder: "カード背面3~4桁の番号", maxlength: "4", id: "cvc"
  #card_token
  = submit_tag "追加する", id: "token_submit"

image.png

最初、= sectionを使っていたのですがうまく行かなかったため
%optionが連続発生し駄長なコードになっているのはご了承ください…

確認兼削除画面

app/view/card/show.html.haml
%label 登録クレジットカード情報
%br
= "**** **** **** " + @default_card_information.last4
%br
- exp_month = @default_card_information.exp_month.to_s
- exp_year = @default_card_information.exp_year.to_s.slice(2,3)
= exp_month + " / " + exp_year
= form_tag(card_delete_path, method: :post, id: 'charge-form',  name: "inputForm") do
  %input{ type: "hidden", name: "card_id", value: "" }
  %button 削除する

image.png

8.Payjpにデータを送りトークンを取得しよう

提供されているpay.jpのサンプルを参照し一部アレンジしております。

app/assets/javascripts/payjp.js
document.addEventListener(
  "DOMContentLoaded", e => {
    Payjp.setPublicKey("pk_test_79ae2d2743199a76f3ebbbbb"); //ここに公開鍵を直書き
    let btn = document.getElementById("token_submit"); //IDがtoken_submitの場合に取得されます
    btn.addEventListener("click", e => { //ボタンが押されたときに作動します
      e.preventDefault(); //ボタンを一旦無効化します
      let card = {
        number: document.getElementById("card_number").value,
        cvc: document.getElementById("cvc").value,
        exp_month: document.getElementById("exp_month").value,
        exp_year: document.getElementById("exp_year").value
      }; //入力されたデータを取得します。
      Payjp.createToken(card, (status, respnse) => {
        if (status === 200) { //成功した場合
          $("#card_number").removeAttr("name");
          $("#cvc").removeAttr("name");
          $("#exp_month").removeAttr("name");
          $("#exp_year").removeAttr("name"); //データを自サーバにpostしないように削除
          $("#card_token").append(
            $('<input type="hidden" name="payjp-token">').val(response.id)
          ); //取得したトークンを送信できる状態にします
          document.inputForm.submit();
          alert("登録が完了しました"); //確認用
        } else {
          alert("カード情報が正しくありません。"); //確認用
        }
      });
    });
  },
  false
);

9.ルートを作成しよう

今回はshow,pay,new,deleteの4つのメゾットがあるので下記の通り追記します。
一部はresoursesで設定してもよいかと思います。

config/routes.rb
  post 'card/new', to: 'card#new'
  post 'card/show', to: 'card#show'
  post 'card/pay', to: 'card#pay'
  post 'card/delete', to: 'card#delete'

10.カードを登録してみよう

テストカードはこちらです。
それ以外を打ち込んだ場合はトークンが発行できずはねられます。
image.png

以上でカード登録から削除まで一通り実装できました。
次回はこれを使って商品支払いを実装します。

参考

https://pay.jp/docs/api/?ruby

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

Payjpでカード情報登録と削除機能を実装する(Rails)

実装する機能と前提条件

Payjp(Pay.jp)を利用してページ内に直接フォームを設置する場合を想定しています。
実装するものとしては下記のとおりです。

  • 自作のカード登録フォーム
  • カード情報とユーザーの紐づけ
  • ユーザーとカードの登録と削除
  • 商品の購入(次回の記事で記述)

イメージとしてはこんな感じの入力画面です。
image.png

もしSDKを使う場合は別記事をご覧いただくかPAY.JP API 利用ガイド | PAY.JPを触るとイメージをつかみやすいと思います。

バージョン情報
ruby 2.3.1
Rails 5.0.7

前提条件

  • deviseが導入済みでログインができている(current_userを使うため)
  • hamlでの記載(gem 'haml-rails')

1.Payjpのアカウントを作成しよう

Payjpのサイトでアカウントを作成します。

2.APIを確認しよう

ダッシュボードのAPIより確認ができます。
今回はテストモードでの実装なので、テスト秘密鍵テスト公開鍵を使用します。
スクリーンショット 2019-04-14 16.31.04.png

3.payjpのgemを設置しよう

下記をgemfileに記載しbandle installを実施します。

gem 'payjp'

4.payjp.jsを読み込めるようにしよう

下記の通りに追記します。

app/views/layouts/application.html.haml
%html
  %head
    %meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
    %title payjptest
    %script{src: "https://js.pay.jp/", type: "text/javascript"}
    -# このscriptを記載
    = csrf_meta_tags
    = stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload'
    = javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
  %body
    = yield

5.データベースを作成しよう

下記内容でpayjpのデータを保管するデータベースを作成します。nullはお好みで。
尚、紐づけは以下のとおりです。
- user_id -> Userテーブルのid
- customer_id -> payjpの顧客id
- card_id -> payjpのデフォルトカードid
(デフォルトカードidはトークンとは違います。ここの理解で結構時間をとってしまいました…)

db/migrate/20190400000000_create_cards.rb
class CreateCards < ActiveRecord::Migration[5.0]
  def change
    create_table :cards do |t|
      t.integer :user_id, null: false
      t.string :customer_id, null: false
      t.string :card_id, null: false
      t.timestamps
    end
  end
end

ちなみにカード情報そのものを保存することは禁止されていますので、
payjpに保管されている情報を顧客idやカードidで呼び出すことで情報取得や支払いなどに対応します。
カード情報非通過化対応のお願い

6.コントローラーを作成しよう

下記内容でコントローラーを作成します。
ENV["PAYJP_PRIVATE_KEY"]は環境変数でテスト秘密鍵を設定し読み込みます。
私はdotenvを利用しています。

app/controllers/card_controller.rb
class CardController < ApplicationController

  require "payjp"

  def new
    card = Card.where(user_id: current_user.id)
    redirect_to action: "show" if card.exists?
  end

  def pay #payjpとCardのデータベース作成を実施します。
    Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
    if params['payjp-token'].blank?
      redirect_to action: "new"
    else
      customer = Payjp::Customer.create(
      description: '登録テスト', #なくてもOK
      email: current_user.email, #なくてもOK
      card: params['payjp-token'],
      metadata: {user_id: current_user.id}
      ) #念の為metadataにuser_idを入れましたがなくてもOK
      @card = Card.new(user_id: current_user.id, customer_id: customer.id, card_id: customer.default_card)
      if @card.save
        redirect_to action: "show"
      else
        redirect_to action: "pay"
      end
    end
  end

  def delete #PayjpとCardデータベースを削除します
    card = Card.where(user_id: current_user.id).first
    if card.blank?
    else
      Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
      customer = Payjp::Customer.retrieve(card.customer_id)
      customer.delete
      card.delete
    end
      redirect_to action: "new"
  end

  def show #Cardのデータpayjpに送り情報を取り出します
    card = Card.where(user_id: current_user.id).first
    if card.blank?
      redirect_to action: "new" 
    else
      Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
      customer = Payjp::Customer.retrieve(card.customer_id)
      @default_card_information = customer.cards.retrieve(card.card_id)
    end
  end
end

7.カードの登録画面を作成しよう

今回は登録画面と確認兼削除画面の2つを作成します。デザインはアレンジしてください。

登録画面

app/view/card/new.html.haml
= form_tag(card_pay_path, method: :post, id: 'charge-form',  name: "inputForm") do
  %label カード番号
  = text_field_tag "number", "", class: "number", placeholder: "半角数字のみ" ,maxlength: "16", type: "text", id: "card_number"
  %br
  %label 有効期限
  %select#exp_month{name: "exp_month", type: "text"}
    %option{value: ""} --
    %option{value: "1"}01
    %option{value: "2"}02
    %option{value: "3"}03
    %option{value: "4"}04
    %option{value: "5"}05
    %option{value: "6"}06
    %option{value: "7"}07
    %option{value: "8"}08
    %option{value: "9"}09
    %option{value: "10"}10
    %option{value: "11"}11
    %option{value: "12"}12
  %span 月/
  %select#exp_year{name: "exp_year", type: "text"}
    %option{value: ""} --
    %option{value: "2019"}19
    %option{value: "2020"}20
    %option{value: "2021"}21
    %option{value: "2022"}22
    %option{value: "2023"}23
    %option{value: "2024"}24
    %option{value: "2025"}25
    %option{value: "2026"}26
    %option{value: "2027"}27
    %option{value: "2028"}28
    %option{value: "2029"}29
  %span%br
  %label セキュリティコード
  = text_field_tag "cvc", "", class: "cvc", placeholder: "カード背面3~4桁の番号", maxlength: "4", id: "cvc"
  #card_token
  = submit_tag "追加する", id: "token_submit"

image.png

最初、= sectionを使っていたのですがうまく行かなかったため
%optionが連続発生し駄長なコードになっているのはご了承ください…

確認兼削除画面

app/view/card/show.html.haml
%label 登録クレジットカード情報
%br
= "**** **** **** " + @default_card_information.last4
%br
- exp_month = @default_card_information.exp_month.to_s
- exp_year = @default_card_information.exp_year.to_s.slice(2,3)
= exp_month + " / " + exp_year
= form_tag(card_delete_path, method: :post, id: 'charge-form',  name: "inputForm") do
  %input{ type: "hidden", name: "card_id", value: "" }
  %button 削除する

image.png

8.Payjpにデータを送りトークンを取得しよう

提供されているpay.jpのサンプルを参照し一部アレンジしております。

app/assets/javascripts/payjp.js
document.addEventListener(
  "DOMContentLoaded", e => {
    Payjp.setPublicKey("pk_test_79ae2d2743199a76f3ebbbbb"); //ここに公開鍵を直書き
    let btn = document.getElementById("token_submit"); //IDがtoken_submitの場合に取得されます
    btn.addEventListener("click", e => { //ボタンが押されたときに作動します
      e.preventDefault(); //ボタンを一旦無効化します
      let card = {
        number: document.getElementById("card_number").value,
        cvc: document.getElementById("cvc").value,
        exp_month: document.getElementById("exp_month").value,
        exp_year: document.getElementById("exp_year").value
      }; //入力されたデータを取得します。
      Payjp.createToken(card, (status, respnse) => {
        if (status === 200) { //成功した場合
          $("#card_number").removeAttr("name");
          $("#cvc").removeAttr("name");
          $("#exp_month").removeAttr("name");
          $("#exp_year").removeAttr("name"); //データを自サーバにpostしないように削除
          $("#card_token").append(
            $('<input type="hidden" name="payjp-token">').val(response.id)
          ); //取得したトークンを送信できる状態にします
          document.inputForm.submit();
          alert("登録が完了しました"); //確認用
        } else {
          alert("カード情報が正しくありません。"); //確認用
        }
      });
    });
  },
  false
);

9.ルートを作成しよう

今回はshow,pay,new,deleteの4つのメゾットがあるので下記の通り追記します。
一部はresoursesで設定してもよいかと思います。

config/routes.rb
  post 'card/new', to: 'card#new'
  post 'card/show', to: 'card#show'
  post 'card/pay', to: 'card#pay'
  post 'card/delete', to: 'card#delete'

10.カードを登録してみよう

テストカードはこちらです。
それ以外を打ち込んだ場合はトークンが発行できずはねられます。
image.png

以上でカード登録から削除まで一通り実装できました。
次回はこれを使って商品支払いを実装します。

参考

https://pay.jp/docs/api/?ruby

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

Payjpでクレジットカード登録と削除機能を実装する(Rails)

実装する機能と前提条件

今回、Payjp(Pay.jp)を利用して入力フォームを直接ページ内に設置します。
実装するものとしては下記のとおりです。

  • 自作のカード情報入力フォーム
  • カード情報とユーザーの紐づけ
  • ユーザーとカードの登録と削除
  • 商品の購入次回の記事参照

イメージとしてはこんな感じの入力フォームです。
image.png

もしSDKを使う場合は別記事をご覧いただくかPAY.JP API 利用ガイド | PAY.JPを触るとイメージをつかみやすいと思います。

バージョン情報
・ruby 2.3.1
・Rails 5.0.7

前提条件
・deviseが導入済みでログインができている(current_userを使うため)
・hamlでの記載(gem 'haml-rails')

1.Payjpのアカウントを作成しよう

Payjpのサイトでアカウントを作成します。

2.APIを確認しよう

ダッシュボードのAPIより確認ができます。
今回はテストモードでの実装なので、テスト秘密鍵テスト公開鍵を使用します。
スクリーンショット 2019-04-14 16.31.04.png

3.payjpのgemを設置しよう

下記をgemfileに記載しbandle installを実施します。

gem 'payjp'

4.payjp.jsを読み込めるようにしよう

下記の通りに追記します。

app/views/layouts/application.html.haml
%html
  %head
    %meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
    %title payjptest
    %script{src: "https://js.pay.jp/", type: "text/javascript"}
    -# このscriptを記載
    = csrf_meta_tags
    = stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload'
    = javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
  %body
    = yield

5.データベースを作成しよう

下記内容でpayjpのデータを保管するデータベースを作成します。nullはお好みで。
尚、紐づけは以下のとおりです。
- user_id -> Userテーブルのid
- customer_id -> payjpの顧客id
- card_id -> payjpのデフォルトカードid
(デフォルトカードidはトークンとは違います。ここの理解で結構時間をとってしまいました…)

db/migrate/20190400000000_create_cards.rb
class CreateCards < ActiveRecord::Migration[5.0]
  def change
    create_table :cards do |t|
      t.integer :user_id, null: false
      t.string :customer_id, null: false
      t.string :card_id, null: false
      t.timestamps
    end
  end
end

ちなみにカード情報そのものを保存することは禁止されていますので、
payjpに保管されている情報を顧客idやカードidで呼び出すことで情報取得や支払いなどに対応します。
カード情報非通過化対応のお願い

6.コントローラーを作成しよう

下記内容でコントローラーを作成します。
ENV["PAYJP_PRIVATE_KEY"]は環境変数でテスト秘密鍵を設定し読み込みます。
私はdotenvを利用しています。

app/controllers/card_controller.rb
class CardController < ApplicationController

  require "payjp"

  def new
    card = Card.where(user_id: current_user.id)
    redirect_to action: "show" if card.exists?
  end

  def pay #payjpとCardのデータベース作成を実施します。
    Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
    if params['payjp-token'].blank?
      redirect_to action: "new"
    else
      customer = Payjp::Customer.create(
      description: '登録テスト', #なくてもOK
      email: current_user.email, #なくてもOK
      card: params['payjp-token'],
      metadata: {user_id: current_user.id}
      ) #念の為metadataにuser_idを入れましたがなくてもOK
      @card = Card.new(user_id: current_user.id, customer_id: customer.id, card_id: customer.default_card)
      if @card.save
        redirect_to action: "show"
      else
        redirect_to action: "pay"
      end
    end
  end

  def delete #PayjpとCardデータベースを削除します
    card = Card.where(user_id: current_user.id).first
    if card.blank?
    else
      Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
      customer = Payjp::Customer.retrieve(card.customer_id)
      customer.delete
      card.delete
    end
      redirect_to action: "new"
  end

  def show #Cardのデータpayjpに送り情報を取り出します
    card = Card.where(user_id: current_user.id).first
    if card.blank?
      redirect_to action: "new" 
    else
      Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
      customer = Payjp::Customer.retrieve(card.customer_id)
      @default_card_information = customer.cards.retrieve(card.card_id)
    end
  end
end

7.カードの登録画面を作成しよう

今回は登録画面と確認兼削除画面の2つを作成します。デザインはアレンジしてください。

登録画面

app/view/card/new.html.haml
= form_tag(card_pay_path, method: :post, id: 'charge-form',  name: "inputForm") do
  %label カード番号
  = text_field_tag "number", "", class: "number", placeholder: "半角数字のみ" ,maxlength: "16", type: "text", id: "card_number"
  %br
  %label 有効期限
  %select#exp_month{name: "exp_month", type: "text"}
    %option{value: ""} --
    %option{value: "1"}01
    %option{value: "2"}02
    %option{value: "3"}03
    %option{value: "4"}04
    %option{value: "5"}05
    %option{value: "6"}06
    %option{value: "7"}07
    %option{value: "8"}08
    %option{value: "9"}09
    %option{value: "10"}10
    %option{value: "11"}11
    %option{value: "12"}12
  %span 月/
  %select#exp_year{name: "exp_year", type: "text"}
    %option{value: ""} --
    %option{value: "2019"}19
    %option{value: "2020"}20
    %option{value: "2021"}21
    %option{value: "2022"}22
    %option{value: "2023"}23
    %option{value: "2024"}24
    %option{value: "2025"}25
    %option{value: "2026"}26
    %option{value: "2027"}27
    %option{value: "2028"}28
    %option{value: "2029"}29
  %span%br
  %label セキュリティコード
  = text_field_tag "cvc", "", class: "cvc", placeholder: "カード背面3~4桁の番号", maxlength: "4", id: "cvc"
  #card_token
  = submit_tag "追加する", id: "token_submit"

image.png

最初、= sectionを使っていたのですがうまく行かなかったため
%optionが連続発生し駄長なコードになっているのはご了承ください…

確認兼削除画面

app/view/card/show.html.haml
%label 登録クレジットカード情報
%br
= "**** **** **** " + @default_card_information.last4
%br
- exp_month = @default_card_information.exp_month.to_s
- exp_year = @default_card_information.exp_year.to_s.slice(2,3)
= exp_month + " / " + exp_year
= form_tag(card_delete_path, method: :post, id: 'charge-form',  name: "inputForm") do
  %input{ type: "hidden", name: "card_id", value: "" }
  %button 削除する

image.png

8.Payjpにデータを送りトークンを取得しよう

提供されているpay.jpのサンプルを参照し一部アレンジしております。

app/assets/javascripts/payjp.js
document.addEventListener(
  "DOMContentLoaded", e => {
    Payjp.setPublicKey("pk_test_79ae2d2743199a76f3ebbbbb"); //ここに公開鍵を直書き
    let btn = document.getElementById("token_submit"); //IDがtoken_submitの場合に取得されます
    btn.addEventListener("click", e => { //ボタンが押されたときに作動します
      e.preventDefault(); //ボタンを一旦無効化します
      let card = {
        number: document.getElementById("card_number").value,
        cvc: document.getElementById("cvc").value,
        exp_month: document.getElementById("exp_month").value,
        exp_year: document.getElementById("exp_year").value
      }; //入力されたデータを取得します。
      Payjp.createToken(card, (status, respnse) => {
        if (status === 200) { //成功した場合
          $("#card_number").removeAttr("name");
          $("#cvc").removeAttr("name");
          $("#exp_month").removeAttr("name");
          $("#exp_year").removeAttr("name"); //データを自サーバにpostしないように削除
          $("#card_token").append(
            $('<input type="hidden" name="payjp-token">').val(response.id)
          ); //取得したトークンを送信できる状態にします
          document.inputForm.submit();
          alert("登録が完了しました"); //確認用
        } else {
          alert("カード情報が正しくありません。"); //確認用
        }
      });
    });
  },
  false
);

9.ルートを作成しよう

今回はshow,pay,new,deleteの4つのメゾットがあるので下記の通り追記します。
一部はresoursesで設定してもよいかと思います。

config/routes.rb
  post 'card/new', to: 'card#new'
  post 'card/show', to: 'card#show'
  post 'card/pay', to: 'card#pay'
  post 'card/delete', to: 'card#delete'

10.カードを登録してみよう

テストカードはこちらです。
それ以外を打ち込んだ場合はトークンが発行できずはねられます。
image.png

以上でカード登録から削除まで一通り実装できました。
次回はこれを使って商品支払いを実装します。

参考

https://pay.jp/docs/api/?ruby

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

Railsでデプロイする際に躓いた箇所

Railsでデプロイする際に躓いた箇所がいくつか(というより沢山)あったので自分用メモも兼ねて書きます。

secret_key_base周り

Rails5.2からsecrets.ymlの代わりにcredentials.yml.encが生成されるようになりました。
rails newされると自動でapp/configにcredentials.yml.encとmaster.keyが生成されます。
master.keyが無い状態でrails credentials:editコマンドを実行するとmaster.keyが生成されますが、生成されたmaster.keyで復号できず困りました。

Rails 5.2 で ActiveSupport::MessageEncryptor::InvalidMessage

こちらの記事にある通り、ローカルにあるmaster.keyの中身をコピーしてproduction環境のmaster.keyに貼り付けたところいけました。

MySQLでAccess denied

ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)

このようなエラーが出てきて入れず。

mysql5.7でパスワードを変更する

どうやら自動で仮パスワードが発行されているようなので調べてみると、

cat /var/log/mysqld.log | grep password
2019-04-14T11:01:59.067618Z 1 [Note] A temporary password is generated for root@localhost: **********

となっていたのでこちらの仮パスワードで無事いけました。

Unicornが起動できない

Unicornを起動しようとしたところ以下のようなエラーが。

master failed to start, check stderr log for details

log/unicorn.logをチェックしたところ、

/home/fkdolly/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0/gems/unicorn-5.5.0/lib/unicorn.rb:49:in `block in builder': wrong number of arguments (given 0, expected 2) (ArgumentError)

調べてみるとUnicorn 5.5.0で出ているエラーのようでした。
Unicorn で Rails アプリが起動しなかったので対処
Unicorn Refreshing Gem List

bundle exec gem list | grep unicorn
unicorn (5.5.0)

同じく5.5.0でしたので、

Gemfile
group :production, :staging do
    gem 'unicorn', '5.4.1'
end
bundle install

これでいけるかなと思ったらまだエラー。
5.5.0を削除するのを忘れていました。

bundle exec gem uninstall unicorn -v '5.5.0'
bundle update

これで無事に起動できました。

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

【第5章】rails tutorial 備忘録

レイアウト

bootstrap

containerとcontainer_fluidの違い

yield

ページごとの内容を挿入する

link_to

<%= link_to "表示文字列”,"パス",class:"class名" %>

link_to image_tag

<%= link_to image_tag("画像名",
alt:"alt名" %>
app/assets/image/にあるところから画像を探して、表示してくれる。

mv コマンド

参考サイト

bootstrap

gemgileに
gem 'bootstrap-sass', '3.3.7'を追加

 $touch app/assets/stylesheets/custom.scss

でカスタムCSSを作り、そこへcssを記載する。

そこへ

app/assets/stylesheets/custom.scss
@import "bootstrap-sprockets";
@import "bootstrap";
を記載する。

CSSを追加

remとem

@@@@@@@

letter-spacing
text-transform

パーシャル(partial)

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title><%= full_title(yield(:title)) %></title>
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>

ここから
<!--[if lt IE 9]>
      <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
      </script>
    <![endif]-->
ここまでを
↓
<%= render 'layouts/shim' %>
に置き換え、切り出す。


    </head>

ここから
    <header class="navbar navbar-fixed-top navbar-inverse">
    <div class="container">
    <%= link_to "sample app","#",id:"logo" %>
    <nav>
    <ul class ="nav navbar-nav navbar-right">
    <li><%= link_to "Home",'#' %></li>
    <li><%= link_to "About",'#' %></li>
    <li><%= link_to "Log in",'#' %></li>
    </ul>
    </nav>
    </div>
    </header>
ここまでを
↓
<%= render 'layouts/header' %>
に置き換え、切り出す


  <body>
  <div class = "container">
    <%= yield %>
    </div>
  </body>
</html>

切り出したものを
layouts/_shim.html.erb
layouts/_header.html.erb
のファイルに記載する。

アセットパイプライン

三つのassetsがある
1 app/assets 今あるアプリケーション固有のアセット

2 lib/assets 自分の開発チームによって作られたライブラリ用のアセット

3 vendor/assets サードパーティのアセット

マニフェストファイル

上記のアセットをどのように一つにまとめるかを指示できる

sass

このあと、progateでやろう。

ルートURL

root_pathは 「/」を返す。
root_urlは「http://www.example.com/」(
完全なurl)を返す

HTTPの標準では、リダイレクトの時は、完全なurlが求められるが、path書式でも動く。

get 'static_page/help'を

get '/help' ,to: 'static_pages#help’に変換すると

テストとviewsで名前付きurl(
help_path)が使えるようになる。

テストで使うルートの書式を名前付きルートに変えてみる。

<%= link_to "About",   'about_path' %>

注意!

名前ルートを''で囲わないこと。

統合テスト

アプリケーションにアクセスするところから
隅々までテストする

rails g controllerで自動作成されたテストと内容は同じで、

require 'test_helper'

class SiteLayoutTest < ActionDispatch::IntegrationTest
  # test "the truth" do
  #   assert true
  # end
end

actionDispatch::IntegrationTestを継承したクラスが記載されている。

単体テスト、機能テスト、統合テストと
様々なテストがある。

テストの種類と動作に関する記事

調べる

各テストのクラスがどんなクラスを継承しているか確認する
継承したクラスによって、意味や動きはどう変わるのか

何をrails newしたら、どのtestファイルが作成されるのかも整理する

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

エンジニア初心者がRailsでランキング機能実装の際につまづいたところ

CDの発売日を管理できるサービスを作っていて、発売日が過ぎたときにランキングから除外しなきゃ!と思ったものの微妙に詰まったのでここに備忘録として書き残しておきます。?

環境:cloud9(IDE)EC2(仮想サーバー)rails(rubyFW)mysql(DB)

まず大前提の知識としてModelはDBの情報を引っ張ってくるということです!(今更)
MVCのそれぞれの役割をしっかり理解しておくことは本当に重要で、理解してプログラミングをしていると今自分が何をやっているのか頭の中で整理できます。

今回は実際に色々試した過程を書きます。

大まかな流れとして、
1.DB設計を考える 2.mysql(DB)でコマンドを色々試す→3.処理が成功したらmodelに実装
という形で行いました。

1.DB設計を考える

ランキングは中間テーブル(relationships)で集計しているので、中間テーブルに発売日カラムを登録することで発売日でフィルターをかけることができるのでは?

2.mysqlでコマンドを色々試す

▼カラム追加(mysql)
alter table relationships add sales_date date;
楽天apiから発売日情報を文字列型で引っ張って来ているのでエラーになってしまった。

alter table relationships add sales_date varchar(255);
文字列型で登録〜うん良さそう

▼発売日を過ぎたものは非表示にするコマンドをチェック
私が実際にやったときはmodelの記述を先に行ってしまったのですごい時間を食ってしまった…先にこっちで確認すべきだった…良い学び

select * from relationships where sales_date > date_format(current_date(),'%Y年%m月%d日');
処理内容としては、現在日時をdate_formatを用いて年月日に変更し、sales_dateと比較演算子を用いて比較しています。これをそのままmodelに実装します。

3.処理が成功したらmodelに実装

▼記述方法

relationship.rb
def Relationship.ranking
  Relationship.where().group().order().limit().count()
end

前述の通り、modelはdbから情報を引っ張ってくるので書き方としてはかなりdbに近いです。
まずwhereで絞り込み、groupで重複した値をまとめ、orderで並べ替え、limitで表示制限をして最後のcountでCDの登録された数を数えるといった流れです。実際のコードを書いていきます。

relationship.rb
def self.ranking
  self.where("sales_date > date_format(current_date(),'%Y年%m月%d日')").group(:item_id).order('count_item_id DESC').limit(12).count(:item_id)
end

where以外はそこまで特別なことはしていないので省きます。
結論から書くとwhereにdbで成功した文をダブルクォーテーションで囲むだけでOKです!笑
これでできたときは拍子抜けしました…それと同時にMVCの理解度が低かったとかなり痛感しました。
modelはdbの情報を引っ張ってくるわけだからdbで実際に成功した文をそのまま書けば確かに間違いはないですねw

まとめ

MVCの役割を理解することの重要性を書きたかったのですがシッチャカメッチャカになっちゃった感。。。
まあそれなりに自分の考えは整理できた気がするので良しとします笑
反省点としては何を書くのか考えていなかったこと、考えをまとめていなかったことの二点ですかね?精進します!

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