- 投稿日:2020-09-19T23:12:34+09:00
Shopifyのカスタムアプリでwebhookを設定する
はじめに
この記事ではShopifyのストア内で起こる特定のeventをrailsで作成したカスタムアプリと連動させるために使用したwebhookの設定についてお話しします。
webhookの通知を受けるためには管理画面上で設定→通知からマニュアルで設定する方法もありますが、アプリを作ったストア全ての管理画面に入れるわけではないこと、公開アプリとして運用したい人たちのために、今回は管理画面からの設定はしないこととします。環境
Ruby 2.6.6
Rails 6.0.21. 必要となるアクセススコープをconfigureする
shopify_app.rb
ShopifyApp.configure do |config| ... config.scope = "read_products, read_orders" ] ... end※ここで注意しなければいけないのが、この時点ですでにストアにアプリがインストールされている場合は、スコープを増やした後にアプリのアンインストール→再インストールをした方が良いという点です。
2.通知を受けたいwebhookとリクエスト先のURLを指定
gem 'shopify_app'をインストールしていることが前提でコマンドラインで下記を指定
rails g shopify_app:add_webhook -t orders/create -a https://example.com/webhooks/orders_createこの後shopify_app.rbには下記が追加される
ShopifyApp.configure do |config| ... config.webhooks = [ {topic: 'orders/create', address: 'https://example.com/webhooks/orders_create'}, ] ... end3.Jobの設定
それぞれのwebhookでjobを作成します
app/jobs/orders_create_job.rbclass OrdersCreateJob < ActiveJob::Base def perform(shop_domain:, webhook:) shop = Shop.find_by(shopify_domain: shop_domain) shop.with_shopify_session do # ここでimplementしたい機能を追加 end end endsidekiq等の非同期処理を行うライブラリを使用されいる場合は、上記のjobがbackgroundで処理されます。
4.webhook用のカスタムcontrollerを作成
この部分はなくても問題ないのですが、webhookを通じてjobで行う以上の機能が必要となる場合などに必要となるので記載します。
routes.rb... post 'webhooks/orders_create', :to => 'custom_webhooks#orders_create' ...app/controllers/custom_webhooks_controller.rb
class CustomWebhooksController < ApplicationController def orders_create end ... private def webhook_params params.except(:controller, :action, :type) end end
- Webhook verification 全てのwebhookはアプリがインストールされたストアからのリクエストであることを証明する必要があります。 Shopify側では、これをhttpリクエストのheaderにHMACを入れることでこれを証明するようにしています。 railsアプリの場合、幸いにも下記を入れるだけでこのHMACを識別して正しいリクエストかどうかを判断してくれます。
class CustomWebhooksController < ApplicationController include ShopifyApp::WebhookVerification ... end
- 必要となるmethodを作成
def orders_create params.permit! OrdersCreateJob.perform_later(shop_domain: shop_domain, webhook: webhook_params.to_h) head :no_content endwebhookを通じてPOSTコールがされたあと、Shopify側に200 series statusを返す必要があります。(公式ドキュメントによると200 OK以外のレスポンスを返した場合には、48時間以内に19回のコールをしてくれるようです)
head :no_content にすることで、レスポンスは "204 no content"=どのデータもレスポンスしていない=webhookのデータは受領されたと判断されます注意点
最初に管理画面にてwebhookの通知を設定をしている場合でも、config上で必要となるscopeのアクセスを許可されていなければhttpリクエストすらされないようでした。
ご自身のアプリがすでにストアにインストールされてしまっている場合には、このscope追加でアプリが再インストールされる際に下記のような画面でスコープ許可がされることを確認してください。
webhookがストアに設定されているかを確認する場合は、
header Content-Type: application/json X-Shopify-Access-Token: 該当のshop.shopify_token GET https://ストア名.myshopify.com/admin/api/2020-07/webhooks.jsonで確認することもできます。
- 投稿日:2020-09-19T22:48:35+09:00
【ruby】例外処理で、施されたら施し返す
例えばあるデータをパースして、特定のデータのみデータベースに保存したいとする。
その中で、パースできない拡張子があればエラーが出て、処理が中断してしまいバグを引き起こしてしまう。そこで、便利なのが例外処理というもので、処理を中断させず例外事案の場合の処理を施すことができる。
まさに、
施すこされたら施し返す、恩返しです
を実現できるのだ。今回は単純な計算を例に、例外処理を見ていこう。
エラーが発生した場合の処理 begin / rescue
Ruby内で、10を0で割ろうとするとエラーが出てしまう。
puts 10 / 0 puts "こんにちわ"divided by 0 (ZeroDivisionError)処理が途中で、中断されてしまう。
そこで、
- エラーの対象になりそうな箇所を、begin
で囲う。
- エラーが発生した時の処理を、rescue
内に記述する。begin 10 / 0 rescue p "0で割れません" end puts "こんにちわ""0で割れません" "こんにちわ"処理が中断されず、エラー時の処理と正常処理どちらも実行された。
省略法
beginなしで、rescueさせる
puts 10 / 0 rescue 0 puts 10 / nil rescue 00 0エラー内容を、変数に格納 rescue =>
begin 10 / 0 rescue => e puts e end puts "こんにちわ"divided by 0 こんにちわエラーオブジェクトが、変数eに格納されて出力できる。
エラーごとの処理を変える rescue "エラーメッセージオブジェクト"
begin 10 / 0 rescue NoMethodError puts "そのようなメソッドはない" rescue ZeroDivisionError puts "0で割れません" end0で割れません2番目のエラーメッセージに該当するので、そのrescueに反応する。
注意点
対象の例外クラスの親が、先に記述されいた場合はそちらが先に処理される
begin 10 / 0 rescue StandardError puts "基本的なエラー" rescue ZeroDivisionError puts "0で割れません" end基本的なエラー明示的なエラーを発生させて、処理を中断させる raise
使用用途は、
1. パラメータが想定されたものでないとき
2. 不正なアクセスがきた時begin raise NoMethodError rescue => e p e endNoMethodError独自のエラーを発生させる
例外クラス(StandardErrorクラス)を継承させてあげる。
class Hoge < StandardError end begin raise Hoge rescue => e p e end#<Hoge: Hoge>エラー時でも、再度初めから実行させる retry
num = 0 begin puts 10 / num rescue ZeroDivisionError => e puts e num = 1 retry end puts "終了しました"divided by 0 10 終了しましたループ1回目では、エラーが発生していて、
ループ2回目では、正常に処理がされている。エラーが発生しても、しなくても行う処理 ensure
begin puts "例外なし" rescue => e puts e ensure puts "Hello" end例外なし Helloensureは、いかなる時でも必ず実行される。
番外編 エラーオブジェクトとは
begin 10 / 0 rescue => e puts e.class puts e.class.superclass puts e.class.superclass.superclass puts e.class.superclass.superclass.superclass endZeroDivisionError StandardError Exception ObjectExceptionが元となるクラスで、Objectがその親
- 投稿日:2020-09-19T21:43:25+09:00
(ギリ)20代の地方公務員がRailsチュートリアルに取り組みます【第11章】
前提
・Railsチュートリアルは第4版
・今回の学習は3周目(9章以降は2周目)
・著者はProgate一通りやったぐらいの初学者基本方針
・読んだら分かることは端折る。
・意味がわからない用語は調べてまとめる(記事最下段・用語集)。
・理解できない内容を掘り下げる。
・演習はすべて取り組む。
・コードコピペは極力しない。
認証システム開発・第6段回目、第11章に入ります。セキュリティ強化の観点から、アカウント有効化のステップを入れていきます。よくある、登録後にメールが送られてきて、そのリンクを踏むと本登録になるやつですね。
本日のBGMはこちら。
Tatuki Seksu "Hanazawa EP"
いろいろあやしいのをシューゲサウンドでパッケージングしましたってかんじが好き。
【11.1.1 AccountActivationsコントローラ 演習】
1. 現時点でテストスイートを実行すると greenになることを確認してみましょう。
→ 現時点ではテスト書いてないのでGREENです。
2. 表 11.2の名前付きルートでは、_pathではなく_urlを使うように記してあります。なぜでしょうか? 考えてみましょう。ヒント: 私達はこれからメールで名前付きルートを使います。
→ pathは相対パス(/とか省略した形)、urlは絶対パス(https:~~とか完全な形)。メールというrails外の処理にはurlの完全形である絶対パスが必要と考えます。
【11.1.2 AccountActivationのデータモデル メモと演習】
コールバックではbefore_〇〇の、〇〇の動作の直前に特定のメソッドを実行することができる。メソッド参照という。ブロックを渡すよりこちらが推奨。
(おさらい)privateより下にメソッドを定義することで、外部に非公開にできる。1. 本項での変更を加えた後、テストスイートが green のままになっていることを確認してみましょう。
→ GREEN
2. コンソールからUserクラスのインスタンスを生成し、そのオブジェクトからcreate_activation_digestメソッドを呼び出そうとすると (Privateメソッドなので) NoMethodErrorが発生することを確認してみましょう。また、そのUserオブジェクトからダイジェストの値も確認してみましょう。
→ こんなかんじ>> user = User.third User Load (0.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ? [["LIMIT", 1], ["OFFSET", 2]] => #<User id: 3, name: "Mr. Sage Hartmann", email: "example-2@railstutorial.org", created_at: "2020-09-17 08:34:09", updated_at: "2020-09-17 08:34:09", password_digest: "$2a$10$.HyqPb.DwmFICve62DsYte1alLAVihIdeS2F8Rjndry...", remember_digest: nil, admin: false, activation_digest: "$2a$10$9VKv/p9kYrz84SdMs/7s/uzEV3mqzGMmTubIq7.Vz4b...", activated: true, activated_at: "2020-09-17 08:34:09"> >> user.create_activation_digest Traceback (most recent call last): 1: from (irb):2 NoMethodError (private method `create_activation_digest' called for #<User:0x000000000426b7a0>) Did you mean? restore_activation_digest! >> user.activation_digest => "$2a$10$9VKv/p9kYrz84SdMs/7s/uzEV3mqzGMmTubIq7.Vz4bbIb.ZeLDRy"
3. リスト 6.34で、メールアドレスの小文字化にはemail.downcase!という (代入せずに済む) メソッドがあることを知りました。このメソッドを使って、リスト 11.3のdowncase_emailメソッドを改良してみてください。また、うまく変更できれば、テストスイートは成功したままになっていることも確認してみてください。
→ email.downcase!に変えるだけやね。user.rbdef downcase_email email.downcase! end
【11.2.1 アカウント有効化のメール送信 演習】
1. コンソールを開き、CGIモジュールのescapeメソッド (リスト 11.15) でメールアドレスの文字列をエスケープできることを確認してみましょう。このメソッドで"Don't panic!"をエスケープすると、どんな結果になりますか?
→ 下記。(クエリパラメータとCGIは用語集に入れてます)>> CGI.escape('foo@example.com') => "foo%40example.com" >> CGI.escape("Don't panic!") => "Don%27t+panic%21"
【11.2.2 送信メールのプレビュー メモと演習】
AWScloud9を使用している場合、チュートリアルでは旧cloud9使用しているので'example.com'に入力する内容の見た目がかなり違うので戸惑いますが、内容は一緒です。Railsサーバーを立ち上げて、別タブで表示した画面のURLのhttps://以下をすべてコピペすればOKです。
1. Railsのプレビュー機能を使って、ブラウザから先ほどのメールを表示してみてください。「Date」の欄にはどんな内容が表示されているでしょうか?
→ 今日の日付とUTC(協定世界時)が表示される。(協定世界時って言葉カッコよくないですか?中二心をくすぐられる)
【11.2.3 送信メールのテスト メモと演習】
ここのassert_matchがいまひとつしっくり来ないですが、「メールの中身に対し、名前と有効化トークンとエスケープしたメルアドが含まれているかテストしている」ぐらいに認識しておきます。
1. この時点で、テストスイートが greenになっていることを確認してみましょう。
→ Yes, GREEN !
2. リスト 11.20で使ったCGI.escapeの部分を削除すると、テストが redに変わることを確認してみましょう。
→ REDになるのは、メールアドレスにメタ文字が含まれていて、エスケープしないと正規表現ではないからですかね。こちらの記事参照。
【11.2.4 ユーザーのcreateアクションを更新 メモと演習】
deliver_now:名前のとおり、その瞬間にメール送信処理を実行。
1. 新しいユーザーを登録したとき、リダイレクト先が適切なURLに変わったことを確認してみましょう。その後、Railsサーバーのログから送信メールの内容を確認してみてください。有効化トークンの値はどうなっていますか?
→ homeに戻りました。Welcome to the Sample App! Click on the link below to activate your account: 以下のURLに含まれているランダムな文字列が有効化トークンです。
2. コンソールを開き、データベース上にユーザーが作成されたことを確認してみましょう。また、このユーザーはデータベース上にはいますが、有効化のステータスがfalseのままになっていることを確認してください。
→ activated: false になっていました。
【11.3.1 authenticated?メソッドの抽象化 メモと演習】
もう何のダイジェストの話してんのか混乱してきましたね。ってなったら11章の始めにあった表11.1を見返しましょう。何の話をしているのか、しっかり把握しながら進めないと。
そんで、この節のタイトルは抽象化より一般化ってかんじがする。authenticated?メソッドを表11.1のどのパターンでも使用できるようにするわけやし。1. コンソール内で新しいユーザーを作成してみてください。新しいユーザーの記憶トークンと有効化トークンはどのような値になっているでしょうか? また、各トークンに対応するダイジェストの値はどうなっているでしょうか?
→ こんな感じっすね。ユーザー作っただけだから記憶系はnilのまま…>> user = User.create(name: "muteki", email: "muteki@man.com", password: "mutekimuteki", password_confirmation: "mutekimuteki") (0.1ms) SAVEPOINT active_record_1 User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) LIMIT ? [["email", "muteki@man.com"], ["LIMIT", 1]] SQL (2.5ms) INSERT INTO "users" ("name", "email", "created_at", "updated_at", "password_digest", "activation_digest") VALUES (?, ?, ?, ?, ?, ?) [["name", "muteki"], ["email", "muteki@man.com"], ["created_at", "2020-09-17 12:57:50.404544"], ["updated_at", "2020-09-17 12:57:50.404544"], ["password_digest", "$2a$10$eDPAP444JbjJDGucKnoFE.MWFBTAR8dxQ.wXPJfzql9E0TPRVDQfq"], ["activation_digest", "$2a$10$zql927sHRszT.bjitRxBn.slJil.Zvc74AJkztqBZzt7kUiSqBgx."]] (0.1ms) RELEASE SAVEPOINT active_record_1 => #<User id: 102, name: "muteki", email: "muteki@man.com", created_at: "2020-09-17 12:57:50", updated_at: "2020-09-17 12:57:50", password_digest: "$2a$10$eDPAP444JbjJDGucKnoFE.MWFBTAR8dxQ.wXPJfzql9...", remember_digest: nil, admin: false, activation_digest: "$2a$10$zql927sHRszT.bjitRxBn.slJil.Zvc74AJkztqBZzt...", activated: false, activated_at: nil>なので、記憶系をわざわざ作ります。
>> remember_token = User.new_token => "5dyf7BoW9H3H9SYH6VPRYg" >> remember_digest = User.digest(remember_token) => "$2a$10$1CymqXEPzP.b05TblQ3Zye/ukhNblEpGlDxI4kT2VoiLUJK1EHVy2" >> user.update_attribute(:remember_token, remember_token) (0.1ms) SAVEPOINT active_record_1 (0.1ms) RELEASE SAVEPOINT active_record_1 => true >> user.update_attribute(:remember_digest, remember_digest) (0.1ms) SAVEPOINT active_record_1 SQL (0.2ms) UPDATE "users" SET "updated_at" = ?, "remember_digest" = ? WHERE "users"."id" = ? [["updated_at", "2020-09-17 13:45:51.944577"], ["remember_digest", "$2a$10$1CymqXEPzP.b05TblQ3Zye/ukhNblEpGlDxI4kT2VoiLUJK1EHVy2"], ["id", 102]] (0.0ms) RELEASE SAVEPOINT active_record_1 => trueということで、各トークンはこんな感じ。ダイジェストは上で出てます。
>> user.remember_token => "5dyf7BoW9H3H9SYH6VPRYg" >> user.activation_token => "p5rorOE7trfF4L-YJynnxg"
2. リスト 11.26で抽象化したauthenticated?メソッドを使って、先ほどの各トークン/ダイジェストの組み合わせで認証が成功することを確認してみましょう。
→ 確認するだけ…ってあれー??activation_tokenでNameError??
って調べたら解決。あくまでユーザーに紐づいてるものだからuser.activation_tokenか。>> user.authenticated?(:remember, remember_token) => true >> user.authenticated?(:activation, activation_token) Traceback (most recent call last): 1: from (irb):11 NameError (undefined local variable or method `activation_token' for main:Object)よって以下でtrue。remember_token作るときに、新しく定義するのではなく、user.remember_tokenで紐付けしたほうがよかったな。
>> user.authenticated?(:activation, user.activation_token) => true
【11.3.2 editアクションで有効化 演習】
1. コンソールから、11.2.4で生成したメールに含まれているURLを調べてみてください。URL内のどこに有効化トークンが含まれているでしょうか?
→ 11.2.4の演習1と同じです。
2. 先ほど見つけたURLをブラウザに貼り付けて、そのユーザーの認証に成功し、有効化できることを確認してみましょう。また、有効化ステータスがtrueになっていることをコンソールから確認してみてください。
→ 認証成功、有効化できていました。
【11.3.3 有効化のテストとリファクタリング メモと演習】
・テストに出てくる配列deliveriesは変数。なので、他のテストに支障が出ないよう、setupでclearしている。
・sizeメソッド:lengthメソッドと同じ。ここではメールの数(=1)を確認している。
・assignsメソッド:対応するアクション内(ここではsignupをテストしているのでcreateアクション)のインスタンス変数(@user)にアクセスできるようになる。
・whereメソッド:与えられた条件にマッチするレコードをすべて返す。こちらにfind,find_byとの比較がありました。1. リスト 11.35にあるactivateメソッドはupdate_attributeを2回呼び出していますが、これは各行で1回ずつデータベースへ問い合わせしていることになります。リスト 11.39に記したテンプレートを使って、update_attributeの呼び出しを1回のupdate_columns呼び出しにまとめてみましょう (これでデータベースへの問い合わせが1回で済むようになります)。また、変更後にテストを実行し、 greenになることも確認してください。
→ 下記user.rbdef activate update_columns(activated: true, activated_at: Time.zone.now) end
2. 現在は、/usersのユーザーindexページを開くとすべてのユーザーが表示され、/users/:idのようにIDを指定すると個別のユーザーを表示できます。しかし考えてみれば、有効でないユーザーは表示する意味がありません。そこで、リスト 11.40のテンプレートを使って、この動作を変更してみましょう9 。なお、ここで使っているActive Recordのwhereメソッドについては、13.3.3でもう少し詳しく説明します。
→ 下記users_controller.rbdef index @users = User.where(activated: true).paginate(page: params[:page]) end def show @user = User.find(params[:id]) redirect_to root_url and return unless @user.activated? end
3. ここまでの演習課題で変更したコードをテストするために、/users と /users/:id の両方に対する統合テストを作成してみましょう。
訳注: updateメソッドは、コールバックとバリデーションを実行せずにスキップしますので、コールバックやバリデーションをかける必要がある場合は注意が必要です。
→ ここ難しいですね。発想としては、「有効化してないユーザー(@non_activated)がindexに表示されていない」のと、有効化してないユーザーのページ(user_path(@non_activated))にアクセスしようとすると、homeに飛ばされる」のを確かめればいいわけだけど…。前者のアサーションが分からず悩みました。
結局調べたところ、「user_path(@non_activated)のリンクが表示されていない(0である)」のを確かめればいいと。なるほど。ということで下記です。テスト名もてきとうに追記しました。あと、setupに@non_activatedとして、uses.ymlの3番目のユーザーをactivated: falseに書き換えてから追加しています。users_index_test.rbdef setup @admin = users(:michael) @non_admin = users(:archer) @non_activated = users(:lana) end test "index as admin including pagination and delete links, not to show non activated user" do log_in_as(@admin) get users_path assert_template 'users/index' assert_select 'div.pagination' first_page_of_users = User.where(activated: true).paginate(page: 1) first_page_of_users.each do |user| assert_select 'a[href=?]', user_path(user), text: user.name assert_select 'a[href=?]', user_path(@non_activated), count: 0 unless user == @admin assert_select 'a[href=?]', user_path(user), text: 'delete' end end assert_difference 'User.count', -1 do delete user_path(@non_admin) end get user_path(@non_activated) assert_redirected_to root_url end
【11.4 本番環境でのメール送信 グチと演習】
ついにきた!!SendGrid!!
これ酷くないですか?登録してもすぐにアカウント凍結されてメール飛ばせなくなるんですよ。前回こいつに時間取られた挙句、結局解決するにはサポートに連絡しないといけないらしく、やってられるかって放置しました。そんなもんチュートリアルに使うなよな…。
ということで、別の手段を導入しようしていろいろ試したのですがどれもうまくいかず…。不服ですが今回はsendgridで済まします。これは今後の課題として置いておきます。
……結局そっこーで凍結されました。もうええわ。1. 実際に本番環境でユーザー登録をしてみましょう。ユーザー登録時に入力したメールアドレスにメールは届きましたか?
→ うん、無理でした。
2. メールを受信できたら、実際にメールをクリックしてアカウントを有効化してみましょう。また、Heroku上のログを調べてみて、有効化に関するログがどうなっているのか調べてみてください。ヒント: ターミナルからheroku logsコマンドを実行してみましょう。
→ やりたいんやけどね、無理ですわ。
第11章まとめ
・終わり悪ければすべて悪い。SendGrid嫌い。
・今後は純粋にActionMailerでメール送信に取り組みたい。
・URLに有効化トークンとエスケープしたメールアドレスを盛り込む。
SendGrid問題、なんとか解決したかったんやけどなあ…。これ以上時間かけるのももったいないので、次に進めます。今後絶対なんとかしてやる!
さて、次は第12章、パスワードの再設定です。認証システム開発の最終章ですね!
⇨ 第12章へ!
⇦ 第10章はこちら
学習にあたっての前提・著者ステータスはこちら
なんとなくイメージを掴む用語集
・クエリパラメータ
URLの末尾で疑問符「?」に続けてキーと値のペアを記述したもの。ユーザーがどこから来たのか解析する手段(パッシブパラメータ)や、指定された変数によってコンテンツの内容を変化させたりできる(アクティブパラメータ)。クエリのこと全般も含めて詳しくはこちら。・CGI(Common Gateway Interface)
クライアント側のWebブラウザの要求に応じてWebサーバが外部プログラムを呼び出して、その実行結果がHTTPを介してクライアントのWebブラウザに送信される仕組みのこと。掲示板、アクセスカウンター、アンケートフォームなどを実装できる。・assert_mutch
与えられた文字列が与えられた正規表現にマッチした場合、検査にパス。・SMTP(Simple Mail Transfer Protocol)
インターネットで電子メールを転送するプロトコル。
- 投稿日:2020-09-19T21:35:05+09:00
【Rails5】Railsで新規アプリを作る【初心者】
概要
『どうも皆さん、おはこんばんにちは』
(…一度言ってみたかった)
筆者は最近RoRアプリを作り始めた、思いっっきり初心者です。
Qiita初投稿という事で、めちゃくちゃ初歩的な「Railsで新規アプリを作る過程」について投稿したいと思います!前提条件
- OS: MacOS
- Rubyバージョン: 2.5.1
- Railsバージョン: 5.2.3
- データベース: MySQL
- Rubyバージョン管理: rbenv
- IDE: VisualStudioCode
上記の環境でアプリを作っていきます!
Railsで新規アプリを作る
ターミナル上で
rbenv local 2.5.1
rails _5.2.3_ new app_name --database=mysql --skip-bundle
を実行します。何を行っているのか
rbenv
rbenvコマンド実行の宣言local 2.5.1
このプロジェクトで使用するRubyのバージョン指定(今回はver.5.2.3)rails
railsコマンド実行の宣言_5.2.3_
rubyのバージョン指定(今回はver.5.2.3)new
新しいアプリの作成コマンドapp_name
作りたいアプリの名前の定義--database=mysql
使いたいデータベースの指定(今回はmysql)
--skip-bundle
bundle install
をスキップする指示
app_name
を.
とすると、カレントディレクトリ上に作られる--database=mysql
は、-d mysql
でもOK--skip-bundle
は、-B
でもOKrbenvの使い方と仕組みについては、以下の記事がわかりやすいので参照してください。
rbenvの使い方と仕組みについて - Qiitaアプリ内のファイル
上記のようにターミナル上で
rails new
をすると、たくさんのフォルダやファイルが作られます。中身は以下のようになっているはずです。app
アプリケーションのコントローラ、モデル、ビュー、ヘルパー、メイラー、チャンネル、ジョブズ、アセットが置かれています。
bin
アプリケーションを起動・アップデート・デプロイするためのRailsスクリプト等のスクリプトファイルが置かれています。
config
アプリケーションの設定ファイル (ルーティング、データベース等) がここに置かれています。
db
現時点のデータベーススキーマと、データベースマイグレーションファイルが置かれています。
lib
アプリケーションで使う拡張モジュールが置かれています。
log
アプリケーションのログファイルが置かれています。
public
このフォルダの下にあるファイルは外部 (インターネット) からそのまま参照できます。静的なファイルやコンパイル済みアセットをここに置きます。
storage
Diskサービスで用いるActive Storageファイルが置かれています。
test
Unitテスト、フィクスチャなどのテスト関連ファイルをここに置きます。
tmp
キャッシュ、pidなどの一時ファイルが置かれます。
vendor
サードパーティによって書かれたコードはすべてここに置きます。通常のRailsアプリケーションの場合、外部からのgemファイルをここに置きます。
.gitignore
Gitに登録しないファイル(またはパターン)をこのファイルで指定します。
.ruby-version
デフォルトのRubyバージョンがこのファイルで指定されています。
config.ru
アプリケーションの起動に必要となる、Rackベースのサーバー用のRack設定ファイルです。
Gemfile
Railsアプリケーションで必要となるgemの依存関係を記述します。このファイルはBundler gemで使われます。
package.json
Railsアプリケーションで必要なnpm依存関係をこのファイルで指定できます。このファイルはYarnで使われます。
Rakefile
このファイルには、コマンドラインから実行できるタスクを記述します。ここでのタスク定義は、Rails全体のコンポーネントに対して定義されます。
独自のRakeタスクを定義したい場合は、Rakefileに直接書くと権限が強すぎるので、なるべくlib/tasksフォルダの下にRake用のファイルを追加するようにしましょう。
README.md
アプリケーションの概要を説明するマニュアルをここに記入します。このファイルにはアプリケーションの設定方法などを記入し、これさえ読めば誰でもアプリケーションを構築できるようにしておく必要があります。
gemのインストール
Rubyにおけるgemは、下記2つの役割を持ちます。
- パッケージ
- パッケージ管理ツール
パッケージを使うことで開発を効率的に進めることができるので、実際の現場でも使用されることが多いようです。
簡単にパッケージをインストール可能なので、Ruby on Rails 初心者でも素早く本格的なアプリ機能を装備することができるんですね。アプリ内で使いたい機能を持つgemを Gemfileに、
Gemfilegem 'gem名'のように記述します。(ここでは、具体的なgemの種類については割愛します。)
また、Gemfile内のrailsの記述を、
Gemfile~ gem 'rails', '5.2.3' ~のように使いたいバージョン(今回はver.5.2.3)で固定します。
先ほど
--skip-bundle
コマンドでgemのインストールをスキップしたので、ターミナル上で
bundle install
を実行します。何を行っているのか
bundle install
bundler というgemを使って、Gemfileの記載内容に従ってgemをインストールするためのコマンドサーバーの立ち上げ
実際にサーバーを立ち上げてみましょう!ターミナル上で
rails server
を実行します。何を行っているのか
rails server
rails new
コマンド で作ったRailsアプリケーションを、local環境でサーバーに繋ぐ指示
rails server
は、rails s
でもOKターミナル上で以下のようなログが流れればサーバーとの接続が完了です!
=> Booting Puma => Rails 5.2.3 application starting in development => Run `rails server -h` for more startup options Puma starting in single mode... * Version 3.12.6 (ruby 2.5.1-p57), codename: Llamas in Pajamas * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://localhost:3000 Use Ctrl-C to stopブラウザ上で確認してみましょう!
localhost:3000 にアクセスします。無事にサーバーへ接続できました!
終わりに
最後までご覧いただきありがとうございました。
今後はdeviseでのユーザー登録方法、Docker上でのRoR環境構築なども記事にしたいなあと考えています(いつになるかは未定)。また、この記事に関して不明な点等ありましたら、お知らせくださると幸いです。
早くエンジニアとして「駆け出したい」ですね。
それでは!参考にしたWebサイト
- 投稿日:2020-09-19T21:31:17+09:00
2桁以上の数字から、任意の桁の数値を取りたい時の方法!!
こんばんは!!
アロハな男、やすのりです今週勉強している中で理解するのに少し時間が必要だったことについて備忘録も兼ねて書き記しておこうと思います
今回のテーマは題名の通り『2桁以上の数字から、欲しい桁の数値を取る時はどうしたらいいの!?』を解決しちゃいましょう!!
ちなみに、計算は全て整数になっているので今回は省きますが、小数点が入っていたりしたらto_iメソッドを使ったりと少し変化も有ります
どうやって欲しい桁の数値を取るの?
それじゃあ、まず先に百の位までの数値の取り方をずらっと書いちゃいますね!
num = 123 # 100の桁が欲しい場合 digit_100 = (num / 100) % 10 # 10の桁が欲しい場合 digit_10 = (num / 10) % 10 # 1の桁が欲しい場合 digit_1 = (num / 1) % 10 puts "100の桁の数値は#{digit_100}です" puts "10の桁の数値は#{digit_10}です" puts "1の桁の数値は#{digit_1}です"さぁ、これでコードの記述が終わりましたね!!
これを実行するとちゃんと欲しい桁の値が取れているのか...結果
100の桁の数値は1です 10の桁の数値は2です 1の桁の数値は3ですちゃんと出力されましたね!!
それじゃあ細かく見ていきましょう。
解説
それじゃあ10の桁の場合を見ていきましょう
digit_10 = (num / 10) % 10となっていますね。
まず数式の前半部分を計算すると12が返ってきます。
ここから元々10の桁だった部分が、今は1の桁に移動していますね。
あとは10の桁以上の数値が不要になるわけなので計算して1の桁だけが欲しいところ...そうか!!
10で割って1の桁を余りとして返せばいいのか!!ということで後半部分の『%』の出番ですね12を10で割った余りを出力結果とするから
2
が結果として返ってくるわけですね!!
この前半部分の10というところ、今回は10の桁だったので10で割ってますが、1万の桁なら1万で、100万なら100万の桁で割れば欲しい桁の数値が1の桁に返ってきます!!
なぜ理解するのに時間が必要だった?
今回の説明を見れば『ん?意外と簡単じゃない?なんで理解に時間がかかったの?』と思う方もいらっしゃるかもしれません。
実は今回の桁数取得の方法を考えている時に出されていた問題が『2桁の数字から数値をそれぞれ取得しなさい』という旨の問題だったんです!!
先ほどの解説の時にも説明しましたが、1の桁を欲しいのであれば『10で割った余りを返り値とすればいいだけじゃん』となったんです。
そして10の桁も『10で割った答えだけで桁の数値が取れるじゃん』となりました。そうするとどうでしょう
digit_10 = num / 10 digit_1 = num % 10というコードになっちゃいました
これでも2桁だけなら答えは一緒なので『あれ...なんでこれでダメなんだ?』となってしまいました...このコードだと桁数が増えた時に、1の桁と1番上の桁の数値を取得するだけなら対応できますが、中間の桁を取得することができません!!
そのことに気付いたら理解がすぐにできましたが、それに気付くまでに少し時間がかかってしまいました
結論
こんな簡単そうに見えることでもハマると一切理解ができない。
だが理解できた時の達成感は変えがたいものが有ります。
もう脳汁ドパドパでてる感じでした皆さんも困難にぶつかっても諦めずレッツトライ!!
- 投稿日:2020-09-19T21:10:36+09:00
【Rails】deviseの会員登録に確認画面と完了画面を加える。
環境
Ruby 2.5.7
Rails 5.2.4gem
gem 'devise'
前提
deviseの新規登録フォームがカスタムできる状態(デフォルトではない状態)
※事前に、新規登録フォームがカスタムでき問題なく動作することをご確認ください。やりたいこと
deviseのデフォルト設定ではsign_upページで情報が入力され送信されると、そのまま登録されると共にあらかじめ指定した(されている)ページに遷移します。
登録の前に入力された情報が確認できるページを挟んだり、登録が完了したことをお知らせするページがあると、より親切かと思いますので、今回は「入力フォーム」に加えて、「入力された情報の確認画面」、「登録完了画面」を作成していきます。
今回の作成で完成するページの流れとしては、
新規会員情報の入力フォームusers/new.html.erb(新規作成)
→入力情報の確認画面users/registrations/new.html.erb
→登録完了画面users/completion(新規作成)
という順番で画面が遷移していきます。少し違和感があるかもしれませんが、deviseで用意されている
users/registrations/new.html.erb
は前のページで入力された情報の確認のみで、見た目上はその前のページで入力された値を表示するだけになります。手順
1.views/usersに入力画面(
new.html.erb
)、完了画面(completion.html.erb
)を用意
2.controllers(controllers/users/registrations_controller.rb
)に、会員登録後のリダイレクト先(users/completion.html.erb
)を追記
3.routes.rb
に、1.で追加したviewファイルのルーティング、registrations_controller.rb
の使用を追記
4.(controllers/users_controller.rb
)にrender用newとcompletionを作成1.確認画面、完了画面の作成
冒頭で記した通り、新規登録時の画面の流れとしては、
新規登録入力フォームusers/new.html.erb
→入力確認画面users/registrations/new.html.erb
→登録完了画面users/completion
となります。
確認画面で"登録する"ボタンを押すとdeviseの標準機能でユーザー情報が登録されます。入力画面
users/new.html.erb<div> <h2>新規会員登録</h2> <%= form_with url: new_user_registration_path, method: :get, local: true do |f| %> <%= f.label :name %> <%= f.text_field :name %> <%= f.label :phone_number %> <%= f.number_field :phone_number %> <%= f.label :email %> <%= f.email_field :email %> <%= f.label :password %> <% if @minimum_password_length %> (<%= @minimum_password_length %>文字以上) <% end %> <%= f.password_field :password %> <%= f.password_field :password_confirmation %> <%= render "users/shared/links" %> <%= f.submit "確認" %> <% end %> </div>元々用意されている
registrations/new.html.erb
のフォームを参考に新規作成します。
登録情報に名前や電話番号情報を追加する方法は割愛します。
追加される場合は先にそちらの設定をして動作が確認できた上で、今回の方法を試していただくか、カラムは増やさずにデフォルトの設定(メールアドレス、パスワードのみ)でお試しください。ポイントとしてはフォームタグです。
users/new.html.erb... <%= form_with url: new_user_registration_path, method: :get, local: true do |f| %> ... <% end %>ここでは保存するモデルは指定せず、urlだけを指定しています。
つまり、フォーム内でsubmitされると、ここで指定したurlに遷移され、フォームに入力されている値も"パラメータ"として遷移先に渡されます。
ここで指定するurlは次の確認画面のurl: new_user_registration_path
を指定します。
このurlはdeviseがデフォルトで用意しているregistrations/new.html.erb
です。このフォームはurlを遷移するだけなので、HTTPメソッドは"POST"ではなく"GET"を指定します。
フォームのHTTPメソッドはデフォルトが"POST"になっているので、method: :get
を明示する必要があります。今回使うフォームタグは
form_with
です。
form_with
はデフォルトの送信方法がAjax(remote: true
)で、画面遷移が行われない仕様なので、local: true
も明示する必要があります。
form_for
の場合はデフォルトがlocal: true
なので、普段は意識する必要はありません。確認画面
users/registration/new.html.erb<div> <h2>入力情報の確認</h2> <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <p><%= params[:name] %></p> <p><%= params[:phone_number] %></p> <p><%= params[:email] %></p> <% unless params[:password].nil? %> <% i = 0 password = "" while i < params[:password].length password << "*" i += 1 end %> <% end %> <p><%= password %></p> <%# 実際に送信するパラメータ %> <%= f.hidden_field :name_family, value: params[:name] %> <%= f.hidden_field :phone_number, value: params[:phone_number] %> <%= f.hidden_field :email, value: params[:email] %> <%= f.hidden_field :password, value: params[:password] %> <%= f.submit "登録する" %> <% end %> </div>この画面がdeviseで用意されている
users/registrations/new.html.erb
です。
元々のこのページには入力フォームがありますが、今回は確認だけなので、フォームは表示しません。
form_for
から始まるフォームタグは元からあるものをそのまま利用しています。前のページから渡されてるパラメータを
params[:name]
などを用いて取得し、確認できるように表示します。パスワード部分については入力されたものが何なのかわからない状態にしています。
(パラメータには載っているのですが、ここの隠し方がわからなかったので、詳しい方ご教授いただけると幸いです。)users/registrations/new.html.erb<% i = 0 password = "" while i < params[:password].length password << "*" i += 1 end %>
params[:password].length
でパスワードの文字数を取得しています。
while i < params[:password].length ... end
で処理の中でi
が1ずつカウントアップしていきます。
同時に、直前で定義した変数password = ""
に"*"
が足されていき、文字数に達したら処理が終了します。
<%= password %>
変数の中身を表示します。users/registration/new.html.erb<%= f.hidden_field :name_family, value: params[:name] %> ...
f.hidden_field
は表示はされませんが、そこに指定されているvalue: params[:name]
などはフォームとして送信されます。
今回のフォームは保存するモデルも(resource
でdeviseが自動的に)指定されているので、このf.hidden_field
で指定された値はそのまま保存される値になります。完了画面
users/completion.html.erb<div> <% if request.referrer.include?('users/sign_up') %> <p>登録が完了しました!</p> <% else %> <p>既に登録済みです。</p> <% end %> </div>前のページで
登録する
が押されると、確認した会員情報が保存されると同時に、この画面に遷移します。
request.referrer
を使うと、どのページからここに遷移してきたか、前のページのURLが取得できます。
request.referrer.include?('users/sign_up')
のinclude?メソッドは()の中の値がそこに含まれているかどうかを返すメソッドです。
ここでusers/sign_up
が前のページのURLに含まれていたかどうかを判断して、そのページで表示するテキストを変えています。
users/registrations/new.html.erb
以外からの遷移であれば、登録済みと表示され、そもそも未登録(未ログイン)の場合に表示しようとするとdeviseのbefore_action :authenticate_user!
で、他のページにリダイレクトが行われます。2.users_controller.rbにnewとcompletionを追加
前の手順ではviewファイルを作成しましたが、このままでは画面表示ができないので、コントローラーでアクションを記述する必要があります。
users_controller.rbclass UsersController < ApplicationController before_action :authenticate_user!, except: %i[new] ... def new end def completion end ... endnewページは新規会員登録フォームなので、下記のように記述する必要があります。
before_action :authenticate_user!, except: %i[new]
before_action :authenticate_user!, except: [:new]
before_action :authenticate_user!, except: :new
どれも意味は一緒ですが、記述するアクションが増えた時に、よりコードが短くなるのは1行目のものです。ちなみに
%i
で複数指定するときはbefore_action :authenticate_user!, except: %i[new action1 action2 action3]
という感じでスペースで区切るだけです。completionは未ログインの場合はリダイレクトさせたいので
except
に含めません。3.新たに作成したviewとusers/registrations_controller.rbをroutes.rbに記述する
routes.rbRails.application.routes.draw do ... # registrations_controller.rbを有効にします。 devise_for :users, controllers: { ... registrations: 'public/users/registrations' } # 作成したusers/new.html.erbとusers/completion.html.erbをルーティングに追加します。 resources :users, only: %i[new] do get 'completion', to: 'users#completion' end end4.登録後のリダイレクト先を変更
確認画面で
登録する
が押されたときに、前の手順で用意したusers/completion.html.erb
に遷移させる必要があります。users/registrations_controller.rbclass Public::Users::RegistrationsController < Devise::RegistrationsController ... def after_sign_up_path_for(resource) public_user_completion_path(resource) end ... endデフォルトか、もしくは任意で別のページがリダイレクト先になっているかと思いますが、そのpathを前の手順で作成した
public_user_completion_path(resource)
(users/completion.html.erbのpath)に設定します。まとめ
より実用的な使い方については、私のGitHubに実際に使っているファイルを公開しているのでそちらも参考にしていただければと思います!
GitHub - MasaoSasaki/matchi質問や解釈の違い、記述方法に違和感ありましたら、コメント等でご指摘いただけると幸いです。
最後まで読んでいただきありがとうございました。
- 投稿日:2020-09-19T20:54:17+09:00
【Active Storage】ファイルアップロード時のバリデーション設定
概要
Active Storageにはデフォルトのバリデーションがないため、自前でバリデーション設定をした時のことを備忘録として記録します。
環境
・ruby '2.5.7'
・rails '5.2.3'過程
1.準備
Active Storageを導入するために以下のコマンドを実行します。
$ rails active_storage:install以下の2つのテーブルを作成するマイグレーションファイルが作成されます。
・active_storage_attachments
・active_storage_blobsrails db:migrateしてテーブルを作成します。
$ rails db:migrate2.モデルへの関連付け
モデルへの関連付けをしていきます。
ここでは、Userモデルに複数のプロフィール画像を設定する場合とします。models/user.rbclass User < ApplicationRecord has_many_attached :avatars end
:avatars
はファイルの呼び名で、:photos
、:images
などファイルの用途に合わせて好きなものが指定出来ます。Userモデルに画像用のカラムを用意する必要はありません。3.バリデーションの設定
Userモデルにバリデーションの設定をしていきます。
ここでは、次の3つの設定をしていきます。・avatar_type
アップロード出来るファイル形式を指定します。・avatar_size
アップロード出来る1ファイルの大きさ(容量)を指定します。・avatar_length
アップロード出来るファイルの数を指定します。models/user.rbclass User < ApplicationRecord (省略) validate :avatar_type, :avatar_size, :avatar_length private def avatar_type avatars.each do |avatar| if !avatar.blob.content_type.in?(%('image/jpeg image/png')) avatar.purge errors.add(:avatars, 'はjpegまたはpng形式でアップロードしてください') end end end def avatar_size avatars.each do |avatar| if avatar.blob.byte_size > 5.megabytes avatar.purge errors.add(:avatars, "は1つのファイル5MB以内にしてください") end end end def avatar_length if avatars.length > 4 avatars.purge errors.add(:avatars, "は4枚以内にしてください") end end endちなみに、
avatars.purge
で一時データを削除しています。
他の入力項目でバリデーションエラーが起きてしまうと、Rails5.2系〜6.0系以前ではモデルのインスタンスのattributeに代入した時点で、アップロードしたファイルがストレージに保存されてしまい、その結果として、blobにエラー用の一時データが溜まってしまう可能性があるためです。
(ただ、Rails6.0へのアップデートでActive Storageの機能変更があり、saveメソッドが実行された後に、ストレージに保存される仕様に変更されたので、6.0以降であれば不要です)結果
参考
ActiveStorageがCarrierWaveの代用として使えるか考える
Rails5 Active Storageを使って画像アップロード機能を実装する
- 投稿日:2020-09-19T19:57:07+09:00
Ruby のメソッド呼び出しと変数参照について注意すること
ブログ記事からの転載です。
最近、ハマっている人が何人書いたのでちょっとまとめてみます。
Ruby のメソッド呼び出し
Ruby ではメソッドを呼び出す場合に他の言語と比較して『
()
を省略してメソッドを呼び出す事』ができます。def hoge(a = nil) "#hoge(#{a})" end # 括弧がなくてもメソッドを呼び出せる p hoge # => "#hoge()" # メソッドっぽい呼び出しでもメソッドを参照できる p hoge() # => "#hoge()" p hoge 42 # => "#hoge(42)" p self.hoge # => "#hoge()"まあこれはそのとおりですね。
メソッド名と同名の変数名が定義されていたらどうなるの
問題は『同名のメソッドと変数』が混載している場合です。
この場合は『変数が参照できれば変数』を参照し、『そうでなければ』メソッドを参照します。def hoge(a = nil) "#hoge(#{a})" end # この時点では変数が定義されていないのでメソッドを優先して呼び出す p hoge # => #hoge() # 変数を定義する hoge = 42 # 変数を定義したあとでは変数を優先して定義する p hoge # => 42 # メソッドっぽい呼び出しではメソッドを呼び出す p hoge() # => "#hoge()" p hoge 42 # => "#hoge(42)" p self.hoge # => "#hoge()"この時に注意するのは『代入式よりも前であればメソッド』を参照し、『代入式よりもあとであれば変数』を参照します。
変数が定義されるタイミングは?
例えば次のように『実際に変数を定義している処理が呼ばれないケース』が Ruby では存在します。
def hoge(a = nil) "#hoge(#{a})" end if false hoge = 42 end # これはメソッド参照? p hogeこれはインタプリタ言語的には『変数が定義されていないのでメソッドが呼び出される』ことを期待する方もおられるかもしれません。
しかし、実際にはp hoge
では『変数hoge
』を参照します。
これは Ruby がソースコードを実行する仕組みに秘密があります。
Ruby ではソースコードを実行する前にまず『全 Ruby のソースコードをパースしてから』Ruby のコードを実行します。
なので、上のコードのように『実行時にそのコードが呼び出されるかどうか』というのは関係なく全ソースコードがパースされるので『代入式』が定義された時点でhoge
という変数が暗黙的に定義されたことになります。
なので、実際に if 文の中身が呼ばれるかどうか関係なく『代入式』が定義された時点で『if 文の外』でも『変数hoge
』が参照されるようになります。# 実際の実行結果 def hoge(a = nil) "#hoge(#{a})" end if false hoge = 42 end # ここでは変数を参照する # 変数のデフォルト値は nil なので nil を返す p hoge # nil後置if + 変数定義
Ruby がどのようにソースコードをパースするのかを理解するのはとてもむずかしいです。
例えば次のように『後置if でhoge
を参照しつつhoge
変数を定義する』場合どうなるでしょうか。hoge = 42 if hoge.nil? p hogeこれは
if hoge.nil?
が変数定義よりも前に処理されるので実際にはhoge = 42
という処理は呼び出されない、と考える人も多いと思います。
しかし、実際にはhoge = 42 if hoge.nil?
というコードは『これ全体で1つの処理』としてパースされます。
なので、if hoge.nil?
が呼び出された時点ですでにhoge = 42
というコードはパース済みになっており『変数hoge
は定義されている』という処理になります。
なので、先程のコードの実行結果は、hoge = 42 if hoge.nil? p hoge # => 42と、いう風に『
hoge = 42
』が処理された状態になります。
逆に後置 if でない場合は結果が異なるので注意する必要があります。# これはエラーになる # error: undefined local variable or method `hoge' for main:Object (NameError) if hoge.nil? hoge = 42 endこれは
if hoge.nil?
が変数よりも前にパースされて『変数が定義されていない状態』で if 文の条件式が実行されるためです。eval("hoge") するとどうなる
Ruby では
eval
というメソッドが存在します。
これは『実行時』に Ruby のソースコードを実行するメソッドです。def hoge(a = nil) "#hoge(#{a})" end hoge = 42 # eval に渡した文字列を Ruby のコードとして実行する p eval("hoge + hoge") # => 84上のコードを実行すると代入式よりもあとで `"hoge + hoge" を実行しているので『変数』を参照します。
では、次のようなコードを実行するとどうなるでしょうか。def hoge(a = nil) "#hoge(#{a})" end # 代入式よりも前に hoge を実行する p eval("hoge") hoge = 42先程から説明している流れからいうと『変数よりも前に
"hoge"
を実行している』のでこれは『メソッド呼び出し』になることを期待します。
しかし、実際に実行すると以下のような結果になります。def hoge(a = nil) "#hoge(#{a})" end # メソッド呼び出しではなくて変数を参照する p eval("hoge") # => nil hoge = 42なぜ、このような結果になるのかというと『 Ruby のソースコードするタイミング』と『
eval
を実行するタイミング』た異なる為です。
eval
を実行するタイミングはあくまでも『Ruby の実行時』になります。
この『実行時』というのは『Ruby のソースコードがパースされたあと』になります。
つまり『eval
を実行するタイミング』ではすでに『Ruby のソースコードがパースされたあと』になっているためhoge
という式は『変数を優先して』参照してしまうのです。
なのでeval
から変数やメソッドを参照する場合、『代入式の定義位置』に関係なく『変数』を優先して呼び出されるのです。
これはbinding.irb
を使用したときにも影響し、例えば次のように『代入式よりも前』でbinding.irb
を呼び出した時に問題になります。def hoge(a = nil) "#hoge(#{a})" end # デバッグ等で binding.irb で実行時に irb を起動する # この irb のコンソール上で hoge を参照すると『変数』を参照する binding.irb hoge = 42
binding.irb
では入力した Ruby のコードをeval
を用いて実行します。
なので、先程の例のように『変数』を参照して実行されることになります。
普段の Ruby のコードではeval
を使うととはめったにないと思うんですがこのようにbinding.irb
などを使用すると間接的にeval
を使うことになるので注意する必要があります。まとめ
- Ruby では『
hoge
』という式がメソッド呼び出しなのか変数参照なのか曖昧である- 変数が存在している場合は変数を優先し、そうでない場合はメソッド呼び出しを優先する
- 代入式より前はメソッド呼び出し、それよりあとは変数参照になる
- ただし、動的に変数を参照する場合は変数を優先するので注意する
eval
やbinding.irb
を使う場合は注意する- 基本的にはメソッド名と同じ名前の変数名は避けるべきではある
- 避けるべきではあるが実際に『どういうメソッド』が定義されているのか不透明なのでむずかしい
- Ruby ではそれが『変数』なのか『メソッド』なのかを意識でコードを書くことが重要
と、言う感じで Ruby の変数についてまとめてみました。
実際にbinding.irb
でメソッドを呼び出した場合にnil
が返ってくる事があり、よくよくコードを見てみたらbinding.irb
よりもあとで同名の変数名が定義されている事がありました。
このように Ruby ではハマりポイントがあるので注意しましょう。
- 投稿日:2020-09-19T17:26:52+09:00
【Ruby on Rails】投稿点数ランキング機能(全体表示)
目標
- ユーザーの投稿点数ランキング
- 投稿に対して評価点数を合計/平均して、その投稿ユーザーの投稿点数ランキング
- 投稿の点数ランキング(user部分を投稿に変更したら可能です)
- 投稿に対して評価点数を合計/平均して、その投稿の点数ランキング
開発環境
ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina前提
※ ▶◯◯ を選択すると、説明等が出てきますので、
よくわからない場合の参考にしていただければと思います。※数値がまだないユーザーも表示できるよう、
left_joinsとsort_byを使って、ランキング機能を実装します。
※他のランキング方法もあるため、随時投稿していきます。カラム追加
投稿に対するコメントにて、評価をつけるため追加。
ターミナル$ rails g migration AddScoreToComments score:integerdb/migrate/xxxxxxxxxxxxx_add_score_to_comments.rbclass AddScoreToComments < ActiveRecord::Migration[5.2] def change add_column :comments, :score, :integer, default: 0 end endこのままでは点数に差が生まれてきてしまうので、
viewで点数を選択式にできるように記述。app/views/posts/show.html.erb評価:<%= f.number_field :score,min:1,max:5 %>合計値を出す場合<% @sum = 0 %> <% @post.comments.each do |comment| %> <% @sum += comment.score %> <% end %> <%= @sum %>平均値を出す場合<% @average = 0 %> <% @post.comments.each do |comment| %> <% @average += (comment.score / @user.comments.count) %> <% end %> <%= @average %>準備が出来たので、本題に進みます。
controller
コントローラーが肝になります。
合計値のランキング:app/controllers/users_controller.rbdef rank @users = User. left_joins(:comments). distinct. sort_by do |user| hoges = user.comments if hoges.present? hoges.map(&:score).sum else 0 end end. reverse end平均値のランキング:app/controllers/users_controller.rbdef rank @users = User. left_joins(:comments). distinct. sort_by do |user| hoges = user.comments if hoges.present? hoges.map(&:score).sum / hoges.size else 0 end end. reverse end
補足
・left_joins(:comments):左外部結合と言って、コメントに紐づくuserを全て取得し、
コメントがない場合はnullで取得するメソッドです。こちらの解説がわかりやすいです。
【Rails】left_joinsメソッドで定義する左外部結合とは?
・distinct:重複レコードを1つにまとめるためのメソッドであり、
今回の場合はコメントが2つ以上あると、userも2つ以上取得してしまうため、
重複を回避するために使用します。
・sort_by do |user|:配列を小さい順に並び替えるメソッドです。
値としてはif以降の条件で代入していきます。
・map(&:score):scoreの値だけ、追加していくメソッドです。
こちらの解説がわかりやすいです。
Railsでよく見る arr.map(&:id) の意味
・reverse:sort_byで小さい順に並び替えたため、逆にしています。
ただし、同数値の場合、新しい順になるため、注意が必要です。
ここは解決出来ましたら再度更新します。
・hoges.size:hogesの数を取得しています。その数値を元に平均を出しています。
view
下記のようにeach降順順で表示可能
app/views/users/rank.html.erbを作成後、app/views/users/rank.html.erb<% @users.each do |user| %> <%= link_to user_path(user) do %> <%= user.name %><br> <% end %> <% end %>routing
config/routes.rbget '/rank', to: 'users#rank'参考サイト
Railsでお手軽ランキング機能
【Rails】ランキング機能の実装まとめ
今回は高いスコアを投稿しているユーザーを表示したかったため、
このような記述となりましたが、
あまり実用的ではないかもしれません。
ただ、これらのランキングを使えば、
点数を高く評価している人だけ、または低い人だけに
アプローチを取ることができるため、営業向きのランキングかと思います。また投稿の点数ランキングは口コミランキングなどを実装したい場合は、
実用的な記述になるかと思います。
- 投稿日:2020-09-19T17:06:42+09:00
未経験エンジニア転職中にで出たコードディングテスト問題
未経験転職にて出題された問題と、自分なりに調べて処理した答えを備忘録として載せます。
実力不足の自分なりに出した答えなので、修正や解説をいただけるととっても嬉しいです!
▲問題1 FizzBuzz
1から100までの数字を順番に出力する関数を作成してください。
ただし、出力する数字が3の倍数の場合には「Fizz」を、出力する数字が5の倍数の場合には「Buzz」を、出力 する数字が3の倍数かつ5の倍数の場合には「FizzBuzz」を、それぞれ数字の代わりに出力してください。
また、各数字もしくは文字列の出力の後に改行コード(LF - \n)を出力してください。fizzbuzzのコード(1..100).each do |n| # 1〜100まで処理を繰り返す def fizzbuzz(n) if n % 15 == 0 # 3と5の倍数(3✖︎5)の時にFizzBuzzを出力 puts "FizzBuzz" elsif n % 3 == 0 # 3の倍数の時にFizzを出力 puts "Fizz" elsif n % 5 == 0 # 5の倍数の時にBuzzを出力 puts "Buzz" else puts n # 上記の条件に当てはまらない場合に数字を出力 end end puts fizzbuzz(n) # fizzbuzzメソッドを出力 end▼問題2 素数を出力
1から1000までの素数を出力する関数を作成してください。
素数の定義は下記の通りである。素数とは、1より大きい自然数で、約数が1と自分自身のみである数字である。
素数を出力するコードprimeRetrun = [] # primeReturnを配列にする (1..1000).each do |n| # 1〜1000まで繰り返し処理 next if n == 1 # ifの条件がtrueの場合、nextで次の処理に移る if n == 2 primeRetrun.push(n) # pushメソッドでprimeReturnの配列の中にnを加える next # 次の処理に移る end judge = true primeRetrun.each do |number| if n % number == 0 # 素数の処理 judge = false break # 強制的に今のeach処理を終わらせて最初のeach処理に戻る end end primeRetrun.push(n) if judge # judgeがtrueだった場合のみ、pushメソッドでprimeReturnの配列の中にnを加える end puts primeRetrun # 配列の処理を加えて入れる※rubyの場合もっと簡単にできます。
rubyの簡単コードrequire 'prime' # primeライブラリを読み込み Prime.each(1000) {|x| p x} # あらまぁとっても簡単。。。▼問題3
0から9999までの数字を順番に1刻みで出力するプログラムを作成しました。 このプログラムを実行した際に、数字の7は何回出力されますか? 例えば、7777が出力された場合、数字の7は4回出力されたものとしてカウントします。 この問題の答え、もしくは答えを計算するためのプログラムを解答してください。
素数を出力するコードnum = [*(1..9999)].to_s # to_s配列の中身を文字列に変換 puts num.count("7") # 配列の中身の文字列の中から7の文字数をカウントする参考にしたURL
https://qiita.com/motoki4917/items/ffc89d955e20b91d1014
https://techacademy.jp/magazine/7507
https://docs.ruby-lang.org/ja/latest/class/Prime.html
https://docs.ruby-lang.org/ja/latest/method/Array/i/inspect.html
https://qiita.com/syo19961113/items/9f189424b5af5e084d33
- 投稿日:2020-09-19T15:47:47+09:00
[Visual Studio Code] rbenv 使用時のデバッグ実行で syntax error が出る
環境
項目 バージョン OS Mac Catalina 10.15.6 Visual Studio Code 1.49.0 Ruby 2.7.1 Rubyのバージョン管理として、 rbenv を使用していた
前提
デバッグに必要な gem は Gemfile に追加しており、インストール済みの状態だった
gem "ruby-debug-ide" gem "debase"エラー
Visual Studio Code 左側の Run を選択し、 [Add Config] -> [RSpec - active spec file only] を選ぶ
上記の設定でデバッグしたところ、画面下のステータスバーが実行中を示すオレンジ色のまま、何も進まない状態になった
ReRunすると下記のように [OUTPUT] ビューに以下のエラーが出力される
Uncaught exception: /Users/pldb/.rbenv/shims/rspec:3: syntax error, unexpected tSTRING_BEG, expecting do or '{' or '(' [ -n "$RBENV_DEBUG" ] && set -x ^ /Users/pldb/.rbenv/shims/rspec:3: syntax error, unexpected ']', expecting end-of-input [ -n "$RBENV_DEBUG" ] && set -x ^ /Users/pldb/.rbenv/versions/2.6.6/bin/rdebug-ide:23:in `load': /Users/pldb/.rbenv/shims/rspec:3: syntax error, unexpected tSTRING_BEG, expecting do or '{' or '(' (SyntaxError) [ -n "$RBENV_DEBUG" ] && set -x ^ /Users/pldb/.rbenv/shims/rspec:3: syntax error, unexpected ']', expecting end-of-input [ -n "$RBENV_DEBUG" ] && set -x ^ from /Users/pldb/.rbenv/versions/2.6.6/bin/rdebug-ide:23:in `<main>'結果
.vscode/launch.json を以下のように変更した
変更前
{ "version": "0.2.0", "configurations": [ { "name": "RSpec - active spec file only", "type": "Ruby", "request": "launch", "program": "/Users/pldb/.rbenv/shims/rspec", "args": [ "-I", "${workspaceRoot}", "${file}" ] } ] }変更後
{ "version": "0.2.0", "configurations": [ { "name": "RSpec - active spec file only", "type": "Ruby", "request": "launch", "program": "${workspaceRoot}/bin/rspec", "args": [ "-I", "${workspaceRoot}", "${file}" ] } ] }これは Visual Studio Code のデフォルト設定そのままである
ただし、binstub を使用した原因
launch.json を生成した時点の
"program"
は"${workspaceRoot}/bin/rspec"
だったところが使用しているrspecのパスが正しいものと考えて以下のパスに差し替えた
% which rspec /Users/pldb/.rbenv/shims/rspec表題のエラーはこれによって発生した
参考: rspec doesn't execute as a program, it is parsed as if it's a code file.
実際に参照していた shims配下のrspec の中身はこれである
#!/usr/bin/env bash set -e [ -n "$RBENV_DEBUG" ] && set -x program="${0##*/}" if [ "$program" = "ruby" ]; then for arg; do case "$arg" in -e* | -- ) break ;; */* ) if [ -f "$arg" ]; then export RBENV_DIR="${arg%/*}" break fi ;; esac done fi export RBENV_ROOT="/Users/pldb/.rbenv" exec "/usr/local/Cellar/rbenv/1.1.2/libexec/rbenv" exec "$program" "$@"これはrbenvが生成した(rspecを参照するための)bashファイルであり、これをそのまま読み込んだ結果エラーになっていた
つまり rspec を十分に理解していないことが原因であった対策
binstub を使用する
参考: 【翻訳+解説】binstubをしっかり理解する: RubyGems、rbenv、bundlerの挙動
プロジェクト内で使用するrspecにするために、 binstub で
${workspaceRoot}/bin/rspec
を生成する
${workspaceRoot}
はVisual Studio Code で展開したディレクトリのフォルダを指すこのディレクトリまで移動してから以下を実行する
% bundle binstubs rspec-core % ./bin/rspec -v RSpec 3.9 - rspec-core 3.9.2 - rspec-expectations 3.9.2 - rspec-mocks 3.9.1 - rspec-support 3.9.3
これでデフォルトの設定のまま実行できる
gem を作成している場合は、(他コントリビュータに影響しないよう)binフォルダを避ける
% bundle binstubs rspec-core --path exe % ./exe/rspec -v RSpec 3.9 - rspec-core 3.9.2 - rspec-expectations 3.9.2 - rspec-mocks 3.9.1 - rspec-support 3.9.3この場合は launch.json の
"program"
のパスが${workspaceRoot}/exe/rspec
になる余禄
プロジェクトの rspec のバージョンに拘らない場合は、以下のように
/usr/local/bin/rsepc
を指定しても動作する{ "version": "0.2.0", "configurations": [ { "name": "RSpec - active spec file only", "type": "Ruby", "request": "launch", "program": "/usr/local/bin/rspec", "args": [ "-I", "${workspaceRoot}", "${file}" ] } ] }それと、これは別件ではあるが、 launch.json の設定に関してもう一つ取り上げる
gemspec でエンコーディングのエラーが発生したUncaught exception: [!] There was an error parsing `Gemfile`: [!] There was an error while loading `xxx.gemspec`: invalid byte sequence in US-ASCII. Bundler cannot continue.見ての通り、エンコーディングの設定が原因である
参考: Encoding issue when using gem 'xcodeproj'
gem 開発時にデバッグする場合の launch.json は、最終的に以下のようになった
{ "version": "0.2.0", "configurations": [ { "name": "RSpec - active spec file only", "type": "Ruby", "request": "launch", "program": "${workspaceRoot}/exe/rspec", "args": [ "-I", "${workspaceRoot}", "${file}" ], "env": { "LANG": "en_US.UTF-8", "LC_COLLATE": "en_US.UTF-8", "LC_CTYPE": "en_US.UTF-8", "LC_MESSAGES": "en_US.UTF-8", "LC_MONETARY": "en_US.UTF-8", "LC_NUMERIC": "en_US.UTF-8", "LC_TIME": "en_US.UTF-8", "LC_ALL": "en_US.UTF-8" } } ] }
- 投稿日:2020-09-19T15:11:33+09:00
RSA署名検証って何をどうしてるの?
この記事はRubyのOpenSSLライブラリを使ってRSA署名検証がどのように行われるのか疑問に思いコードを書いてみた備忘録のようなものです。
公開鍵暗号やRSA暗号について詳しく踏み込むような内容ではありません。公開鍵暗号方式の署名という行為はどうやらメッセージを秘密鍵で暗号化したものであるということみたいです。
(RSA暗号での署名はメッセージを秘密鍵で 復号化 するというのが正しいという話もあります。RSAの産みの親がそう言っていたのだとか。)
ここでは署名検証は署名を公開鍵で 復号化(public_decrypt) して確認するので署名は秘密鍵で 暗号化 という定義にしておきます。それでは、Rubyを使って署名の作成と署名検証を行っていきます。
require 'openssl' # 鍵の作成 rsa = OpenSSL::PKey::RSA.generate 2048 # メッセージ M = "署名検証手順確認" # ハッシュ関数指定 digest = OpenSSL::Digest::SHA256.new # 署名作成 sig = rsa.sign(digest, M) => "#I\xE1\xE9\xE3\x95\xCE\xE2U\x8EwU\xF49a\f\xE7\x11\xF5\xC5|H\xF0\xB1\x9Ct\xE5\xB3\x93Tj\xD2\xFC,\x0F1+\xB9\x88p\xEEe\x99#\xCC\xB3\x81\x98U\x01Uc\xC3*\x92\v\xD3(\xE9~&@{\xA1S\x83\v\x83\xFF\xDF\xB8\x82r\xC8\x85|\xC1^\x9F>\xDAc\x17\x9A\xEB\xA8\x1E\xA8\xA4v\xC0\xA3\x98f\xFF\x87^\xFB9#\x98l\xE1\xA9\xB5g-\a\xC3\xAD\x17&\x8C\x84\xAD\x06\xB7\x04c\xA9\xB4{w\x15\xDB\f\xCFQ\x91\xF8t\x16\x8A\x8A\xBC\xB2\xC5H\xD1\xC8p}\xC7\xD6\a\x0F'm\xDB\tT\xDF4\xAAv\xF1\xD4\x14\x86\xD0\x82?\xA6\xB8\xC8\x91\xA8Su\x81Yc9\x83\x94$\x96I\xC9%\xE3\x82\xD6\xB6j\xD1\xB9\xDB\xE0\xD80=v\xBD\n\xDC\xFB:\xC9\x01\xA6\xF3\xC2\xBAT\xAE\x98\xE7B\x10\xE7$\x12_\xEC\x1Ar\x86B\xDEC<:nfV\x12z\xC8%Ng\xF0\xCF\xAA\xD2\x94\xC1\xC0\x1C\x9D,>\xF7+\x83s\xCBX)!\x90)W\xF0\xEA" # 署名検証 rsa.verify(digest, sig, M)上記で署名の作成と検証ができています。
・・・
・・・検証って一体何してるの?
って自分は思いました。こちらの記事と記事中にあるブログの画像を参考にさせていただきました。
署名検証は
- メッセージをハッシュ関数でハッシュ値H1を出す
- 署名を公開鍵で復号化しEMSA-PKCS1-v1_5のデータを得る
- EMSA-PKCS1-v1_5データのパディングを除去してH2を得る
- H1とH2を比較するという手順を踏めばRubyのOpenSSLでは署名検証出来そうです。(本当は参考記事のようにさらに処理をしないといけないのかなと思います。)
実際にコードで実験してみます。
# 署名を復号化 decrypted = rsa.public_decrypt(sig) => "010\r\x06\t`\x86H\x01e\x03\x04\x02\x01\x05\x00\x04 Un\x1A\x02^\xDE\x11Q\x9C~\xD3c\xE7H}6\x88\xAF\x1E\xC5\xAC7#\xB6\xC4@\"_]\xB9W\x10" # 2048bit鍵なので32byteを取り出す m_hash = decrypted[-32, 32] => "Un\x1A\x02^\xDE\x11Q\x9C~\xD3c\xE7H}6\x88\xAF\x1E\xC5\xAC7#\xB6\xC4@\"_]\xB9W\x10" # メッセージのハッシュ値 digest.digest(M) => "Un\x1A\x02^\xDE\x11Q\x9C~\xD3c\xE7H}6\x88\xAF\x1E\xC5\xAC7#\xB6\xC4@\"_]\xB9W\x10" m_hash == digest.digest(M) => true署名を復号化したものと、メッセージをハッシュしたものが一致しました。
検証成功ですね。検証失敗パターンも確認しておきましょう。
m_hash == digest.digest("検証失敗するよ") => false想定通り失敗しました。
署名検証
verify
の中ではこのような処理が行われているようです。僕と同じ疑問を持った方の参考になれば幸いです。
この領域に強い方のご指摘や修正リクエスト大歓迎です。
- 投稿日:2020-09-19T12:25:47+09:00
実務経験1週間のまとめ
- 投稿日:2020-09-19T12:12:56+09:00
《未経験→webエンジニア》実務5日目
昨日投稿できなかったので、今日投稿します。
この記事の目的
自分がやったこと、知らなかったこと、やるべきことを明確にし
1日あたりの成長速度を速める。【今日やったこと】
APIテスト
イシューに上がっている軽微な内容の修正【知らなかったこと】
・APIのレスポンスは、コントローラーに種別で作られている
・メモ帳のデフォルト設定で””が逆さになっており、エラーが起きる
・現在いるブランチ名はVScodeの左下に表示されている!知らなかったテストbreakman→セキュリティ系のテストを行ってくれる
今回の案件では、breakman,rspec,rubocopの3段階でテストする
expected: "期待されている文言" got: "実際の文言"ここが違わないかをチェックする
API文言の修正だけでなく、ステータスコードもセットで直すようにする
HTTPのステータスコードhttps://qiita.com/terufumi1122/items/997e24dde87f807e3944
- 投稿日:2020-09-19T11:18:20+09:00
Rails 6で認証認可入り掲示板APIを構築する #14 seed実行時間の表示
←Rails 6で認証認可入り掲示板APIを構築する #13 認証ヘッダの付与
完成図
$ rails db:seed -----user start----- count from: 0 count to: 10 3.4542s -----user end----- -----post start----- count from: 0 count to: 13 0.1095s -----post end----- 3.5883sseedsファイルの編集
まずはcontrollerの修正と同じく、postはuserから生成するため、user_seeds.rbから作っていきます。
db/seeds/user_seeds.rb# frozen_string_literal: true unless User.exists? 10.times do |i| email = "test#{i + 1}@example.com" User.create!(email: email, password: "password", uid: email, provider: "email", name: Faker::Name.name) end endとりあえず10ほぼユーザーを生成してみましょう。
続いて、post_seeds.rbを上記で生成したユーザーに所属させる形で生成します。
db/seeds/post_seeds.rb# frozen_string_literal: true unless Post.exists? users = User.all users.each do |user| Random.rand(0..3).times do user.posts.create!(subject: Faker::Lorem.word, body: Faker::Lorem.paragraph) end end end全ユーザーを取得し、0から3件ランダムで投稿を生成します。
Random.rand(x..x)
はseedでよく使う手法なので覚えておくと良いです。db/seeds.rbの編集
db/seeds.rb# frozen_string_literal: true seed_models = %i[user post] all_process_time = Benchmark.realtime do seed_models.each do |model| puts "-----#{model} start-----" puts "count from: #{model.to_s.classify.constantize.count}" process_time = Benchmark.realtime do require "./db/seeds/#{model}_seeds" end puts "count to: #{model.to_s.classify.constantize.count}" puts "#{format('%.4<time>f', time: process_time)}s" puts "-----#{model} end-----" end end puts "#{format('%.4<time>f', time: all_process_time)}s"$ rails db:seed -----user start----- count from: 0 count to: 10 3.4542s -----user end----- -----post start----- count from: 0 count to: 13 0.1095s -----post end----- 3.5883smodelが増えてきて処理時間が伸びてきたら、どこがボトルネックになっているのか調査しやすくなるはずです。
続き
- 投稿日:2020-09-19T10:52:23+09:00
[Rails] User検索機能を実装する
概要
Railsプロジェクトで掲示板サイトを作成中、User検索機能を実装する機会がありました。
備忘録としてここに手順を残しておきます。ルーティングの追加
GET /users/searchでUsersコントローラのsearch アクションにルーティングされるようにconfig/routes.rbを編集します。
config/routes.rbresources :users do get :search, on: :collection endusersコントローラーの編集
searchアクションを作成します。
検索文字列はsearch_keywordフィールドへの入力とするので、params[:search_keyword]で取得します。app/controllers/users_controller.rbdef search if params[:search_keyword].present? @users = User.where('name LIKE ?', "%#{params[:search_keyword]}%") else @users = User.none end endビューの追加
app/views/users/search.html.erb を作成します。
views/users/search.html.erb<h1>User search</h1> <%= form_tag search_users_path, method: :get do %> <%= text_field_tag :search_keyword %> <%= submit_tag "Search", username: :nil, class: "button is-info" %> <% end %> <%= render 'users/users', users: @users %>User の情報が入っている app/views/users/_users.html.erb を既に作っていたので render で呼び出しました。
完成
以上でRailsプロジェクトにUser検索機能を実装することができました。
ありがとうございます。
- 投稿日:2020-09-19T10:33:31+09:00
[Rails]ストロングパラメーターにuser_id(外部キー)を記述する方法
投稿内容
今回はストロングパラメータに外部キーを記述する方法をアウトプット。
実装方法
controller.rbprivate def item_params params.require(:item).permit(:name, :description, :category, :brand, :condition, :shipping_cost, :prefecture_id, :shipping_day, :price, images_attributes: [:image]).merge(user_id: current_user.id) endこのように
mergeメソッド
を使い記述。
今回の場合は、ログインしているユーザーのidがuser_id
としてパラメーターに保存される。最後に
今回は簡潔にアウトプット!参考にして下さい!
- 投稿日:2020-09-19T02:40:41+09:00
bundle updateをしても、繰り返し促される時の解決法
To update to the latest version installed on your system, run `bundle update --bundler`. To install the missing version, run `gem install bundler:2.1.4`このようなエラーが繰り返し表示されたときは、
gem update --system
を実行すると解決する場合があります。
- 投稿日:2020-09-19T01:53:00+09:00
form_withメソッドの使用方法
【概要】
1.結論
2.どのように使用するか
1.結論
<%= form_with(model or URL, ) do |f| %>と使用する!
2.どのように使用するか
自分はこのように使用しました!
views/time/new.html.erb<%= form_with(model: @time, local: true) do |f| %>自分は”model”に@timeでインスタンス変数を入れました。
modelの後にurlでpath指定してあげるとpathによってmethodも自動で振り分け機能になり、そしてアクションも指定できます。またpathの中に(****.id)と指定するとidを引っ張った状態でアクションを行えます!class=""指定してあげて、cssにあてることもできます!
|f|はヘルパーメソッドに適用でき、form_withの中身を"f."がついているものに入れ込むことができます!
|f|は変数のようなものなので使いやすい名前で統一したもらえばOKです!f.label
f.checkout
f.password_field
f.email_field等のヘルパーメソッドに適用できます!