20210917のRubyに関する記事は13件です。

?インターネット老人?のためのホームページ(死語)リフォーム術

この記事の対象 ~00年代初頭にホームページ作っていて、現在放置中……という人、あるいはそういう人から依頼されて昔のフォルダを受け取った人が対象になります。 スキル的にはjQuery(Bootstrap)なら何とか勢~(バックにも関心がある)SPA初心者勢を想定しています。 手順 1.本当に自前でやる必要があるか考える Webサービスが氾濫する現在、現在サイトにある機能を本当に自前で提供する必要があるか考えましょう。 日記 まぁ最有力はブログへの移行ですね。黒歴史を消す人も多いですが、逆に過去の日記みたいなもんで、残しておきたいと思う人もいるかと思います。ていうかホームページは放置してて日記にあたる部分だけ流石にブログに移行してる人も多いかと思いますね。 何らかの理由でブログに移行できない、不適切だと思う場合はスクレイピングして文章データをmdやらjsonに纏めて、今流行りのGatsbyあたりに手を出すのも良いのではないでしょうか。 イラスト これは現行のシェアとしてもシステム的にもpixivへ丸投げするのが一番妥当かと思います。 画像ギャラリー系のライブラリを入れて自前のサイトで見せることもできますが、pixivと二重管理になって放置する可能性が高いかと。 小説 これは難しい。投稿サイトは昔から山ほどありますが、なろうを始め色がついてたりするので……。(2~3年で閉鎖しないという意味で)安定してて、ジャンル問わずで一強みたいなのがあればいいんですが。 あと00年代初頭って「Web小説ならではリッチ表現を目指そう」的な流れもあって、小説本文中に挿絵画像ぶちこんだり、JSやフォントタグ弄りやってたりする小説もそこそこあるので、そこらへん守る必要がある(ギミックが前提)があったり、その系譜を現代の技術で更に進化させたいという気骨の方は自前も全然アリだと思います。 掲示板 これも難しい。 SNSの直接交流やハッシュタグ交流で代替できちゃってそうで完全には出来てないので、「アカウントを持たなくても書ける、個人管理のフォーラム」のニーズは確かにあるんですよ。 ただ当時でいうところのCGI(死語)がPerl/PHP+ただのログファイルで出来てたのに対し、現在はバックエンド系言語(Ruby/PHP等) + フレームワーク + DBが普通かつ、今時の設計だとバックエンドはAPIのみとなって、表示面はフロントエンドでやる必要があると敷居上がりまくってるんですよね。真っ向からやるにはバックエンドの勉強をガッツリしないときついかと。 OSSのフォーラムアプリも調べましたが、需要がニッチ化したのと、今だとバックエンドAPI+フロントエンドのセット提供になり、なおかつ密結合にならざるを得ないので、今一つ開発が盛り上がってない印象を受けました。現行問題なく動いてるのならそのまま+SNS交流で逃げてもいいのではという感触はありますね。 ゲーム系チャットアプリのイメージが強いですが、discordとかで丸投げできないかなーというのは考えたりしますが、使ったことがないので(ry チャット 掲示板と同じくdiscordに丸投げできないかな~(ry 2. WebスクレイピングしてHTMLから実データを取り出して整形する 昔はHTMLファイルの中に装飾データ(fontタグ)や実データを含めて全てが詰まっていたので、解析してオブジェクトの形に纏める(=スクレイピング)のは必須ですね。DOMを、tableタグを、ひたすら掘り続けるのだ……⛏ ゲーム攻略サイトとかデータ系サイトはここの工数を覚悟しといた方がいいです。抽出もさることながら、使い勝手が悪いとか色々データ整形したくなると思うので、延々とデータ整形することになります(体験談) ところでスクレイピングといえばPython (というかBeautifulSoup)がオススメとされていますが、「Webフロントエンド系の技術は仕方ないにせよ、Pythonまで手出すのはキツイ……」と思う方も多いかと思います。 そういう方は、そもそも自分のサイトであることを活かし、 ローカルの開発サーバー(手っ取り早いのはVSCodeの拡張機能のLiveServerとか)を用意 自サイトにJSのスクレイピングプログラムを仕込んでデータオブジェクトを作る 以下のJSでJSONファイルを生成してダウンロードさせる export const downloadJsonFile = (data: unknown, baseName: string): void => { const blob = new Blob([JSON.stringify(data)], { "type": "application/json" }) const fileName = `${baseName}.json` const url = URL.createObjectURL(blob) //aタグを生成し、クリックしたことにしてDLさせるというアプローチを取る //かなり無理くり感あるが現状これがベストプラクティスな模様。 const aTag = window.document.createElement("a") document.body.appendChild(aTag) aTag.download = fileName aTag.href = url aTag.click() aTag.remove() URL.revokeObjectURL(url) //生成したURLが保持されてしまうので解放する } こういう感じで対処しましょう。ちなみに自分はJSでファイルを生成→DLさせられるのを知らなくて、途中までconsole.logに吐き出し→エディタにコピペでせっせとJSONファイルを作ってました? 参考:JavaScriptでファイルダウンロード処理を実現する - Qiita 3.旧サイトとの連携を気にしつつ好きな技術で作り直す わざわざ作り直したいと思うぐらいですし、サイトの規模としてはそこそこ大きいですよね?となると、旧サイトと繋がりを意識しつつ徐々に入れ替えていく形を取る方が良いかと思います。 技術面に関してはお好きな技術で……としか言いようがありませんが、最近のトレンドから言うと大規模→React/小規模→Vue or Svelteという形になるのかなと思います。 また元が静的なウェブサイトという特性からリフォーム後も静的な特性が強いかと思われるので、SSGとの親和性が高いのかな~とも感じます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Ruby] AtCoder過去問 B - Nice Shopping

はじめに AtCoder過去問B問題をRubyで解いてみました。 よろしくお願いします。 問題はこちらから確認してください↓ B - Nice Shopping はじめに入力を受け取ります。 今回は少し面倒でした。 a, b, m = gets.split.map(&:to_i) a_ary = gets.split.map(&:to_i) b_ary = gets.split.map(&:to_i) m_ary = [] m.times do |i| m_ary << gets.split.map(&:to_i) end 割引券の配列m_aryの中は配列の中に配列を入れています。m_aryの中のそれぞれの配列が割引券一枚の条件を示しています。 割引券を使わずとも一番安い組み合わせが存在する可能性がありますので、price_aryという配列を作って代入しておきます。 a, b, m = gets.split.map(&:to_i) a_ary = gets.split.map(&:to_i) b_ary = gets.split.map(&:to_i) m_ary = [] m.times do |i| m_ary << gets.split.map(&:to_i) end price_ary = [a_ary.min + b_ary.min] 割引券を使った場合の金額もこのprice_aryに入れていきます。 割引券の使った時の金額は例えば1枚目(配列m_aryの先頭)であれば下記のように表せます。 a_ary[m_ary[0][0]-1] + b_ary[m_ary[0][1]-1] - m_ary[0][2] 2枚目(m_aryの2番目も配列)の場合は a_ary[m_ary[1][0]-1] + b_ary[m_ary[1][1]-1] - m_ary[1][2] これを利用してtimesメソッドで処理を行います。 割引券の数だけ繰り返すようにして、出来上がった金額はprice_aryに入れていきます。 そして最後にminメソッドでprice_aryの中の一番小さい要素を出力したら完成です。 a, b, m = gets.split.map(&:to_i) a_ary = gets.split.map(&:to_i) b_ary = gets.split.map(&:to_i) m_ary = [] m.times do |i| m_ary << gets.split.map(&:to_i) end price_ary = [a_ary.min + b_ary.min] m_ary.length.times do |i| price_ary << a_ary[m_ary[i][0]-1] + b_ary[m_ary[i][1]-1] - m_ary[i][2] end puts price_ary.min
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Example title

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

fakerを使って投稿に対してのダミーコメントを作ってみた

現在投稿系のアプリを作成しており、1投稿に対してコメントを複数つけるようにしました。 そこでコメントが少ない場合なら良いのですが増えてきたときにコメントを見るために下までスクロールしないといけなくなります。 自分がユーザーでも面倒くさいので他の方法を考えました。 2つ考えてみました 1つ目の方法は (クリックしてコメントを表示)みたいなボタンを作ってボタンがクリックされたら表示する。という動作です これはjavascriptを使って実装できると思いました。 普段は@commentを(display:none)で消しておいて、onclickでshowさせるみたいにできるはずです。 以下のサイトが参考になると思います。 2つ目の方法は gem 'kaminari' を実装して、設定した数だけ表示して他の要素はページを切り替えることで見れるようにすることです ↓こんな感じ こっちが簡単かなと思ったのでkaminariでやっていこうと思います kaminariを使ったのpaginationの実装の仕方は今回は省きます。 こちらの記事を参考にさせて頂きました! いざ実装! まずはkaminariを導入します 投稿の詳細画面でコメントを表示させ、1ページに付き3件のコメントを表示させたいと思います posts_controller.rb def show @comments = Comment.all.order(created_at: :desc).page(params[:page]).per(3) end orderで投稿が新しい順に表示します。 3件の指定は .per に渡している数字です ひとまず機能はできたのですが、ちゃんと動くか分かりません。 動作を確認するためには大量のコメントデータを作る必要があるのですが、1つ1つ作っても良いのですがめちゃくちゃ面倒なのでgemを使います ダミーデータを作るには、「faker」というgemを使うとすぐに実装できます 今回はコメントのダミーだけ作りたいので、コメントする投稿は1種類でコメントするuserと内容だけをダミーにしたいと思います。 ダミーのユーザーは下のコードで作りました。 nicknameを見ればわかると思いますが、そうですドラゴンボールのキャラをランダムで作りました笑 他にもポケモンやワンピースなどでも作ることができます! 20.times do |n| User.create!( nickname: Faker::JapaneseMedia::DragonBall.unique.character, email: Faker::Internet.unique.email, password: "3150test", password_confirmation: "3150test" ) end ダミーの投稿に関しては、 commentsテーブルのカラムがuser_id, post_id, contentを入れています。 ここでどれか指定を忘れていると適用する時にエラーになるので気をつけて下さい user_idは先ほど作成したダミーを使うので user_id: rand(1..20) post_idは固定するので試したい投稿のidを入れて下さい contentんはランダムで適当なものを作るので content: Faker::Lorem.sentence 10.times do |n| Comment.create!( user_id: rand(1..20), post_id: 4, content: Faker::Lorem.sentence ) end こんな感じで作ることができます! まとめ 今回は調べても出てこないようなものだったのでそもそもが実装する必要がないものかもしれません笑 でも自分が試したいものを作れたので満足です! ちゃんとpaginationも動いてくれたし、超サイヤ人2の悟空にもコメントもらえました! もし同じようなことを考えている人がいたら活用してやってください! ありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

extend Activesupport::Concernについて

concernsに定義するモジュールでよく書かれているがいまいち何をしているのかよくわかっていなかったので調べました。 結論 単純に言えば、モジュールでのクラスメソッドの定義やそれをincludeする側でクラスメソッドとして追加する方法、クラスレベルでのメソッド呼び出しの容易な方法を提供してくれるものだと理解しました。 具体例 具体例は以下のページと同じものです。 https://api.rubyonrails.org/v6.1.4/classes/ActiveSupport/Concern.html 例えば、モジュールがincludeされたときに特定の処理を呼び出したり、モジュールのメソッドをクラスメソッドとして追加したい時、通常以下のように書きます。 module M # https://docs.ruby-lang.org/ja/latest/method/Module/i/included.html def self.included(mod) # includeする側(例えばクラス)の特異メソッドとしてClassMethodsを追加する -> クラスメソッドとして呼び出せる mod.extend ClassMethods mod.class_eval do before_action :xxx end end module ClassMethods # クラスメソッドを定義 end end ActiveSupport::Concernを利用すると以下のように書けます。 module M extend ActiveSupport::Concern included do before_action :xxx end class_methods do # クラスメソッドを定義 end end ActiveSupport::Concern内のicludedやclass_methodsなどのメソッドが面倒な記述を肩代わりしてくれ、簡潔に書けるようになります。 (extendしているのでMのクラスメソッドのように扱える)    また、モジュール間の依存関係もいい感じに整理して書けるようにしてくれます。 例えば以下の場合、HostクラスはBarモジュールをincludeしたいが、BarモジュールはFooモジュールに依存しているので、FooモジュールもHostがincludeしなければならない。 module Foo def self.included(base) base.class_eval do def self.method_injected_by_foo ... end end end end module Bar def self.included(base) base.method_injected_by_foo end end class Host include Foo # Hostが直接関係のないモジュールまでincludeしている include Bar end Barだけincludeしようとするとエラーになる。 class Host # include Foo include Bar end ==> undefined method `method_injected_by_foo' for Host:Class (NoMethodError) ActiveSupport::Concernを使うと依存関係の記述を綺麗に整理できます。 module Foo extend ActiveSupport::Concern included do def self.method_injected_by_foo ... end end end module Bar extend ActiveSupport::Concern include Foo included do self.method_injected_by_foo end end class Host include Bar end 参考 ActiveSupport::Concernが具体的に提供してくれるもの。(ソースコード) https://github.com/rails/rails/blob/83217025a171593547d1268651b446d3533e2019/activesupport/lib/active_support/concern.rb#L110
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

要素の最後を求める時

◼️ famiry = ["suzuki", "takurou", "gou",・・・・ "qiita"] 例えば上記の様な配列があったとする。最後の要素だけを取り出す時、suzuki 君から順に最後まで数えてqiita君の順番が98番だった時、puts famiry[98] と書き出力するのはそごくめんどくさい。 ◼️ こんな時、こんな問題を解決するのが [配列の要素数 -1]を使うこと。 書き方: famiry[famiry.lenght -1 ]      puts famiry 上記の様な書き方を行うことで全体の要素数から最後の値ふだけを出力できる。そして、数えるみたいなめんどいことはやらなくておくなる。 今日の投稿は以上です。 wagaでした!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

エラー:No route matches [GET] "/new_user_session_path"

環境 MacOS BigSur Ver11.5.2 Ruby 3.0.2 Rails 6.1.4.1 状況 Railsアプリを実装中、下記のエラー発生 No route matches [GET] "/new_user_session_path" 一見問題なさそう app/views/layouts/_header.html.slim li = link_to 'ログイン', 'new_user_session_path' pathを確認したけど間違ってない $ rails routes ... new_user_password_path GET /users/password/new(.:format) devise/passwords#new ... 解決方法 原因:pathを””で囲っていた… 初歩的なミスすぎて自分で自分に引きました app/views/layouts/_header.html.slim li = link_to 'ログイン', new_user_session_path 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Ralis でデータベースにあるテーブルの中身を指定して取得してviewに表示する方法

データベースのテーブルの中身を指定して取得。 テーブル名:lists カラム名:title def index @lists = List.find_by(title:"リスト") @lists_number = List.find_by(number:46) end あとはviewに記述すれば表示されます。 <%= @lists.title %> <%= @lists_number.title %>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

エラー:Could not find 'spring' (= 2.1.1) among 167 total gem(s) (Gem::MissingSpecError)

環境 MacOS BigSur Ver11.5.2 Ruby 3.0.2 Rails 6.1.4.1 状況 RailsアプリをHerokuへデプロイした際に下記のエラーが発生 Could not find 'spring' (= 2.1.1) among 167 total gem(s) (Gem::MissingSpecError) 原因 どうやらこのgemが悪さをしているらしい Gemfile group :development do (略) gem 'spring' gem 'spring-commands-rspec' end 疑問点 developmentだけのgemなのになぜデプロイ時にエラーが出るのか謎 解決策 この2つのgemをコメントアウト Gemfile group :development do (略) # gem 'spring' # gem 'spring-commands-rspec' end bundle installも忘れずに! デプロイし直すと正常にデプロイ完了! 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

結合テストを書いていく①

はじめに 単体テストコードはフリマアプリ作成時にしっかり書いたのですが、結合テストは書いていなかったのでオリジナルアプリでは書いていきたいと思います。 その中で学習したことをアウトプットとして投稿させて頂きます。 単体テストと結合テストの違い(単体テストの場合) 単体テストは機能ごとにテストを行います。 例えばuserの単体テストコードの場合 user_rspec.rb describe 'ユーザー新規登録' do context '登録できるとき' do it 'nickname,email,password,company_name,profession_idが存在する場合は登録ができる' do end end context '登録ができないとき' do end end モデルやコントローラーの機能ごとに問題がないかバリデーションの挙動を確認します。 単体テストと結合テストの違い(結合テストの場合) 結合テストの場合はユーザーがアプリを使用する一連の流れを確認するものになります。 ホームページ → 新規登録ボタンをクリック → 新規登録フォームに入力し完了ボタンをクリック → ホームページに遷移する この結合テストを実行するためにはSystem Specという技術を使用します。 この技術を使用するためにはCapybaraというGemが必要ですが標準で記載されているかと思われます。 ファイルの作成 実施にテストコードを記述していくためにファイルを作成します。 今回はユーザーについての結合テストコードを記述していきます。 ターミナル rails g rspec:system users これでファイルは作成されます。 それではexampleを整理していきます 新規登録できる場合を考えていきます。 この時のポイントは、「ユーザー目線で考える」ことです。あまり細かく考えずに、「ブラウザでどのような操作をすると、どうなるのか」を考えます。 spec>system>users_spec.rb require 'rails_helper' RSpec.describe "新規登録", type: :system do before do @user = FactoryBot.build(:user) end context 'ユーザーが新規登録ができる時' do it '正しい情報を入力すればユーザー新規登録ができてトップページに移動する' do # トップページに移動する # トップページにサインアップページへ遷移するボタンがあることを確認する # 新規登録ページへ移動する # ユーザー情報を入力する # サインアップボタンを押すとユーザーモデルのカウントが1上がることを確認する # トップページへ遷移したことを確認する # ログアウトボタンが表示されることを確認する # サインアップページへ遷移するボタンや、ログインページへ遷移するボタンが表示されていないことを確認する end end end 実際にはアプリを操作しながら書いていくと分かりやすいです。 次は実施にコードを書いていきます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

未ログイン状態のユーザーを転送

今回は自分が最初よくわからなくて苦戦した部分です。 例を出すと、ログインしてない状態でも、「投稿する」ボタンの遷移先であるURLを直接入力すると、新規投稿ページにアクセスできてしまうという事。 一体どういうこと?って感じでした汗 わかりやすく言うと、URLに直接、新規投稿や編集のパスを入力すると遷移できてしまうと言うこと! つまり、ログインもログアウトも関係なく誰でも出来てしまいます! セキュリティみたいな物ですね^^; そこで、今回は未ログインユーザーが投稿画面など直接アクセスしてきた際には、ルートパスに遷移するように設定を行います! このような仕組みをリダイレクトと言い、例を出してcontroller.rbのすべてのアクションに対して、「もし、ユーザーがログインしていなかったらindexアクションにリダイレクトする」ような機能を実装をしてみます! 1.リダイレクトとは? 本来受け取ったパスとは別のパスへ転送する機能のことをリダイレクトと言います! リダイレクトを利用すると、アクションに処理を持たせて実行した上で、そのパスのビューを返すのではなく別の意図したパスにユーザーを転送させることができるみたいです! 下記の例のコードを見て頂き、1個づつ理解していきます! contoroller.rb class EatsController < ApplicationController before_action :move_to_index, except: [:index, :show] def index @eats = Eat.all end def edit end def show end private def eat_params params.require(:eat).permit(:name, :image, :text) end def move_to_index unless user_signed_in? redirect_to action: :index end end end 2. before_action :move_to_index, except 2行目にある構文! indexアクションにアクセスした場合、indexアクションへのリダイレクトを繰り返してしまい、無限ループが起こりま! この対策として、except: :indexを付け加えています! ログインしていなくても、詳細ページに遷移できる仕様にするためのexcept: [:index, :show]としています! また、exceptはbefore_actionで使用できるオプションです!exceptは「除外する」という意味があります! この後に指定したアクションに対しては、事前処理は実行されません! つまり簡単に言うと、except: [:index, :show]と書いたら、indexとshow以外は除外しますよー! と言う感じです!合っていなかったらごめんなさい( ; ; ) redirect_toメソッド Railsでリダイレクト処理を行う際に使用するメソッド! コントローラーでの処理が終わった後、アクションに対応するビューファイルを参照せずに、別ページへリダイレクトさせることができます! 記述は下記の通りです! redirect_to action: :リダイレクト先となるアクション名 例のコードの部分だと def move_to_index unless user_signed_in? redirect_to action: :index こうなります! unlessでuser_signed_in?を判定して、その返り値がfalseだった場合にredirect_toが実行されます! つまり、ユーザーがログインしていない場合にはindexアクションが実行されます! こうして未ログインユーザーを転送していく様にしていきます! まとめ redirect_toメソッドとexceptオプションの意味をしっかりと理解していれば使いこなせますね! この部分の意味合いを難しく考えなければ良いかなと思います! それにしても全然わかりやくすかけていないような気がして申し訳ないです汗 言語化して自分で説明するのも難しいですね^^; まだまだ未熟者ですが、引き続きアウトプットしていく様にします! 間違っていたらご指導おねがい致します(_ _)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsのScaffoldを使って3分でwebアプリを作ってみる

Ruby on Railsのscaffoldを使って最速でwebアプリケーションを構築してみます。 Scaffoldとは まずはRuby on Railsのscaffoldとは何かについて解説します。 scaffoldとは、Railsに備わっているコマンドの1つで、ルーティングやコントローラー(controller)、ビュー(view)、モデル(model)とテーブル(データベース)の記述やファイルなどを自動で作成してくれるコマンドです。 本来、scaffoldは建築現場の足場やビルの窓を拭くときに使用される吊り足場を意味します。Ruby on Railsのscaffoldにおいても、アプリケーションの足場であるMVC(上記で紹介したModel-View-Controller)等を指し示し、それらを容易に自動生成できます。 つまり、scaffold を使用することで、コントローラーやモデルを作成する手間を省くことができます。 scaffoldを使って作成されるルーティングは、Railsが定める7つのアクションになります。(index・show・new・edit・create・update・destroyアクションの7つです。) 以上がRails scaffoldについての簡単な説明になりますが、さすがにこれだけでは分かりにくいので、以下からは実際にRailsのscaffoldを使って、WEBアプリケーションを作ってみます。 実装 実際にScaffoldを使ってアプリケーションを作ってみます。 まずはターミナル上で次のコマンドを打ち込みます。 rails new testapp 次にディレクトリを移動します。 cd testapp ここからScaffoldを利用します 【scaffoldのコマンド書式】 rails g scaffold モデル名 カラム名①:データの型① カラム名②:データの型②・・・ 上記の書式に沿って、モデル、カラムを設定しましょう。 今回は簡単にTweetモデルにcontentカラムのみをのっけて書いてみます。 rails g scaffold Tweet content:string このコマンドでmodel、controller、viewすべてが作成されました。 最後に rails db:migrate こちらを打ち込みmigreteします。 これで完成です。驚く程かんたんですね。 動作確認 最後に、どんなものが完成したのかを確認します。 まずは、アプリのディレクトリ上で rails s と打ち込みます。 起動が確認できたら、Chromeなどのブラウザで http://localhost:3000/tweets 上記のURLを直接入力します。 このような画面が出たら成功です。 画面上の NewTweetから飛び、 なにか投稿を入力してみましょう。 投稿がうまくいけば下記のような画面になるはずです。 編集や削除などの機能も勝手に実装されていることが分かります。 まとめ 今回Scaffoldを使ったwebアプリケーション構築のかんたんな例を示してみました。 大規模なアプリ開発時にはあまり使えませんが、軽くテスト用のアプリを作りたかったり、 個人開発の小規模なアプリであれば開発スピートに大きく貢献してくれる便利な機能だと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby on Rails】Web APIの作り方を詳しく解説!

はじめに 以前にこんな記事を投稿しました。 【3分で出来る】Ruby on RailsでWeb APIの作成 この記事で解説したように、Ruby on Railsは本当に優秀なフレームワークで、簡単なAPIだったら数分で作れちゃうんです。 しかし前回は3分で作ったAPIを実際に動かして試してみたというだけで、ソースコードの中身までは解説しませんでした。 今回はソースコードを見ながら、Ruby on Railsで作ったAPIが動く仕組みを見ていきます。 前回作成したAPIがある状態で解説を行うので、まだの方は上記リンクを見て作ってみてください。5つのコマンドを打つだけで終わります。 前提知識 APIとは JSON HTTPリクエスト、レスポンス GET, POST, DELETE, etc… 環境 ruby 2.6.5 Rails 6.0.2 macOS Catalina 10.15.3 Rails APIの仕組み 前回の記事で一通り作ったAPIを試しましたが、以下の表を覚えていますでしょうか。 メソッド パスhttp://localhost:3000/ の続き 効果 GET users 全件取得 POST users bodyのjsonでデータ投入 GET users/:id 該当idのデータを取得 PATCH users/:id 該当idのデータをbodyのjsonで更新 PUT users/:id 該当idのデータをbodyのjson更新 DELETE users/:id 該当idのデータを削除 1行目を例にして、なぜhttp://localhost:3000/users/ にGETリクエストを送るとユーザ情報が全件取得できるのかなど見ていきましょう。 ルーティング Railsを触ったことがある人はルーティングを知っているでしょう。 /config/routes.rbにルーティングが記述されています。開いてみてみると以下のように記述されています。 Rails.application.routes.draw do resources :users # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html end 「あれ?こんなの書いた覚えはないぞ」と思うかもしれませんが、以下のコマンドを打った際に生成されたものです。 $ rails g scaffold user user_id:string password:string scaffoldは必要なものを一通り作ってくれるのでuserに関するものを一通り作成してくれました。その中の一つがルーティングです。 ではルーティングの中にあるresources: usersとはどういう意味でしょうか? Rails.application.routes.draw do resources :users end これは以下と同じことを意味します。 Rails.application.routes.draw do get 'users' => 'users#index' get 'users/:id' => 'users#show' get 'users/new' => 'users#new' post 'users' => 'users#create' get 'users/:id/edit' => 'users#edit' patch 'users/:id' => 'users#update' delete 'users/:id' => 'users#destroy' end これ、冒頭に書いた表と大体一致しますよね。(余計なものもありますが) get 'users' => 'users#index'は http://localhost:3000/users/ にGETリクエストを送ったときは(get 'users') usersコントローラのindexアクションを実行しろ('users#index') という意味です。 ではusersコントローラのindexアクションを見てみましょう。 コントローラとアクション usersコントローラは/app/controllers/users_controller.rbにあります。 中を見てみるとindexメソッドが見つかると思います。これがindexアクションです。 class UsersController < ApplicationController before_action :set_user, only: [:show, :update, :destroy] # GET /users def index @users = User.all render json: @users end # 以下省略、、、 ちなみにこのコントローラやその中身も作った覚えがないと思いますが、$ rails g scaffold user user_id:string password:stringのコマンドで生成されたものです。scaffoldすごい! indexアクションの中身を見てみると ユーザをすべて取得して(@users = User.all) jsonにして返す(render json: @users) となっています。 以上のルーティング、コントローラ、アクションを踏まえると、なぜhttp://localhost:3000/users/ にGETリクエストを送るとユーザ情報が全件取得できるのか分かったのではないでしょうか。 他に関しても同様です。 自分のオリジナルに作り変える APIは以下の動きをすると書いていますが、これはあくまでもscaffoldのコマンドに任せて作成した場合の話です。 メソッド パスhttp://localhost:3000/ の続き 効果 GET users 全件取得 POST users bodyのjsonでデータ投入 GET users/:id 該当idのデータを取得 PATCH/PUT users/:id 該当idのデータをbodyのjsonで更新 DELETE users/:id 該当idのデータを削除 例えば usersコントローラのindexアクションの中身をいじれば、全件取得ではなくidの昇順に並べたときの上から10個だけ取得するようにできる usersコントローラのcreateアクション(post ‘users’)をいじれば、パスワードを暗号化する処理をしてからデータベースに格納するようにできる というかrails g scaffoldのコマンドを使う必要もありません。routes.rbにルーティングを記述し、該当するコントローラとアクションに自分がさせたい処理を書くだけです! さいごに Ruby on Railsで作ったAPIの中身を解説しました。非常にシンプルな作りだったためわかりやすかったかと思います。 作りは違いますが、どの言語やフレームワークでも基本的には同じです。あなたの独自のAPIを作ってみましょう!ランダムに運勢をjsonで返すAPIとか。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む