20201112のRubyに関する記事は23件です。

AWS SDK for RubyでS3オブジェクトサイズの取得

HLS形式の動画サイズ取得の為に使いました!

※オブジェクトデータ1000件以上を想定しています。

Class: Aws::S3::Client

client = AWS::S3::new

size = 0
options = { bucket: [バケット名], prefix: [プレフィックス] }
loop do
  object_list = client.list_objects_v2(options)
  object_list.contents.each do |object|
    size += object.size
  end
  options[:continuation_token] = object_list.next_continuation_token
  break unless object_list.next_continuation_token
end

gigabyte = (size / (2 ** 30).to_f).round(2)

CLIだとさらに簡単
AWS CLIを使ってS3上にあるファイル数とファイルサイズの合計を取得する

$ aws s3 ls s3://[バケット名]/[フォルダ名]/  --recursive --human --sum

実装後にLambdaに書けばよかったなーーと反省。

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

【Rails】devise gemを使用して複数のモデルを管理する

RailsのdeviseというGemを使用してログイン機能等を作る際、
一般の方と企業でログイン画面や管理を分けたいなという時があると思います。

deviseを使用してWebアプリケーションの制作を行ったことはありますが、
今回初めて複数のモデルで実装を行ったため備忘録として残しておきたいと思います。

環境
Ruby:   2.5.6
Rails:  5.2.4
devise: 4.7.3

docker内で作業しますので、bundle execがついていますが、
docker外の方は外して入力してみてください。

devise導入

1.Gemのインストール

今回はFacebook認証も行いたかったので、deviseomniauth-twitterをGemfileへ追加

Gemfile
gem 'devise'
gem 'omniauth-facebook'

そしてbundle install

2.devise関連のファイル作成

ターミナルで下記コマンドを入力

bundle exec rails g devise:install

以下のような文言が出てくると思います

create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Depending on your application's configuration some manual setup may be required:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

     * Required for all applications. *

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

     * Not required for API-only Applications *

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

     * Not required for API-only Applications *

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

     * Not required *

===============================================================================

それぞれ内容を確認して追加をしていきます。

1.config/environments/development.rbに以下の文言を追加してねという内容。
  言われた通り、デフォルトのURLを記載します。

config/environments/development.rb
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

2.config/routes.rbにrootでアクセスした時(1で設定したURLにアクセスした時)のURLを設定してねという内容
私はまだ作成していなかったので、ここで作成します。

ターミナル
bundle exec rails g controller Posts(コントローラー名) index

 config/routes.rbにてURLを設定

config/routes.rb
Rails.application.routes.draw do
  root 'posts#index'
end

3.app/views/layouts/application.html.erbにflashメッセージを追加してねという内容
  とりあえず記載されているものを書きました。

app/views/layouts/application.html.erb
.
.
.
  <body>
    <p class="notice"><%= notice %></p>
    <p class="alert"><%= alert %></p>

    <%= yield %>
  </body>
</html>

4.viewを生成してねと言われていますが、2パターン作りたいので今は無視します!

devise設定

ログインユーザーを2パターンにするためにconfig/initializers/devise.rbの設定を変更していきます。
元々コメントアウトされているので探してください!

config/initializers/devise.rb(変更前)
.
#config.scoped_views = false
.
.
#config.sign_out_all_scopes = true
.
config/initializers/devise.rb(変更後)
# 複数のmodelでログイン画面を分けるために変更
config.scoped_views = true
# 複数のmodelでをグインしている際、一方をログアウトした時にもう片方もログアウトしてしまうことを防ぐ
config.sign_out_all_scopes = false

deviseモデル作成

今回は一般の方と企業の2パターンを作ろうと思います!

ターミナル
bundle exec rails g devise user
bundle exec rails g devise company

マイグレーションファイルを確認

(モデル名以外同様のファイルが生成されているので、companyモデルのファイルは省略します)

db/migrate/20201112105533_devise_create_users.rb
# frozen_string_literal: true

class DeviseCreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      # t.integer  :sign_in_count, default: 0, null: false
      # t.datetime :current_sign_in_at
      # t.datetime :last_sign_in_at
      # t.string   :current_sign_in_ip
      # t.string   :last_sign_in_ip

      ## Confirmable
      # t.string   :confirmation_token
      # t.datetime :confirmed_at
      # t.datetime :confirmation_sent_at
      # t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at


      t.timestamps null: false
    end

    add_index :users, :email,                unique: true
    add_index :users, :reset_password_token, unique: true
    # add_index :users, :confirmation_token,   unique: true
    # add_index :users, :unlock_token,         unique: true
  end
end

modelファイルを確認

Facebook認証を取り入れるため、:omniauthableomniauth_providers: [:facebook]を追記しました。

models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :omniauthable, omniauth_providers: [:facebook]
end

変更や追加ができたところでbundle exec rails db:migrate

ルーディングの確認

config/routes.rbを確認

config/routes.rb
Rails.application.routes.draw do
  devise_for :companies
  devise_for :users
  root 'postss#index'
end

bundle exec rails routesで確認

Controller#Actionの部分がcompanyとuserで同じになってしまっている。
つまり、controllerが同一になってしまっているので変更する必要がある。
(*Controller#Actionだけ離れてしまいました...
  めんどくさくて直せていないので、右にスライドしてください・・・!)

ターミナル
          Prefix Verb             URI Pattern                                                                          Controller#Action
             new_company_session GET      /companies/sign_in(.:format)                                                            devise/sessions#new
                 company_session POST     /companies/sign_in(.:format)                                                            devise/sessions#create
         destroy_company_session DELETE   /companies/sign_out(.:format)                                                           devise/sessions#destroy
            new_company_password GET      /companies/password/new(.:format)                                                       devise/passwords#new
           edit_company_password GET      /companies/password/edit(.:format)                                                      devise/passwords#edit
                company_password PATCH    /companies/password(.:format)                                                           devise/passwords#update
                                 PUT      /companies/password(.:format)                                                           devise/passwords#update
                                 POST     /companies/password(.:format)                                                           devise/passwords#create
     cancel_company_registration GET      /companies/cancel(.:format)                                                             devise/registrations#cancel
        new_company_registration GET      /companies/sign_up(.:format)                                                            devise/registrations#new
       edit_company_registration GET      /companies/edit(.:format)                                                               devise/registrations#edit
            company_registration PATCH    /companies(.:format)                                                                    devise/registrations#update
                                 PUT      /companies(.:format)                                                                    devise/registrations#update
                                 DELETE   /companies(.:format)                                                                    devise/registrations#destroy
                                 POST     /companies(.:format)                                                                    devise/registrations#create
                new_user_session GET      /users/sign_in(.:format)                                                                 devise/sessions#new
                    user_session POST     /users/sign_in(.:format)                                                                 devise/sessions#create
            destroy_user_session DELETE   /users/sign_out(.:format)                                                                devise/sessions#destroy
user_facebook_omniauth_authorize GET|POST /users/auth/facebook(.:format)                                                           devise/omniauth_callbacks#passthru
 user_facebook_omniauth_callback GET|POST /users/auth/facebook/callback(.:format)                                                  devise/omniauth_callbacks#facebook
               new_user_password GET      /users/password/new(.:format)                                                            devise/passwords#new
              edit_user_password GET      /users/password/edit(.:format)                                                           devise/passwords#edit
                   user_password PATCH    /users/password(.:format)                                                                devise/passwords#update
                                 PUT      /users/password(.:format)                                                                devise/passwords#update
                                 POST     /users/password(.:format)                                                                devise/passwords#create
        cancel_user_registration GET      /users/cancel(.:format)                                                                  devise/registrations#cancel
           new_user_registration GET      /users/sign_up(.:format)                                                                 devise/registrations#new
          edit_user_registration GET      /users/edit(.:format)                                                                    devise/registrations#edit
               user_registration PATCH    /users(.:format)                                                                         devise/registrations#update
                                 PUT      /users(.:format)                                                                         devise/registrations#update
                                 DELETE   /users(.:format)                                                                         devise/registrations#destroy
                                 POST     /users(.:format)                                                                         devise/registrations#create

ルーディング修正

config/routes.rb
devise_for :companies, controllers: {
    sessions:      'companies/sessions',
    passwords:     'companies/passwords',
    registrations: 'companies/registrations'
  }
  devise_for :users, controllers: {
    sessions:           'users/sessions',
    passwords:          'users/passwords',
    registrations:      'users/registrations',
    omniauth_callbacks: 'users/omniauth_callbacks'
  }

もう一度bundle exec rails routesで確認していただくと無事controllerの部分が変更されていると思います!

ビューの作成

最初のrails g devise:installを実行した際に対応しなかった部分です。

ターミナル
bundle exec rails g devise:views users
bundle exec rails g devise:views companies

それぞれファイルが生成されたかと思います!

コントローラーの作成

ターミナル
bundle exec rails generate devise:controllers users
bundle exec rails generate devise:controllers companies

こんな感じの実行結果になるかと思います。

create  app/controllers/users/confirmations_controller.rb
      create  app/controllers/users/passwords_controller.rb
      create  app/controllers/users/registrations_controller.rb
      create  app/controllers/users/sessions_controller.rb
      create  app/controllers/users/unlocks_controller.rb
      create  app/controllers/users/omniauth_callbacks_controller.rb
===============================================================================

Some setup you must do manually if you haven't yet:

  Ensure you have overridden routes for generated controllers in your routes.rb.
  For example:

    Rails.application.routes.draw do
      devise_for :users, controllers: {
        sessions: 'users/sessions'
      }
    end

===============================================================================

下の部分、まさかのエラー!?と思いましたが、エラーじゃないです。(ほっ
controllerがこんな感じだから、追加でroutes.rbに以下のような記述が必要だよ〜
と例を出して教えてくれています。

先ほど設定しているので無視で大丈夫です!

おまけ(omniauth認証を導入する方)

このままだとhttp://localhost:3000/users/sign_inにアクセスしてもエラーになると思います。
undefined method `omniauth_authorize_path' for 〜みたいなやつが。。

Facebook認証の設定についてはここに記載しませんが、
app/views/users/shared/links.html.erbの
omniauth_authorize_path(resource
name, provider)の部分がおかしいです。

ルーディングを確認するとomniauth_authorize_pathというpathはなく、user_facebook_omniauth_authorize_pathとなっているはずなので修正しましょう。

asを使用して名前を変更したわけでもないのになんで・・・?と思いましたが、
理由はよくわからなかったです。最初からなのかな・・・?

とりあえず完成

何はともあれ!とりあえず基本的な設定部分は完成です。

http://localhost:3000/users/sign_inhttp://localhost:3000/companies/sign_in
どちらでアクセスしてもログイン画面が出ると思います!

必要であればカラムを増やしたりカスタマイズしてください!

この記事がどなたかのお役に立てたら嬉しいです。
ありがとうございました!

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

[ Ruby ] 特異メソッドと特異クラス

はじめに

特異クラス、特異メソッドについて、ふと調べてみようと思ったので、その内容をまとめてみます。

特異メソッド

オブジェクト固有のメソッドのことです。
定義するメソッド名の前に、オブジェクト名を書くことで定義できます。
なお、定義する際に、そのオブジェクトが既に存在していないといけません。

class Klass
end

apple = Klass.new
orenge = Klass.new

def apple.tokui_method
  puts "I'm apple"
end

apple.tokui_method
# => I'm apple
orenge.tokui_method
# => undefined method `tokui_method'

もしも定義する際にその指定するオブジェクトが存在していなかった場合、エラーとなります。

class Klass
end

def apple.tokui_method
  puts "I'm apple"
end

apple = Klass.new

apple.tokui_method
# => undefined local variable or method `apple' for main:Object (NameError)

特異メソッド内でsuperを呼ぶと、クラスに定義されている同名のメソッドが呼ばれます。
また、そのメソッドのオーバーライドが出来るという便利な点もあります。

class Klass
  def my_name
    puts "I'm fruits"
  end
end

apple = Klass.new
orenge = Klass.new

def apple.my_name
  super
  puts "I'm apple"
end

apple.my_name
# => I'm fruits
# => I'm apple
orenge.my_name
# => I'm fruits

特異クラス

あるオブジェクトに特異メソッドを定義した際に、そのメソッドが定義されるクラスが特異クラスです。

通常のクラスとは違い、特異クラスはあるオブジェクトだけが使用するクラスです。
そのため、特異クラスからオブジェクトを作成したり、サブクラスを作成することは禁止されています。

オブジェクトの特異クラスを確認するには
Object#singleton_classを使用します。

class Klass
end

obj = Klass.new
# => #<Klass:0x00007f8fb584cc08>

TokuiClass = obj.singleton_class
# => #<Class:#<Klass:0x00007f8fb584cc08>>

TokuiClass.new
# => can't create instance of singleton class (TypeError)

class SubTokuiClass < TokuiClass
end
# => can't make subclass of singleton class (TypeError)

また、前述した特異メソッドは特異クラスに定義されています。
特異メソッドに関しては
singleton_class.method_defined?で確認することができます。

class Klass
end

obj = Klass.new

def obj.tokui_method
  :tokui_method
end

p obj.class.method_defined? :tokui_method
# => false
p obj.singleton_class.method_defined? :tokui_method
# => true

特異クラスが作成されるタイミング

オブジェクトが生成されたタイミングでは、そのオブジェクトの特異クラスは存在していません。
特異クラスは以下の場合に作成されます。

1, 特異メソッドを定義するタイミング
2, 特異クラス定義式を評価したタイミング
3, Object#singleton_classでオブジェクトに対して特異クラスの確認をするタイミング

特異メソッドを定義するタイミング
obj = Klass.new

def obj.tokui_method
  :tokui_method
end
特異クラス定義式を評価したタイミング
class << obj
end
Object#singleton_classでオブジェクトに対して特異クラスの確認をするタイミング

確認しようとしたタイミングで、特異クラスが存在していなければ新たに作成されます。

obj.singleton_class

オブジェクトと特異クラス

特異クラスは、オブジェクトのクラスのサブクラスになります。

class Klass
end

obj = Klass.new
obj.singleton_class.supperclass
# => Klass

特異クラスがあるオブジェクトに対して作成されると、そのオブジェクトは特異クラスのインスタンスになりますが、Rubyの中では
特異クラスのインスタンスであるということは無視されるようになっており、常にオブジェクトのクラスのインスタンスとして扱われます。
Object#instance_of?で引数の直接のインスタンスか確認できるため、これを使用してみます。

obj.instance_of? obj.singleton_class
# => false

obj.instance_of? Klass
# => true

特異クラスをもてないオブジェクト

Rubyで以下のオブジェクトは特異クラスを持つことが出来ません。

  • 数値
  • Symbol
  • true, false, nil
整数とsymbleはエラーが返ってきます
1.singleton_class
# => can't define singleton (TypeError)
:symble.singleton_class
# => can't define singleton (TypeError)
true, false, nil は自身のクラスが特異クラスとして返ってきます
p true.singleton_class
# => TrueClass

p false.singleton_class
# => FalseClass

p nil.singleton_class
# => NilClass
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Amazon Redshift でcliから複数のクエリを投げてみた

Amazon Redshiftで複数クエリを投げる時にめちゃくちゃ苦労したので、まとめてみる。
利用環境はMacです。
前回の記事に引き続いて検証しました〜!

【背景】

  • Athenaで複数のクエリを投げてみました(こちらご参照ください)が、Redshiftも同じ感じで出来そう?
  • 出来るなら検証しちゃった方がいいしやってみよう!!

こんな課題感で手を動かし始めました。

【実際にやったこと/考えていたこと】

  • cliからクエリ投げられる方法を探す
    • 全然見つからない?
  • rubyのgemを使ってみる
    • 何使ったらいけるのかわかりにくい!!
    • 英語のドキュメントでわかりにくい!!

結局二つ目のgemで複数クエリ投げることができましたので、詰まった一つ目と一緒にまとめていきたいと思います〜!
(会社の先輩にとても助けていただきました?‍♂️)

cliからクエリを投げられる方法を探す

公式ドキュメントを参考にcliからawsに接続する方法を色々と探していました。
クラスターの削除や、追加については書いてあるものの、DBを立てて、クエリを投げるとこまで書いてありませんでした。

JSONでスクリプト書いてcurlで送れるだろ〜。どっかにサンプルコード書いてるだろ〜と思っていたので、なかなか調べても出てこなく、どんどん沼にはまっていった気がします。。。

ここで、先輩に一度相談して、"Gemでいいのあると思うから調べてみて〜"とのこと。
全く、考えになかったですが、"Gem redshift"と検索すると何件がヒットしました。そこで"aws-sdk-redshift"というのを見つけました。

rubyのgemを使ってみる

こちらの記事を参考にやってみてました〜!

まずaws-sdkをインストールする

日本語の参考ドキュメントの通り進めていくと(少し違いますが)、まず以下のスクリプトでレスポンスが返ってきました。
ここまででエラーが出たら、クラスターが作成できているか、必要なIAMがアタッチされているかどうかなどこちらの記事を参考にデバックしてみてください。

Redshiftとの接続
require 'aws-sdk'

cluster_identifier = "クラスター識別子"

aws_client = AWS::Redshift.client.new(
        :redshift_endpoint => "エンドポイント",
        :access_key_id => 'xxxxxxxxxxxx',
        :secret_access_key => 'xxxxxxxxxxxxxxx'
)

cluster = aws_client.describe_clusters(
                :cluster_identifier => cluster_identifier
).clusters[0]


dbuser=cluster.master_username
dburl="DBI:Pg:dbname=#{cluster.db_name};host=#{cluster.endpoint.address};port=#{cluster.endpoint.port}"

puts dbuser
puts dburl

よし!じゃあこのまま、クエリを投げよう!!!!(......どうやって???)
となりました。

あまり意味もわからないまま、認証はできた。
あまり意味もわからないが、DBも接続できた??
あまり意味もわからないから、クエリを投げるメソッドがあるのかわからない。。。

となっていました。

aws_client.methods

で、しらみつぶしにメソッド名を見て行ってもそれらしきメソッドもなく、(api_requestsがそれか!!と思いましたが、うまくできませんでした。)

ここでもう一度先輩に聞きに行くことに、、、、
すると"RedshiftDataAPIServiceってのあるけどこれは??"とのこと、、、
なんで気がつかなかったんだ!!

RedshiftDataAPIService見たら、execute_statementとかget_statement_resultある

そこからは早かったです。
先ほどのスクリプトを以下のように書き換えました。

クラスターのdbに対してクエリを投げる
require 'aws-sdk'

aws_client =  Aws::RedshiftDataAPIService::Client.new(
        access_key_id: '********************',
        secret_access_key: '************************',
      )
10.times do |i|
  aws_client.execute_statement({
    cluster_identifier: 'クラスター識別子',
    database: 'DB名',
    db_user: 'マスターユーザー名',
    sql: 'select * from db.table名'
   })
end

すると、、、何の音沙汰もない、、、、
そりゃそうです。これはクエリを投げるためのメソッド。
management consoleに見に行ったら、クエリが実行されてました。

ちなみに、レスポンスも返ってきてます。↓公式ドキュメント参照
image.png

ここで返ってきてるidを取得して、get_statement_resultでクエリの結果も確認することができます〜!!
※レスポンスをparseして、表示するところまで一つのスクリプトで書きたかったのですが、ここはまだ出来ていません。。。
今後やっていきたいと思います!!

まとめ

  • athenaでやった通り進めたらいけると思っていたら、全然方向性が違ったので、大変だった
  • 詰まったときに何で詰まっているのか、何のためにしているのかを明確にすると、方向転換ができる

英語のドキュメントが多く、日本語が少なくて大変だったので、まとめます
引き続き学びがあれば更新していきたいと思います〜:)

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

link_toメソッドでmethod: :deleteにしても、HTTPがGETになってしまう現象

はじめに

 link_toメソッドを使って、削除機能を実装しようとしたときに、つまずいたこととその解決法についてまとめておく。

エラー内容

 「HTTP[GET]を探したけれど、そんなものないよ」みたいな感じのルーティングエラーが出た。

link_toメソッドのHTTPメソッドのデフォルト

 link_toメソッドはHTMLでいうところのaタグの役割なので、ページを遷移させるときに使いことが主になる。そのため、特にmethodを指定しなければ、HTTPメソッドはGETとなる。

method: :deleteにする理由

先に挙げたように、link_toメソッドはデフォルトでGETになっているので、methodを別に指定する必要があるから。

エラーの解決方法

 荒技になるが、link_toメソッドをbutton_toメソッドに変える。多少、デザインが変わるが、機能は意図したものが実装できる。

最後に

 Rails6では、webpackがデフォルトであり、何やらうまく読み込まなくなってしまっているようだった。今まで、このエラーはでなかったのに、オリジナルアプリケーションを作るようになってから、見かけるようになった…。いまだに原因は謎に包まれている。

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

Example title

Example

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

【自分用メモ】Rspecの導入とエラーメッセージ日本語化

はじめに

自分用の備忘録。
毎回手順を確認するのが面倒なので、自分なりのパッケージをまとめてみる。

手順

Rspec

Gemをインストール

Gemfile
# 中略

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  # 追記
  gem 'rspec-rails'
  gem 'factory_bot_rails'
  gem 'faker'
end

# 中略

アプリケーションにRspecをインストール

ターミナル
% rails g rspec:install

rspecファイルの設定

.rspec
--require spec_helper
# 追記
--format documentation

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

Gemをインストール

Gemfile
# 最下部
gem 'rails-i18n'

application.rbを編集

config/application.rb
# 中略

module App
 class Application < Rails::Application
   # Initialize configuration defaults for originally generated Rails version.
   config.load_defaults 6.0

   # 追記
   config.i18n.default_locale = :ja
  # 省略
 end
end

ymlファイル作成(devise)

config/locales/devise.ja.yml => 作成

ymlファイル編集(devise)

以下、コピペ

config/locales/devise.ja.yml
ja:
  activerecord:
    attributes:
      user:
        confirmation_sent_at: パスワード確認送信時刻
        confirmation_token: パスワード確認用トークン
        confirmed_at: パスワード確認時刻
        created_at: 作成日
        current_password: 現在のパスワード
        current_sign_in_at: 現在のログイン時刻
        current_sign_in_ip: 現在のログインIPアドレス
        email: メールアドレス
        encrypted_password: 暗号化パスワード
        failed_attempts: 失敗したログイン試行回数
        last_sign_in_at: 最終ログイン時刻
        last_sign_in_ip: 最終ログインIPアドレス
        locked_at: ロック時刻
        password: パスワード
        password_confirmation: パスワード(確認用)
        remember_created_at: ログイン記憶時刻
        remember_me: ログインを記憶する
        reset_password_sent_at: パスワードリセット送信時刻
        reset_password_token: パスワードリセット用トークン
        sign_in_count: ログイン回数
        unconfirmed_email: 未確認Eメール
        unlock_token: ロック解除用トークン
        updated_at: 更新日
    models:
      user: ユーザ
  devise:
    confirmations:
      confirmed: メールアドレスが確認できました。
      new:
        resend_confirmation_instructions: アカウント確認メール再送
      send_instructions: アカウントの有効化について数分以内にメールでご連絡します。
      send_paranoid_instructions: メールアドレスが登録済みの場合、本人確認用のメールが数分以内に送信されます。
    failure:
      already_authenticated: すでにログインしています。
      inactive: アカウントが有効化されていません。メールに記載された手順にしたがって、アカウントを有効化してください。
      invalid: "%{authentication_keys}またはパスワードが違います。"
      last_attempt: もう一回誤るとアカウントがロックされます。
      locked: アカウントは凍結されています。
      not_found_in_database: "%{authentication_keys}またはパスワードが違います。"
      timeout: セッションがタイムアウトしました。もう一度ログインしてください。
      unauthenticated: アカウント登録もしくはログインしてください。
      unconfirmed: メールアドレスの本人確認が必要です。
    mailer:
      confirmation_instructions:
        action: メールアドレスの確認
        greeting: "%{recipient}様"
        instruction: 以下のリンクをクリックし、メールアドレスの確認手続を完了させてください。
        subject: メールアドレス確認メール
      email_changed:
        greeting: こんにちは、%{recipient}様。
        message: あなたのメール変更(%{email})のお知らせいたします。
        subject: メール変更完了。
      password_change:
        greeting: "%{recipient}様"
        message: パスワードが再設定されたことを通知します。
        subject: パスワードの変更について
      reset_password_instructions:
        action: パスワード変更
        greeting: "%{recipient}様"
        instruction: パスワード再設定の依頼を受けたため、メールを送信しています。下のリンクからパスワードの再設定ができます。
        instruction_2: パスワード再設定の依頼をしていない場合、このメールを無視してください。
        instruction_3: パスワードの再設定は、上のリンクから新しいパスワードを登録するまで完了しません。
        subject: パスワードの再設定について
      unlock_instructions:
        action: アカウントのロック解除
        greeting: "%{recipient}様"
        instruction: アカウントのロックを解除するには下のリンクをクリックしてください。
        message: ログイン失敗が繰り返されたため、アカウントはロックされています。
        subject: アカウントの凍結解除について
    omniauth_callbacks:
      failure: "%{kind} アカウントによる認証に失敗しました。理由:(%{reason})"
      success: "%{kind} アカウントによる認証に成功しました。"
    passwords:
      edit:
        change_my_password: パスワードを変更する
        change_your_password: パスワードを変更
        confirm_new_password: 確認用新しいパスワード
        new_password: 新しいパスワード
      new:
        forgot_your_password: パスワードを忘れましたか?
        send_me_reset_password_instructions: パスワードの再設定方法を送信する
      no_token: このページにはアクセスできません。パスワード再設定メールのリンクからアクセスされた場合には、URL をご確認ください。
      send_instructions: パスワードの再設定について数分以内にメールでご連絡いたします。
      send_paranoid_instructions: メールアドレスが登録済みの場合、パスワード再設定用のメールが数分以内に送信されます。
      updated: パスワードが正しく変更されました。
      updated_not_active: パスワードが正しく変更されました。
    registrations:
      destroyed: アカウントを削除しました。またのご利用をお待ちしております。
      edit:
        are_you_sure: 本当によろしいですか?
        cancel_my_account: アカウント削除
        currently_waiting_confirmation_for_email: "%{email} の確認待ち"
        leave_blank_if_you_don_t_want_to_change_it: 空欄のままなら変更しません
        title: "%{resource}編集"
        unhappy: 気に入りません
        update: 更新
        we_need_your_current_password_to_confirm_your_changes: 変更を反映するには現在のパスワードを入力してください
      new:
        sign_up: アカウント登録
      signed_up: アカウント登録が完了しました。
      signed_up_but_inactive: ログインするためには、アカウントを有効化してください。
      signed_up_but_locked: アカウントが凍結されているためログインできません。
      signed_up_but_unconfirmed: 本人確認用のメールを送信しました。メール内のリンクからアカウントを有効化させてください。
      update_needs_confirmation: アカウント情報を変更しました。変更されたメールアドレスの本人確認のため、本人確認用メールより確認処理をおこなってください。
      updated: アカウント情報を変更しました。
      updated_but_not_signed_in: あなたのアカウントは正常に更新されましたが、パスワードが変更されたため、再度ログインしてください。
    sessions:
      already_signed_out: 既にログアウト済みです。
      new:
        sign_in: ログイン
      signed_in: ログインしました。
      signed_out: ログアウトしました。
    shared:
      links:
        back: 戻る
        didn_t_receive_confirmation_instructions: アカウント確認のメールを受け取っていませんか?
        didn_t_receive_unlock_instructions: アカウントの凍結解除方法のメールを受け取っていませんか?
        forgot_your_password: パスワードを忘れましたか?
        sign_in: ログイン
        sign_in_with_provider: "%{provider}でログイン"
        sign_up: アカウント登録
      minimum_password_length: "(%{count}字以上)"
    unlocks:
      new:
        resend_unlock_instructions: アカウントの凍結解除方法を再送する
      send_instructions: アカウントの凍結解除方法を数分以内にメールでご連絡します。
      send_paranoid_instructions: アカウントが見つかった場合、アカウントの凍結解除方法を数分以内にメールでご連絡します。
      unlocked: アカウントを凍結解除しました。
  errors:
    messages:
      already_confirmed: は既に登録済みです。ログインしてください。
      confirmation_period_expired: の期限が切れました。%{period} までに確認する必要があります。 新しくリクエストしてください。
      expired: の有効期限が切れました。新しくリクエストしてください。
      not_found: は見つかりませんでした。
      not_locked: は凍結されていません。
      not_saved:
        one: エラーが発生したため %{resource} は保存されませんでした。
        other: "%{count} 件のエラーが発生したため %{resource} は保存されませんでした。"

ymlファイル作成(一般)

config/locales/ja.yml => 作成

ymlファイル編集(一般)

config/locales/ja.yml
ja:
  time:
    formats:
      default: "%m/%d %H:%M"
  activerecord:
    attributes:
      モデル①:
        カラム①: 対応する日本語
        カラム②: 対応する日本語
      モデル②:
        カラム①: 対応する日本語
        カラム②: 対応する日本語
  # ActiveModelを使用している場合、続けて追記
 activemodel:
    attributes:
      モデル名:
        カラム名: 対応する日本語

おわりに

毎度なにかしら抜けるのでメモリました。

この一連の設定を自動化するプログラムを書けるようになりたいものです。

✔︎

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

ActiveHashの活用

はじめに

Railsでオリジナルアプリを制作しています。このアプリにActiveHashを適用しました。プルダウン形式でActiveHashで設定したデータを選択できるようにしました。忘れても思い出せるよう書き残します。

※ActiveHashは都道府県名一覧のように変更されないデータを扱います。変更されないデータなので、データベースには直接保存する必要がないです(都道府県毎に用意したidは保存されます)。

開発環境
ruby 2.6.5
Rails 6.0.3.4

目次

1.ActiveHashの導入
2.モデルの準備
3.コントローラーの準備
4.ビューの表示

1.ActiveHashの導入

ActiveHashはGemの1つ。Gemファイルに追記し、ターミナルでインストールする。

Gemfile
gem 'active_hash'
ターミナル
bundle install

2.モデルの準備

ここではday(日数)をActiveHashの対象とする。モデル作成時--skip-migrationを追加するとマイグレーションファイルは作成されない。他にもActiveHashの対象があるなら、その数だけモデルを作成する。

ターミナル
rails g model day --skip-migration

モデル内ではActiveHashを継承するすること。self.dataはハッシュ形式のデータが格納された配列になる。ハッシュ内はidとname(日数)が紐づく。

app/models/day.rb
class day < ActiveHash::Base #←ActiveHashを継承する
 self.data = [
   { id: 1, name: '--' },
   { id: 2, name: '1日' },
   { id: 3, name: '1週間' },
 ]
 end

続いて上記で設定した日数のidをデータベースに保存する設定を行う。ActiveHashが紐づくテーブルとしてarticleを例にする。

2020***********_create_articles.rb
class CreateArticles < ActiveRecord::Migration[6.0]
 def change
   create_table :articles do |t|
     t.string     :title        , null: false
     t.text       :text         , null: false
     t.integer    :day_id       , null: false #ActiveHashのidが保存されるカラム 
     t.timestamps
   end
 end
end

忘れずマイグレーションを行う。モデルのアソシエーションも。

app/model/article
validates :day_id # _idをつける
belongs_to_active_hash :day # _idは不要

3.コントローラーの準備

ストロングパラメータにday_idを追加して、保存できるようにする。

article.controller.rb
:
  def new    
    @article = Article.new
  end

  def create    
    @article = Article.new(article_params)
  end

  private
  def article_params
    params.require(:article).permit(:title, :text, :day_id)
  end

ビューの表示

collection_selectによってプルダウン形式で表示できる。引数は第一から第五まである。

引数
第一引数(保存されるカラム ) day_id
第二引数(オブジェクトの配列) Day.all
第三引数(カラムに保存される項目) id
第四引数(選択肢に表示されるカラム名) name
第五引数(オプション) {}
htmlオプション {class:"day-select"}
<%= f.collection_select(:day_id, Day.all, :id, :name, {}, {class:"day-select"}) %>

以上

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

[Rails] devise の使い方 (備忘録)

はじめに

これまでログイン、ログアウトといった認証系の機能は自前で実装していたのですが、今回ポートフォリオを制作するにあたってdeviseを使っておきたいなと思い、その使い方の備忘録として本記事を残します。

実行環境

この記事は以下の環境で動作確認しています。
ruby 2.7.1
rails 6.0.3
devise 4.7.3

インストール

Gemfileに追記。
後半で日本語化するのでそのgemも入れておきます。

Gemfile
gem 'devise'
gem 'devise-i18n'
gem 'devise-i18n-views'

bundle installを実行。

$ bundle install

deviseの設定

関連ファイルを作成。

$ rails g devise:install

するとファイルが作成され、以下のような英文が表示されます。

Running via Spring preloader in process 5911
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Depending on your application's configuration some manual setup may be required:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

     * Required for all applications. *

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

     * Not required for API-only Applications *

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

     * Not required for API-only Applications *

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

     * Not required *

===============================================================================

1. 環境ファイルにデフォルトのurlオプションを定義します。

config/environments/development.rb
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

2. ルートurlを定義します。

config/routes.rb
root to: 'homes#index'

3. flashを表示させたい場所に以下を記載します。

<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>

4. viewのカスタマイズについては後ほど記載します。

Userモデルの作成

$ rails g devise User

作成されたマイグレーションファイルを見ると、emailとpasswordしかないので追加したいカラムがあれば追記します。追記し終えたらマイグレーションを実行。

$ rails db:migrate

この時点で http://localhost:3000/users/sign_up を開けば新規登録ページが作成されています。
もしカラムの追記を忘れていて後から追加したい場合は以下を実行する。(今回はusernameカラムの追加を想定して行う)

$ rails g migration add_username_to_users username:string

usernameは必ず記入して欲しいので NOT NULL 制約をつけておきます。

db/migrate/XXXXXXXXXXXXXX_add_username_to_users.rb
class AddUsernameToUsers < ActiveRecord::Migration[6.0]
  def change
    add_column :users, :username, :string, null: false
  end
end

deviseに対応したviewの作成

viewのカスタマイズをしたいので以下を実行。

$ rails g devise:views users

viewの編集内容を反映させます。

config/initializers/devise.rb
# 247行目の config.scoped_views = false のコメントアウトを外して true に変更
config.scoped_views = true

sign_upの際にusernameを登録できるようにします。

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
  end
end

コントローラーを作成し、ルーティングを変更する

$ rails g devise:controllers users

コントローラーファイルと英文が表示されます。

Running via Spring preloader in process 9004
      create  app/controllers/users/confirmations_controller.rb
      create  app/controllers/users/passwords_controller.rb
      create  app/controllers/users/registrations_controller.rb
      create  app/controllers/users/sessions_controller.rb
      create  app/controllers/users/unlocks_controller.rb
      create  app/controllers/users/omniauth_callbacks_controller.rb
===============================================================================

Some setup you must do manually if you haven't yet:

  Ensure you have overridden routes for generated controllers in your routes.rb.
  For example:

    Rails.application.routes.draw do
      devise_for :users, controllers: {
        sessions: 'users/sessions'
      }
    end

===============================================================================

ここで現在のルーティングを確かめておきます。

$ rails routes

Prefix               Verb   URI Pattern                          Controller#Action
new_user_session     GET    /users/sign_in(.:format)             devise/sessions#new
user_session         POST   /users/sign_in(.:format)             devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format)            devise/sessions#destroy
...
new_user_registration GET    /users/sign_up(.:format)       devise/registrations#new

このようにController#Actionの部分が devise/registrations,devise/sessionsになっていると、これから定義するメソッドが反映されません。

コントローラーを作成した際に表示された英文に従ってルートをオーバーライドします。

config/routes.rb
devise_for :users, controllers: {
    registrations: 'users/registrations',
    sessions: 'users/sessions'
  }

オーバーライドできたので現在のルーティングを確認します。

$ rails routes

Prefix               Verb   URI Pattern                    Controller#Action
new_user_session     GET    /users/sign_in(.:format)       users/sessions#new
user_session         POST   /users/sign_in(.:format)       users/sessions#create
destroy_user_session DELETE /users/sign_out(.:format)      users/sessions#destroy
...
new_user_registration GET    /users/sign_up(.:format)      users/registrations#new                   

このようになり、コントローラーのカスタマイズができるようになります。
メソッドを定義します。

app/controllers/users/registrations_controller.rb
  # アカウント作成後のリダイレクト先
  def after_sign_up_path_for(resource)
    root_path
  end

  # アカウント編集後のリダイレクト先
  def after_update_path_for(resource)
    root_path
  end
app/controllers/users/sessions_controller.rb
  # ログアウト後のリダイレクト先
  def after_sign_out_path_for(resource)
    root_path
  end

  # ログイン後のリダイレクト先
  def after_sign_in_path_for(resource)
    root_path
  end

これで全てのリダイレクト先がトップページになりました。

日本語化する

まず、このRailsアプリケーションのデフォルトの言語を日本語にします。

config/application.rb
require_relative 'boot'
require 'rails/all'

Bundler.require(*Rails.groups)

module ConnectStudy
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 6.0

    config.i18n.default_locale = :ja # ここを追記
  end
end

devise の日本語翻訳ファイルを生成します。

$ rails g devise:views:locale ja

これで日本語になります。configを変更した際はサーバーの再起動をお忘れなく。

deviseには便利なヘルパーメソッドもたくさん用意されているのでそれらを利用してアプリ開発を効率よく行っていこうと思います。

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

FactoryBot ActiveStorageを使った画像を紐付ける方法

FactoryBotとは

RSpecにテストを効率化するための機能です。
予め値を設定しておき、それに沿ったインスタンスを生成します。

ActiveStorageで画像を紐付けよう

factories/post.rb
FactoryBot.define do
  factory :post do
    #{ } の値が参照されて保存される。
    text {"テキストです"}

    #afterメソッド。Postインスタンスをbuildした後、画像をつける。
    after(:build) do |post|
      post.image.attach(io: File.open('spec/fixtures/test_image.png'), filename: 'test_image.png', content_type: 'image/png')
    end

  end
end

Postインスタンスのimageカラムに画像をつけるよう記述します。
HTTPリクエスト経由で画像を付けない場合は、

io: File.open('画像ファイル場所指定'), filename: 'ファイルの名前', content_type: 'ファイルのタイプ(imageとかtextとか)/拡張子

と記述します。

以上です!

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

[解決]Rails6にVuetifyを導入した時のwebpackerエラー "ActionView::Template::Error Webpacker can't find hello_vue ~"

エラーになった過程

vueをrails6に導入して、vuetifyを追加。→試しにvuetifyのパーツをコピペ。→うまく機能しているかブラウザで確かめるため、rails s→コンパイル時にエラー発生。

エラー内容

ActionView::Template::Error (Webpacker can't find hello_vue in /usr/src/myapp/public/packs/manifest.json. Possible causes:
1. You want to set webpacker.yml value of compile to true for your environment
   unless you are using the `webpack -w` or the webpack-dev-server.
2. webpack has not yet re-run to reflect updates.
3. You have misconfigured Webpacker's config/webpacker.yml file.
4. Your webpack configuration is not creating a manifest.
Your manifest contains:
{
  "application.js": "/packs/js/application-9afcbb5693aa87623e69.js",
  "application.js.map": "/packs/js/application-9afcbb5693aa87623e69.js.map",
  "components/user.js": "/packs/js/components/user-156f569cb5c8b04ee2e1.js",
  "components/user.js.map": "/packs/js/components/user-156f569cb5c8b04ee2e1.js.map",
  "entrypoints": {
    "application": {
      "js": [
        "/packs/js/application-9afcbb5693aa87623e69.js"
      ],
      "js.map": [
        "/packs/js/application-9afcbb5693aa87623e69.js.map"
      ]
    },
    "components/user": {
      "js": [
        "/packs/js/components/user-156f569cb5c8b04ee2e1.js"
      ],
      "js.map": [
        "/packs/js/components/user-156f569cb5c8b04ee2e1.js.map"
      ]
    },
    "main": {
      "js": [
        "/packs/js/main-f6918c73db91592ebf7f.js"
      ],
      "js.map": [
        "/packs/js/main-f6918c73db91592ebf7f.js.map"
      ]
    }
  },
  "main.js": "/packs/js/main-f6918c73db91592ebf7f.js",
  "main.js.map": "/packs/js/main-f6918c73db91592ebf7f.js.map"
}
):
    11: 
    12:   <body>
    13:     <%= yield %>
    14:     <%= javascript_pack_tag 'hello_vue' %>
    15:   </body>
    16: </html>

app/views/layouts/application.html.erb:14
^C- Gracefully stopping, waiting for requests to finish
=== puma shutdown: 2020-11-12 02:56:13 +0000 ===
- Goodbye!

ここにも書いてあるが、→https://github.com/rails/webpacker#vue
下のコマンドを上から実行していくと、エラーが解決しました。

./bin/rails webpacker:install
./bin/rails webpacker:install:vue
bin/webpack
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubyでreturnを省略する際に気をつけること

返却前の処理に気をつけると良い。

example

例えば、以下のようなメソッドを実装する場合、

p sample_method()
# => { 'hoge' => 0, 'piyo' => 0 }

返却前の処理を誤って記述してしまうと、returnを利用する場合は構文エラーを出してくれるが、

def sample_method
  result = { 'hoge' => 0 }

  # 1の後に間違ってカンマ","をつけてしまった
  result['piyo'] = 1,
  return result
end

# =>
# SyntaxError (xxx:nn: void value expression)
#   return result
#   ^~~~~~
# xxx:nn: syntax error, unexpected local variable or method, expecting `end'
#   return result
#          ^~~~~~

returnを省略する場合は意図しない値が返ってきてしまう場合がある。

def sample_method
  result = { 'hoge' => 0 }

  # 1の後に間違ってカンマ","をつけてしまった
  result['piyo'] = 1,
  result
end

p sample_method()
# => [1, {"hoge"=>0, "piyo"=>[...]}]

Rubyとしては正しい構文であるため、エラーは発生しない。

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

【Ruby】anemoneとnokogiriでクローラーを作ってみた。

システム開発にあたり、他のWEBページから情報を取得する必要があったので、クローラーを作成しました。

 最初に考えたこと

私がやろうとしていたことは、他のWEBページから情報を取得し、現在作成中のアプリのDBに保存することでした。ということで、なんとなく「情報を取得」ってことはスクレイピングか!という感じで意気込んでいました・・・。

 調査を開始し、分かったこと

自分がやろうとしていたことは、確かにスクレイピング。しかしながら、その情報を取得するためには、まずクローラーと呼ばれるものを作成しなければならないことが判明しました。

クローラーとは?

一方クローラーは、Webページ内にある全てのリンクを巡回して、深堀りしながら目的の情報を取得する方法です。この行為自体はクローリングと呼ばれます。
クローラーでリンクを探す際にはもちろんスクレイピングをしてHTMLのタグを解析して、リンク先を取得します。

http://tech.feedforce.jp/anemone_crawler.html

スクレイピングとは?

スクレイピングとは、WebページのHTMLを解析してデータを抽出することです。

webdesign-3411373_640.jpg

要するに、
●スクレイピングは1つのページに情報が集まっている場合に使える。
●クローラーはWEBサイト内を巡回してくれる。

ということで、クローラーを作成し→その中にスクレイピングに関するコードを記述する→DBに保存する記述を書くという流れが見えてきました。

完成したソースコード

# ruby gemを使用 nokogiri anemoneを使えるようにした
require 'nokogiri'
require 'anemone'
require 'pry'
# 巡回起点となるURL
URL = 'https://********/********'.freeze

area_urls = []
prefecture_urls = []
city_urls = []
# サイト内を巡回する記述
Anemone.crawl(URL, depth_limit: 0, delay: 1) do |anemone|
  anemone.focus_crawl do |page|
    page.links.keep_if do |link|
      link.to_s.match(%r{*********/[0-9]{1,2}})
    end
    page.links.each do |link|
      area_urls << link
    end
  end
end

area_urls.each do |area|
  Anemone.crawl(area, depth_limit: 0, delay: 1) do |anemone|
    anemone.focus_crawl do |page|
      page.links.keep_if do |link|
        link.to_s.match(%r{**********/[0-9]{1,2}/[0-9]{5}})
      end
      page.links.each do |link|
        prefecture_urls << link
      end
    end
  end
end

prefecture_urls.each do |prefecture|
  Anemone.crawl(prefecture, depth_limit: 1, delay: 1, skip_query_strings: true) do |anemone|
    anemone.focus_crawl do |page|
      page.links.keep_if do |link|
        link.to_s.match(%r{**********/[0-9]{1,2}/[0-9]{5}/[0-9]})
      end
      page.links.each do |link|
        city_urls << link
      end
    end

    PATTERN = %r[**********/[0-9]{1,2}/[0-9]{5}/[0-9]].freeze

    anemone.on_pages_like(PATTERN) do |page|
      url = page.url.to_s

      str = url.to_s

      html = URI.parse(url).open
      # ここからスクレイピングの記述
      doc = Nokogiri::HTML.parse(html, nil, 'UTF-8')
# XpathでHTMLを指定
      name = doc.xpath('/html/body/div[4]/div/div[2]/div[1]/h1').text
      pos = doc.xpath('/html/body/div[4]/div/div[2]/table[1]/tbody/tr[3]/td/text()[1]').text
      post = pos.strip
      postcode = post.match(/[0-9]{7}/)
      add = doc.xpath('/html/body/div[4]/div/div[2]/table[1]/tbody/tr[3]/td/text()[2]').text
      address = add.strip
      tel = doc.xpath('/html/body/div[4]/div/div[2]/table[1]/tbody/tr[4]/td').text
      fax = doc.xpath('/html/body/div[4]/div/div[2]/table[1]/tbody/tr[5]/td').text
      staff_number = doc.xpath('/html/body/div[4]/div/div[2]/table[4]/tbody/tr[1]/td/p').text
      company = doc.xpath('/html/body/div[4]/div/div[2]/table[5]/tbody/tr[2]/td').text
      office_url = doc.xpath('/html/body/div[4]/div/div[2]/table[1]/tbody/tr[6]/td/a').text
      # 正規表現でURLから5桁の数字を抜き出す
      if str =~ %r{/(\d{5})(/|$)}
        city_number = Regexp.last_match(1)
        p Regexp.last_match(1)
      end
# インスタンスを作成し、スクレイピングで取得した情報をDBに保存、その際にバリデーションを無視する。
      offices = Office.new(name: name,
                           postcode: postcode,
                           tel: tel,
                           fax: fax,
                           address: address,
                           staff_number: staff_number,
                           company: company,
                           url: office_url,
                           city_number: city_number)
      offices.save(validate: false)
    end
  end
end


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

マルチスケールシミュレーション特論:第 5 回をまとめてみた

ruby-2.5.5p157

ruby 構文(hello world)

はじめに

どんなプログラミング言語もまず始めは hello world から始めるものなので hello world を通して様々な出力用の関数を覚えていく

Strings を打ち出す方法

まず初心者の人は基本として以下のどれかを覚えておけばよい

  • print: 改行が必要
  • puts: 自動改行をしてくれる
  • p: coding の最中に debug がわりに打ち出すとき
  • pp: p の pretty print, require 'pp'が必要
  • printf: format を整えるときに便利

上記の中で私はよく python を使うので慣れている、~print~ を使う事にする

print の使い方について

print には改行が必要なので以下のように改行用の文字(\n)が必要となる

print "Hello " + ARGV[0] + "\n"

  • source ~/Downloads/git/grad_members_20f/members/taiseiyo/memos/class5.org
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rake

rake

https://qiita.com/daddygongon/items/1c2d6d2895333ccf5e62

rakeはmakeやantのruby版

system call

system 'rake -T' みたいな書き方

# frozen_string_literal: true

task :default do
  system 'rake -T'
  exit
end

desc 'hello NAME'
task :hello do
  name = ARGV[1]
  puts "Hello #{name}!"
  exit
end

  • source ~/go/src/github.com/TeamNishitani/grad_members_20f/members/iPolyomino/c8_rake.org
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby On Rails】createアクションとdestroyアクションにおいて、redirect_to action: :showができない(使えない)場合の緊急対策

備忘録です。
閲覧いただきありがとうございます。
走り書きのため、説明や記述に間違いなどあればご指摘お願いいたします。

背景

redirect_toで、action: :アクション名を指定してあげることで、そのコントローラー内のアクションを呼び出し実行することができることを学びました。

その学びを生かして、updateされた場合(つまり、編集が更新された場合)はredirect_to action: :showと記述することでshowアクションをリダイレクトすることができました。

  def update
    if @hoge.update(hoge_params)
      redirect_to action: :show
    else
      render :edit
    end
  end

問題点

しかし、createとdestroyアクションで、redirect_to action: :show ではエラーが出てしまいました。

  def create
    @hoge = Hoge.new(hoge_params)
    if @hoge.save
      redirect_to action: :show
    else
      render :new
    end
  end

(中略)

  def destroy
    if @hoge.destroy
      redirect_to action: :show
    else
      render :show
    end
  end

エラー文

ActionController::UrlGenerationError in HogesController#create
No route matches {:action=>"show", :controller=>"hoges"}

対策

rails routesでルーティングを検索し、Prefixのパスを記述し、必要であればkeyを渡してあげました。

  def create
    @hoge = Hoge.new(hoge_params)
    if @hoge.save
      redirect_to hoge_path(current_user.id)
    else
      render :new
    end
  end

(中略)

  def destroy
    if @hoge.destroy
      redirect_to hoge_path(current_user.id)
    else
      render :show
    end
  end

この様にすることで、createアクションで新規作成を行った場合や、destroyアクションで削除を行った後に、showと同じ画面へ遷移できました。

※以上の対策はあくまで緊急回避策であると考えています。(私が学習不足のため)

今後学習すべきこと

なぜ・何が原因で action: :showでリダイレクトできなかったのか、処理の流れを把握できる様にしていくこと。

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

Q.エレベーター(Ruby編)

エレベーターの階数計算の問題(Ruby編)

問題

エレベーターが何階分の距離を動いたか計算するプログラムを完成させてください。
ただし、エレベーターは最初は必ず 1 階にいるものとします。

1階から3階へ → 2階分移動したことになるので合計2階分
3階から1階へ → 2階分移動したことになるので合計4階分
1階から4階へ → 3階分移動したことになるので合計7階分

入力される値

入力は以下のフォーマットで与えられます。

N
f_1
...
f_N
・1 行目にログの行数を示す整数 N が入力が与えられます。
・続く N 行にエレベーターが止まった階 f_i (1 ≦ i ≦ N) が整数で順に入力されます。
・入力は合計で N+1 行であり、最終行の末尾に改行が 1 つ入ります。

期待する出力

エレベーターが何階分を動いたかを整数で出力してください。

入力例1

3
3
1
4

出力例1

7

私の答え(有志のサイトをみて参考にしました)

n = gets.to_i
i = 1
s = 0
n.times {
    a = gets.to_i
    s += (a - i).abs
    i = a
}
puts s

これで出力結果に間違いはないのですが、{}の中身がいまいち理解できていませんので記事にしました。n.timesで任意の入力値分繰り返される訳ですが6行目のs += (a - i).absがなぜこうなるのかは分かりませんでした。仮に任意の数を全て当てはめてみると、「0 += (3 - 1).abs」となりました。全く意味不明です。また、7行目のi = aというのは当てはめると 1 = 3 みたいになるのですがなぜこうなるのだろう。今回のように任意の入力値がいくつあるかわからない場合のgets.to_iを繰り返す処理をかなり調べてみたが該当サイトはなかなか少なく、初学者の私にとっては難しいコードでした。一つ一つのメソッドは分かるが、プログラミング脳になっていないせいか、今回の6.7行目のようなコードが自分の知識だけではまだまだ書けないという事が分かりました。でも分からないからそこに楽しさがあるという事も。

以上!

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

【Rails】テーブルの作成、カラムの追加、カラムの型の変更方法

はじめに

ポートフォリオを作成していて、あとからカラムを追加したいときや、最初に設定したカラムの型を変更したいときに、どうすればよいのか分からなかったことがあったので、初学者なりに初学者がみてもわかりやすいようにまとめました。
(最初は既にあるマイグレーションファイルに直接追加や変更を加えればよいと思っていました。しかしそれは正しくないので、新たに別のマイグレーションファイルを作成して追加や変更する方法を記述していきます。)

モデルとテーブルの作成

下記のコマンドによりモデルを作成すると、モデルと一緒にこのモデルが担当するテーブルを作成するためのマイグレーションファイルが自動で作成されます。

$ rails g model [モデル名] [カラム名]:[カラムの型]

例えば、Userモデルを作成したい場合、[モデル名]にUser、[カラム名:カラムの型]にはname:string email:stringを指定します。コマンドは以下のようになります。

$ rails g model User name:string email:string

コマンドを実行すると以下のようなマイグレーションファイルが作成されます。

db/migrate/XXXXXXXXXXXXXX_create_users.rb
class CreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      t.string :name
      t.string :email

      t.timestamps
    end
  end
end

上記ファイルが生成されたのを確認し、次のコマンドでマイグレーションを実行します。

$ rails db:migrate

これでUsersテーブルが作成されました。

カラムの追加

既に作成したテーブルにカラムを追加したい場合は、既存のマイグレーションファイルに直接書き込むのではなく、新たにマイグレーションを作成して追加します。

カラムを追加する為のマイグレーションファイルの作成は次のコマンドになります。

$ rails g migration Add[カラム名]To[テーブル名] [カラム名]:[カラム型]

例えば既にあるusersテーブルにintroductionカラム(text型)を追加したい場合は以下になります。

$ rails g migration AddIntroductionToUsers introduction:text

コマンドを実行すると以下のようなマイグレーションファイルが作成されます。

db/migrate/XXXXXXXXXXXXXX_add_introduction_to_users.rb
class AddIntroductionToUsers < ActiveRecord::Migration[6.0]
  def change
    add_column :users, :introduction, :text
  end
end

上記ファイルが生成されたのを確認し、次のコマンドでマイグレーションを実行します。

$ rails db:migrate

これでusersテーブルにintroductionカラム(text型)が追加されました。

カラムの型の変更

既にあるテーブルのカラムの型を変えたいときは、カラム追加と似た手順で変更することができます。

カラムの型を変更する為のマイグレーションファイルの作成は次のコマンドになります。

$ rails g migration change_data_[カラム名]_to_[テーブル名]

例えば既にあるproductionsテーブルのmaterialカラムの型を変更したい場合は以下になります。

$ rails g migration change_data_material_to_productions

コマンドを実行するとマイグレーションファイルが作成されるので、変更したいカラムの型を追記します。
例えば、productionsテーブルのmaterialカラムの型をinteger型に変更したい場合は以下のように追記します。

db/migrate/XXXXXXXXXXXXXX_change_data_material_to_productions.rb
class ChangeDataMaterialToProductions < ActiveRecord::Migration[6.0]
<!-- ***** 以下を追加 ***** -->
  def change
    change_column :productions, :material, :integer
  end
<!-- ***** 以上を追加 ***** -->
end

追記が完了したら、次のコマンドでマイグレーションを実行します。

$ rails db:migrate

これでproductionsテーブルのmaterialカラムの型がinteger型に変更されました。

最後に

この記事は初学者がポートフォリオ作成中に学んだ事を初めてQiitaにまとめました。

内容的に間違いがあればぜひコメントいただけると嬉しいです。

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

[Rails]バリデーションのエラーメッセージを非同期通信で実装してみた!

Railsと日々格闘している「超」がつく初心者です。
自分自身の知識の整理のために、共有します。

はじめに

先日、Railsでの非同期通信の実装を学んだのですが、自分の中で消化し切れていない部分があったので、理解を深めるためにも、アウトプットします!
ユーザーオススメの本を投稿するサイトを想定しており、投稿された本に対して、コメントができます。
 ※コメント機能の非同期通信自体は、このページではあまり解説していません。

今回は、コメント欄を空欄で送信ボタンを押してしまった時に、エラーメッセージがコメント欄の真上に出るようにして、かつ、エラーメッセージ自体を非同期通信で実装してみよう、というものです。
それでは早速いきましょう!

バリデーション

models/comment.rb
class BookComment < ApplicationRecord

  belongs_to :user  #Userモデルに紐付け
  belongs_to :book  #Bookモデルに紐付け

  validates :body, presence: true, length: {maximum: 150}
end

コメントモデル内にて、presence: trueを設定したことにより、空欄での投稿を禁止しました。
ついでに、length: {maximum: 150}も併せて設定しています。

さっそく、コントローラーを確認していきましょう!

Commentsのコントローラー

comments_controller.rb
class BookCommentsController < ApplicationController
  before_action :authenticate_user!  #ログイン済ユーザーのみにアクセスを許可する

  def create
    @book = Book.find(params[:book_id])
    @comment = Comment.new(comment_params)  #このタイミングでバリデーションチェックがかかる!
    @comment.book_id = @book.id
    @comment.user_id = current_user.id
    unless @comment.save  #@commentがsaveできなかった場合、
      render 'error'      #comments/error.js.erbを呼び出している(後述)
    end
  end

  private
  def comment_params
    params.require(:comment).permit(:comment)
  end
end

パラメーターを通ってきた値を使用して、newメソッドとsaveメソッドでデータベースに登録しています。
その際に、外部キーであるbook_idとuser_idはパラメーターでは入手ができないので、このタイミングで設定をしてあげています。
まあ、ここまでは大丈夫ですかね。

ここで大事なのは、バリデーションチェックはデータベースに保存される直前にされるので、エラー文で取得するインスタンス変数は
@comment = Comment.new(comment_params)
であるということです。
つまり、パラメータを通過してきた値それ自身に対して、エラーを含んでいるかどうかをチェックしているのです。

続いては、コメント欄はBookの詳細ページに入っているので、Booksのコントローラを確認しましょう!

Booksのコントローラー

books_controller.rb
class BookController < ApplicationController
  before_action :authenticate_user!  #ログイン済ユーザーのみにアクセスを許可する

  def show
    @book = Book.find(params[:id])
    @comment = Comment.new  #Commentsコントローラーに値を渡す為のnewメソッド
  end
end

ここも特に問題ないでしょう!
折り返し地点に到達しました。
このペースで、Bookの詳細ページを確認していきましょう!

Booksのshowページ

app/views/books/show.html.erb
  <div id="comments_error">
    <%= render 'layouts/errors', model: @comment %>
  </div>

  <%= form_with model:[@book,@comment] do |f| %>
    <%= f.text_area :comment %>
    <%= f.submit '送信'%>
  <% end %>

前半のcomments_errorの部分に、layoutsの_errors.html.erbをrenderで呼び出しています。

また、form_withを利用して、コメント入力欄を設けているのですが、非同期通信を設定したいので、local:trueは記述せずにおきます。
尚、form_withの場合はデフォルトで非同期通信になるので、remote: trueをあえて記述する必要はありません。

エラーメッセージのパーシャル部分

app/views/layouts/_errors.html.erb
<% if model.errors.any? %>
  <div id="error_explanation">
    <h3>
      <%= pluralize(obj.errors.count, "error") %> prohibited this model from being saved:
    </h3>

    <ul>
      <% model.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>

Booksのshowページからrenderで呼び出していたのを覚えていますか。
いよいよ、エラーメッセージの登場です。
errors.full_messagesは全てのエラーメッセージを配列で取得しています。
複数のエラーに引っかかっていることも想定されるので、eachメソッドでループ処理をかけています。
このエラー文はデフォルトで入っているものなので、コメント欄以外にも様々な場面で利用できます。

エラーメッセージの非同期通信で使用するjsファイル

app/views/comments/error.js.erb
$("#comments_error").html("<%= j(render 'layouts/errors', model: @comment) %>");

books/show.html.erbの中で、id="comments_error"の箇所を書き換える処理になります。
$("#comments_error")id = "comments_error"をターゲットとし、render 'layouts/errors'で指定しているlayouts/_errors.html.erbの内容で書き換えています。

なお、ここでmodelに渡している@commentですが、これはどこで定義しているものか分かりますか?
jsファイルは、Commentsコントローラーで呼び出していましたね。
つまり、Commentsコントローラー内の、createアクションで定義している、
@comment = Comment.new(comment_params)
layouts/_errors.html.erbに渡しているのです。

う〜ん、ややこしい!!

(補足)コメント機能自体のjsファイルも記載しておきます

app/views/comments/create.js.erb
$(".comments").html("<%= j(render 'comments/index', book: @book) %>");
$("#comment_comment").val("");

画面のイメージ図

非同期通信を実装したことにより、
image.png
このまま、空欄でコメントを送信しようとすると、
image.png
と、目論見通り怒られてしまいました。
ということはこれで、非同期通信を利用したエラーメッセージの完成!
メッセージ文を日本語に変換したりもできるのですが、誌面の都合上、またの機会に。

おわりに

非同期通信は、コントローラーとか、ページ間遷移とかが多くって、非常にこんがらがりますよね。
何度か読み返してもらえれば、理解に近づけるかと思います。
自分の中で、処理の流れを腹落ちさせれば、実装にかかる時間をどんどん短く出来るかもしれません。
拙文失礼いたしました。
一緒に勉強頑張りましょう!

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

Rails でフォーム送信時のプルダウンメニューの項目をCSV インポートしてDB のデータから表示したい

はじめに

Rails でフォーム送信時のプルダウンメニューの項目をCSV インポートしてDB のデータを使って表示する為の備忘録です。

環境

  • macOS 10.15.6
  • Ruby 2.5.7
  • Rails 5.2.3
  • rspec-rails 4.0.1
  • capybara 3.32.2

参考URL

CSV インポート関連
https://qiita.com/Ryuta1346/items/c21cb70b9879c66c8639
https://qiita.com/SoarTec-lab/items/50e046ea2a2764c12c21
https://docs.ruby-lang.org/ja/latest/class/CSV.html
https://qiita.com/3yatsu/items/416411c0a8f696dbf99e
https://qiita.com/rllllho/items/672e336a03335cba6b34

プルダウンメニュー関連
https://qiita.com/HrsUed/items/56677d6c266d8a53ffa7
https://qiita.com/kawakami_shotaro/items/11a677bf34136cb7686d
https://qiita.com/colorrabbit/items/b58888506e41d1370fd1
https://crieit.net/posts/Rails-collection-select
https://qiita.com/_akira19/items/c218186983f444c2d794

国コード一覧CSV
https://qiita.com/tao_s/items/3yy2b90a2751bfbdd585ea

目標

  1. プルダウンメニューの選択肢をCSV インポートする
  2. プルダウンメニューの選択項目をDB のデータを使い表示する

見た目のイメージです↓
form1.png

プルダウンメニューの選択肢はDB に保存しているカラムの情報を使って表示します↓
form2.png

実装

CSV インポートとフォームのプルダウン化を分けて解説します。

1. プルダウンメニューの選択肢をCSV インポートする

  1. 国名一覧保存用にCountry モデル作成
  2. db/seeds.rb にインポート処理を追加
  3. rails コマンドでインポート処理を実行

Ruby のCSV ライブラリを使用してインポート処理を行います。
今回は以下のようなCSV から国名一覧をインポートしました。
作成したCSV ファイルはルートディレクトリに追加しました。

country.csv
番号,国・地域名,ISO 3166-1に於ける英語名,数,三字,二字,場所,各行政区分
1,アイスランド,Iceland,352,ISL,IS,北ヨーロッパ,ISO 3166-2:IS
2,アイルランド,Ireland,372,IRL,IE,西ヨーロッパ,ISO 3166-2:IE

CSV は国コード一覧CSV を使わせて頂きました。

1. Country モデル作成

下記のようなモデルを作成しました。
region カラムは今回は使っていません。

attribute type
country_name string
region string
# Country モデル作成
$ rails g model Country country_name:string region:string

2. インポート処理を追加

インポート処理はseeds.rb に追記しました。
別途ファイルを作成しrunner コマンドで実行する方法もあるようです。

seeds.rb
require "csv"

# CSV ファイルへのパスは絶対パスで指定
CSV.foreach("country.csv", headers: true) do |row|
  Country.create!(
    country_name: row["国・地域名"],
    region: row["場所"]
  )
end

3. インポート処理を実行

rails コマンドでCSV インポートを実行します。
seed ファイルに他の処理も書いていたので今回はDB 内を全削除してインポートし直しました。

# CSV をインポートしてDB に保存する場合はこれだけ
$ rails db:seed

# DB を消去して全て入れ直す
$ rails db:migrate:reset
$ rails db:seed

# rails コンソールでインポートされたか確認
$ rails c
# インポートした国名の件数を確認
> Country.count
249

2. プルダウンメニューの選択項目をDB のデータを使い表示する

新規投稿時のフォーム送信のView ファイルを修正します。

view/model_names/new.html.erb
# 修正前
<%= form_with model: @model_name do |f| %>
  <%= f.label :country %>
  <%= f.text_field :country %>

  <%= f.submit "送信" %>
<% end %>
view/model_names/new.html.erb
# 修正後
<%= form_with model: @model_name do |f| %>
  <%= f.label :country %>
  <%= f.collection_select :country, Country.all, :id, :country_name, prompt: "国を選択してください" %>

  <%= f.submit "送信" %>
<% end %>
# collection_select の文法
<%= f.collection_select <保存先のカラム名>, <表示用の配列データ>, <保存する値のカラム名>,  <表示用のカラム名>, <オプション> %>
  • 保存先のカラム名: country
  • 表示用の配列データ: Country.all
  • 保存する値のカラム名: id
  • 表示用のカラム名: country_name
  • オプション: prompt オプションで国を選択してくださいを表示

collection_select の使い方についてはこちら解説が非常に分かりやすいです。

学び

  • 検索などその後の処理も考慮してインポートを行う
  • 選択肢が縦に長くなってしまうので、階層を持たせるなどして使いやすさを考慮した使用に変更したい
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rbenv とRubyのバージョンが違って対処した方法

最近プログラミングを始めたばかりの私ですがRubyを新しいものにアップデートしようとして困った点と解決した方法を記しておきたいと思います。

環境はMacBookPro OS Catalina。
Rubyの元々入っていたバージョンは2.6.3で2.7.2にアップデートを試みた時でした。

Rubyのアップデートコマンドから2.7.2をインストールしたはずでrbenvから

rbenv version

と入れてバージョンを見ると、

2.7.2 (set by /Users/○○○(ユーザー名)/.ruby-version) 

と出るのですが、

ruby -v

入れると、

ruby 2.6.3p62

の文字が、、、。

いろいろなサイトを見ると

which ruby
rbenv global 2.7.2

などと入れても一向に変わらず。同じように困っている人の記事から打ち込んでみるとターミナルを開いている間は一時的に直っても閉じて再びバージョンを確認すると2.6.3に戻っている、、、。

そんな時に役立ったのがこちらのコードでした。

echo 'eval "$(rbenv init -)"' >>  ~/.zshrc

からの

source ~/.zshrc

からの

rbenv global 2.7.2

と入れてみました。
確認してみると、

ruby 2.7.2p137

の文字が!

恐る恐るターミナルを閉じて再度開いて

ruby -v

と入れてみると

ruby 2.7.2p137

の文字が出ました!同じ現象でお困りの方はぜひ試してみて下さい。

参考:
Progate: "Rubyの開発環境を用意しよう!"

Progateさんのこちらのコードを参考に解決させていただきました。

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

【Rails】Googleアナリティクスを導入する方法【簡単】

今回開発し、リリース間近のWebサービスでデータ収集するために、Googleアナリティスクスを導入したのでその方法を紹介します。
google-analytics-railsというgemがありそちらを使う方法もあるのですが、githubで見てみると2017年の10月あたりで更新が止まっており(一応先月にReadmeは更新されてた)、不安だったので今回はgem無しで導入しました。

【前提条件】
・Googleアナリティクスに登録していること。(登録方法はこちら

導入方法

Googleアナリティクス用の部分テンプレートを用意し、headタグで読み込むだけです。

layauts/_google_analytics.html.haml
%script{async: "", src: "https://www.googletagmanager.com/gtag/js?id=トラッキングID"}
:javascript
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'トラッキングID');
  if (#{raw current_user.to_json}) {
    gtag('set', {'user_id': #{raw current_user.to_json}.id});
  }
application.html.haml
!!!
%html
  %head
    %meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}
    = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
    = javascript_pack_tag 'application', 'data-turbolinks-track': 'reload'
    - if Rails.env.production?
      = render 'layouts/google_analytics'

ここでポイントになるのが、最後のif 文で、これはログインしている場合はcurrent_userをjsonに変換してデータを渡して上げているという点です。
また、エスケープ処理を回避させるためにActionView::Helpers::OutputSafetyHelperのrawメソッドを使っています。html_safeでも同じことができますが、nilだった場合に例外が発生してしまうのでrawメソッドが推奨されているようです。(Railsガイドを見てみると、To insert something verbatim use the raw helper rather tha calling html_safe:とあります。)

参考

https://qiita.com/t1gert1ger/items/b9a197e2d85050b9d7d6

最後まで読んでいただきありがとうございます!

日々学んだことをアウトプットしてます!何かのお役に立てれば幸いです。ご指摘などあればコメントいただけますと幸いです。

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

【Ruby】gsubメソッドとsubメソッドの使い方

はじめに

Ruby学習用にアプトプットさせていただきます。
今回は「gsubメソッド」と「subメソッド」を用いた文字の置換え方法をご紹介します。

gsubメソッド

gsubメソッドを使用することで、マッチした部分を全て置換えることができます。

n = gets ←(今回はgetsにtest-testと入力してみた)
m = n.gsub("test","hoge")
=> hoge-hoge(test-testがhoge-hogeに置換わった)

subメソッド

subメソッドを使用することで、最初にマッチした部分のみ置換えることができます。

n = gets ←(今回はgetsにtest-testと入力してみた)
m = n.sub("test","hoge")
=> hoge-test(test-testがhoge-testに置換わった)

【応用】gsubメソッドでマッチした部分をすべて置換て複数のパターンを置換

s = gets ← (今回はgetsにPAIZAと入力)
n = s.gsub(/A|E|G|I|O|S|Z/,"A" => 4,"E" => 3,"G"=>6,"I"=>1,"O"=>0,"S"=>5,"Z"=>2)
>> P4124

第一引数でマッチした正規表現に該当した部分を第二引数で置換えている

応用まとめ

正規表現を使わない場合

文字列.gsub(置換したい文字列, 置換後の文字列)
>> 置換え後の文字列

正規表現を使う場合

文字列.gsub(/正規表現/, 正規表現に該当した箇所を置換した後の文字列)
>> 正規表現に該当した箇所を置換した後の文字列
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む