- 投稿日:2020-11-12T23:48:21+09:00
AWS SDK for RubyでS3オブジェクトサイズの取得
HLS形式の動画サイズ取得の為に使いました!
※オブジェクトデータ1000件以上を想定しています。
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に書けばよかったなーーと反省。
- 投稿日:2020-11-12T22:55:29+09:00
【Rails】devise gemを使用して複数のモデルを管理する
RailsのdeviseというGemを使用してログイン機能等を作る際、
一般の方と企業でログイン画面や管理を分けたいなという時があると思います。deviseを使用してWebアプリケーションの制作を行ったことはありますが、
今回初めて複数のモデルで実装を行ったため備忘録として残しておきたいと思います。環境Ruby: 2.5.6 Rails: 5.2.4 devise: 4.7.3docker内で作業しますので、
bundle execがついていますが、
docker外の方は外して入力してみてください。devise導入
1.Gemのインストール
今回はFacebook認証も行いたかったので、
deviseとomniauth-twitterをGemfileへ追加Gemfilegem 'devise' gem 'omniauth-facebook'そして
bundle install2.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.rbconfig.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.rbRails.application.routes.draw do root 'posts#index' end3.
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 = falsedeviseモデル作成
今回は一般の方と企業の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 endmodelファイルを確認
Facebook認証を取り入れるため、
:omniauthableとomniauth_providers: [:facebook]を追記しました。models/user.rbclass 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.rbRails.application.routes.draw do devise_for :companies devise_for :users root 'postss#index' endbundle 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.rbdevise_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(resourcename, provider)の部分がおかしいです。ルーディングを確認すると
omniauth_authorize_pathというpathはなく、user_facebook_omniauth_authorize_pathとなっているはずなので修正しましょう。asを使用して名前を変更したわけでもないのになんで・・・?と思いましたが、
理由はよくわからなかったです。最初からなのかな・・・?とりあえず完成
何はともあれ!とりあえず基本的な設定部分は完成です。
http://localhost:3000/users/sign_inとhttp://localhost:3000/companies/sign_in
どちらでアクセスしてもログイン画面が出ると思います!必要であればカラムを増やしたりカスタマイズしてください!
この記事がどなたかのお役に立てたら嬉しいです。
ありがとうございました!
- 投稿日:2020-11-12T22:42:14+09:00
[ 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
- 投稿日:2020-11-12T21:21:08+09:00
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に見に行ったら、クエリが実行されてました。ちなみに、レスポンスも返ってきてます。↓公式ドキュメント参照
ここで返ってきてるidを取得して、get_statement_resultでクエリの結果も確認することができます〜!!
※レスポンスをparseして、表示するところまで一つのスクリプトで書きたかったのですが、ここはまだ出来ていません。。。
今後やっていきたいと思います!!まとめ
- athenaでやった通り進めたらいけると思っていたら、全然方向性が違ったので、大変だった
- 詰まったときに何で詰まっているのか、何のためにしているのかを明確にすると、方向転換ができる
英語のドキュメントが多く、日本語が少なくて大変だったので、まとめます
引き続き学びがあれば更新していきたいと思います〜:)
- 投稿日:2020-11-12T21:08:54+09:00
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がデフォルトであり、何やらうまく読み込まなくなってしまっているようだった。今まで、このエラーはでなかったのに、オリジナルアプリケーションを作るようになってから、見かけるようになった…。いまだに原因は謎に包まれている。
- 投稿日:2020-11-12T20:50:49+09:00
【自分用メモ】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:installrspecファイルの設定
.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 endymlファイル作成(devise)
config/locales/devise.ja.yml => 作成ymlファイル編集(devise)
以下、コピペ
config/locales/devise.ja.ymlja: 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.ymlja: time: formats: default: "%m/%d %H:%M" activerecord: attributes: モデル①: カラム①: 対応する日本語 カラム②: 対応する日本語 モデル②: カラム①: 対応する日本語 カラム②: 対応する日本語 # ActiveModelを使用している場合、続けて追記 activemodel: attributes: モデル名: カラム名: 対応する日本語おわりに
毎度なにかしら抜けるのでメモリました。
この一連の設定を自動化するプログラムを書けるようになりたいものです。
✔︎
- 投稿日:2020-11-12T20:48:13+09:00
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ファイルに追記し、ターミナルでインストールする。
Gemfilegem 'active_hash'ターミナルbundle install2.モデルの準備
ここではday(日数)をActiveHashの対象とする。モデル作成時--skip-migrationを追加するとマイグレーションファイルは作成されない。他にもActiveHashの対象があるなら、その数だけモデルを作成する。
ターミナルrails g model day --skip-migrationモデル内ではActiveHashを継承するすること。self.dataはハッシュ形式のデータが格納された配列になる。ハッシュ内はidとname(日数)が紐づく。
app/models/day.rbclass day < ActiveHash::Base #←ActiveHashを継承する self.data = [ { id: 1, name: '--' }, { id: 2, name: '1日' }, { id: 3, name: '1週間' }, ] end続いて上記で設定した日数のidをデータベースに保存する設定を行う。ActiveHashが紐づくテーブルとしてarticleを例にする。
2020***********_create_articles.rbclass 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/articlevalidates :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"}) %>以上
- 投稿日:2020-11-12T19:48:55+09:00
[Rails] devise の使い方 (備忘録)
はじめに
これまでログイン、ログアウトといった認証系の機能は自前で実装していたのですが、今回ポートフォリオを制作するにあたってdeviseを使っておきたいなと思い、その使い方の備忘録として本記事を残します。
実行環境
この記事は以下の環境で動作確認しています。
ruby 2.7.1
rails 6.0.3
devise 4.7.3インストール
Gemfileに追記。
後半で日本語化するのでそのgemも入れておきます。Gemfilegem 'devise' gem 'devise-i18n' gem 'devise-i18n-views'
bundle installを実行。$ bundle installdeviseの設定
関連ファイルを作成。
$ 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.rbconfig.action_mailer.default_url_options = { host: 'localhost', port: 3000 }2. ルートurlを定義します。
config/routes.rbroot 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:stringusernameは必ず記入して欲しいので NOT NULL 制約をつけておきます。
db/migrate/XXXXXXXXXXXXXX_add_username_to_users.rbclass AddUsernameToUsers < ActiveRecord::Migration[6.0] def change add_column :users, :username, :string, null: false end enddeviseに対応したviewの作成
viewのカスタマイズをしたいので以下を実行。
$ rails g devise:views usersviewの編集内容を反映させます。
config/initializers/devise.rb# 247行目の config.scoped_views = false のコメントアウトを外して true に変更 config.scoped_views = truesign_upの際にusernameを登録できるようにします。
app/controllers/application_controller.rbclass 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.rbdevise_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 endapp/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.rbrequire_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 enddevise の日本語翻訳ファイルを生成します。
$ rails g devise:views:locale jaこれで日本語になります。configを変更した際はサーバーの再起動をお忘れなく。
deviseには便利なヘルパーメソッドもたくさん用意されているのでそれらを利用してアプリ開発を効率よく行っていこうと思います。
- 投稿日:2020-11-12T18:54:52+09:00
FactoryBot ActiveStorageを使った画像を紐付ける方法
FactoryBotとは
RSpecにテストを効率化するための機能です。
予め値を設定しておき、それに沿ったインスタンスを生成します。ActiveStorageで画像を紐付けよう
factories/post.rbFactoryBot.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 endPostインスタンスのimageカラムに画像をつけるよう記述します。
HTTPリクエスト経由で画像を付けない場合は、
io: File.open('画像ファイル場所指定'), filename: 'ファイルの名前', content_type: 'ファイルのタイプ(imageとかtextとか)/拡張子と記述します。
以上です!
- 投稿日:2020-11-12T17:11:48+09:00
[解決]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
- 投稿日:2020-11-12T16:57:32+09:00
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としては正しい構文であるため、エラーは発生しない。
- 投稿日:2020-11-12T16:17:29+09:00
【Ruby】anemoneとnokogiriでクローラーを作ってみた。
システム開発にあたり、他のWEBページから情報を取得する必要があったので、クローラーを作成しました。
最初に考えたこと
私がやろうとしていたことは、他のWEBページから情報を取得し、現在作成中のアプリのDBに保存することでした。ということで、なんとなく「情報を取得」ってことはスクレイピングか!という感じで意気込んでいました・・・。
調査を開始し、分かったこと
自分がやろうとしていたことは、確かにスクレイピング。しかしながら、その情報を取得するためには、まずクローラーと呼ばれるものを作成しなければならないことが判明しました。
クローラーとは?
一方クローラーは、Webページ内にある全てのリンクを巡回して、深堀りしながら目的の情報を取得する方法です。この行為自体はクローリングと呼ばれます。
クローラーでリンクを探す際にはもちろんスクレイピングをしてHTMLのタグを解析して、リンク先を取得します。http://tech.feedforce.jp/anemone_crawler.html
スクレイピングとは?
スクレイピングとは、WebページのHTMLを解析してデータを抽出することです。
要するに、
●スクレイピングは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
- 投稿日:2020-11-12T16:08:54+09:00
マルチスケールシミュレーション特論:第 5 回をまとめてみた
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
- 投稿日:2020-11-12T14:51:18+09:00
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
- 投稿日:2020-11-12T14:50:43+09:00
【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でリダイレクトできなかったのか、処理の流れを把握できる様にしていくこと。
- 投稿日:2020-11-12T12:48:39+09:00
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行目のようなコードが自分の知識だけではまだまだ書けないという事が分かりました。でも分からないからそこに楽しさがあるという事も。
以上!
- 投稿日:2020-11-12T12:33:41+09:00
【Rails】テーブルの作成、カラムの追加、カラムの型の変更方法
はじめに
ポートフォリオを作成していて、あとからカラムを追加したいときや、最初に設定したカラムの型を変更したいときに、どうすればよいのか分からなかったことがあったので、初学者なりに初学者がみてもわかりやすいようにまとめました。
(最初は既にあるマイグレーションファイルに直接追加や変更を加えればよいと思っていました。しかしそれは正しくないので、新たに別のマイグレーションファイルを作成して追加や変更する方法を記述していきます。)モデルとテーブルの作成
下記のコマンドによりモデルを作成すると、モデルと一緒にこのモデルが担当するテーブルを作成するためのマイグレーションファイルが自動で作成されます。
$ rails g model [モデル名] [カラム名]:[カラムの型]例えば、Userモデルを作成したい場合、[モデル名]にUser、[カラム名:カラムの型]にはname:string email:stringを指定します。コマンドは以下のようになります。
$ rails g model User name:string email:stringコマンドを実行すると以下のようなマイグレーションファイルが作成されます。
db/migrate/XXXXXXXXXXXXXX_create_users.rbclass 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.rbclass 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.rbclass ChangeDataMaterialToProductions < ActiveRecord::Migration[6.0] <!-- ***** 以下を追加 ***** --> def change change_column :productions, :material, :integer end <!-- ***** 以上を追加 ***** --> end追記が完了したら、次のコマンドでマイグレーションを実行します。
$ rails db:migrateこれでproductionsテーブルのmaterialカラムの型がinteger型に変更されました。
最後に
この記事は初学者がポートフォリオ作成中に学んだ事を初めてQiitaにまとめました。
内容的に間違いがあればぜひコメントいただけると嬉しいです。
- 投稿日:2020-11-12T09:09:31+09:00
[Rails]バリデーションのエラーメッセージを非同期通信で実装してみた!
Railsと日々格闘している「超」がつく初心者です。
自分自身の知識の整理のために、共有します。はじめに
先日、Railsでの非同期通信の実装を学んだのですが、自分の中で消化し切れていない部分があったので、理解を深めるためにも、アウトプットします!
ユーザーオススメの本を投稿するサイトを想定しており、投稿された本に対して、コメントができます。
※コメント機能の非同期通信自体は、このページではあまり解説していません。今回は、コメント欄を空欄で送信ボタンを押してしまった時に、エラーメッセージがコメント欄の真上に出るようにして、かつ、エラーメッセージ自体を非同期通信で実装してみよう、というものです。
それでは早速いきましょう!バリデーション
models/comment.rbclass 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.rbclass 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.rbclass 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("");画面のイメージ図
非同期通信を実装したことにより、
このまま、空欄でコメントを送信しようとすると、
と、目論見通り怒られてしまいました。
ということはこれで、非同期通信を利用したエラーメッセージの完成!
メッセージ文を日本語に変換したりもできるのですが、誌面の都合上、またの機会に。おわりに
非同期通信は、コントローラーとか、ページ間遷移とかが多くって、非常にこんがらがりますよね。
何度か読み返してもらえれば、理解に近づけるかと思います。
自分の中で、処理の流れを腹落ちさせれば、実装にかかる時間をどんどん短く出来るかもしれません。
拙文失礼いたしました。
一緒に勉強頑張りましょう!
- 投稿日:2020-11-12T05:39:14+09:00
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目標
- プルダウンメニューの選択肢をCSV インポートする
- プルダウンメニューの選択項目をDB のデータを使い表示する
プルダウンメニューの選択肢はDB に保存しているカラムの情報を使って表示します↓
実装
CSV インポートとフォームのプルダウン化を分けて解説します。
1. プルダウンメニューの選択肢をCSV インポートする
- 国名一覧保存用にCountry モデル作成
- db/seeds.rb にインポート処理を追加
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:IECSV は国コード一覧CSV を使わせて頂きました。
1. Country モデル作成
下記のようなモデルを作成しました。
region カラムは今回は使っていません。
attribute type country_name string region string # Country モデル作成 $ rails g model Country country_name:string region:string2. インポート処理を追加
インポート処理はseeds.rb に追記しました。
別途ファイルを作成しrunner コマンドで実行する方法もあるようです。seeds.rbrequire "csv" # CSV ファイルへのパスは絶対パスで指定 CSV.foreach("country.csv", headers: true) do |row| Country.create!( country_name: row["国・地域名"], region: row["場所"] ) end3. インポート処理を実行
railsコマンドでCSV インポートを実行します。
seed ファイルに他の処理も書いていたので今回はDB 内を全削除してインポートし直しました。# CSV をインポートしてDB に保存する場合はこれだけ $ rails db:seed # DB を消去して全て入れ直す $ rails db:migrate:reset $ rails db:seed # rails コンソールでインポートされたか確認 $ rails c # インポートした国名の件数を確認 > Country.count 2492. プルダウンメニューの選択項目を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の使い方についてはこちら解説が非常に分かりやすいです。学び
- 検索などその後の処理も考慮してインポートを行う
- 選択肢が縦に長くなってしまうので、階層を持たせるなどして使いやすさを考慮した使用に変更したい
- 投稿日:2020-11-12T00:54:38+09:00
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さんのこちらのコードを参考に解決させていただきました。
- 投稿日:2020-11-12T00:45:25+09:00
【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
最後まで読んでいただきありがとうございます!
日々学んだことをアウトプットしてます!何かのお役に立てれば幸いです。ご指摘などあればコメントいただけますと幸いです。
- 投稿日:2020-11-12T00:02:02+09:00
【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(/正規表現/, 正規表現に該当した箇所を置換した後の文字列) >> 正規表現に該当した箇所を置換した後の文字列






