1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

パーフェクトRuby on Rails 2章 メモ・雑感

Posted at

2章 Ruby on RailsとMVC

雑感

この章では基本的なMVCの仕組みを押さえつつ、今まで抜けていたより詳細な基本的な知識を再確認することができました。特にjbuilder周りは知っていれば個人開発もっと楽にできたなあと感じたのと、業務でもすぐに使いそうなのでしっかり押さえていきたいと思います。以下、初見の知識とメモしたかった箇所を中心とした忘備録です。

1章でもそうだったのですが、私の環境(以下参照)でscaffoldするとエラーとなりました。解決策は以下の記事を参考にしております。次章以降も毎回rails new実行時に同様の操作をしています。

$ ruby -v
ruby 2.7.8p225 (2023-03-30 revision 1f4d455848) [x86_64-darwin23]
$ bin/rails -v
Rails 6.0.6.1

「Webpacker::Manifest::MissingEntryError in Tasks#index」エラーが発生する

単数系のresourceでルーティングを作成

複数存在しない単一のリソースはresourcesの単数系のresourceでルーティングを定義でき、以下のような違いがある。

  • 基本のルーティングからindexを除いたルーティングが定義される
  • 単一のリソースなのでURLに:idが含まれない
config/routes.rb
resource :profile
 new_profile GET    /profile/new(.:format)      profiles#new
edit_profile GET    /profile/edit(.:format)     profiles#edit
     profile GET    /profile(.:format)          profiles#show
             POST   /profile(.:format)          profiles#create
             PATCH  /profile(.:format)          profiles#update
             PUT    /profile(.:format)          profiles#update
             DELETE /profile(.:format)          profiles#destroy

rescue_fromによってRailsが自動対応するもの以外の例外に対する挙動を指定

  • Railsはいくつかの特定の例外クラスに関してはそれぞれに対応したエラーコードを返す
  • それ以外の例外が発生した場合はrescue_fromというクラスメソッドを用いることでアプリケーション全体の振る舞いとして特定のレスポンスを返却することができる
class LoginFailed < StandardError
end

with:オプションで例外発生時に呼ばれるアクションを指定する。

class ApplicationController < ActionController::Base
  rescue_from LoginFailed, with: :login_failed

  def login_failed
    render template: "shared/login_failed", status: 401
  end
end

ログインが失敗した場合に定義した例外を発生させる。

class LoginController < ApplicationController
  def create
    @user = User.where(name: params[:name], password: params[:password]).find
    raise LoginFailed unless @user # ログイン失敗時に例外発生
  end

variantsによるテンプレートの切り替え

コントローラ内でrequest.variant:tablet:mobileの値を入力することで展開されるビューテンプレートファイルをindex.html.erbからindex.html+mobile.erbへ、といった具合に、"+"とrequest.variantの値を合わせた名称のテンプレートへと変更できる。

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :detect_mobile_variant

  private

  def detect_mobile_variant
    request.variant = :mobile if request.user_agent =~ /iPhone/
  end
end

<補足> chromeでPCからUserAgentをiPhoneとしてアクセスする方法

1. Chrome開発者ツールを開く(F12 or Command + Option + I)
2. 開発者ツールの「...」(その他)メニューをクリック
3. More tools → Network conditions を選択
4. User agentセクションで「Custom」を選択
5. 以下のようなiPhoneのUser-Agentを入力:

Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1

コンソールでURLとパスの取得をする

  • ルーティング表示した時の各Prefixへ_pathをつけるとドメインやポートを除いた/から始まるパス部分を、_urlとすると完全なURLを取得できる
  • コントローラーやビューでは単にedit_profile_urlと記述するとURLを取得できるがコンソール上ではappオブジェクトを経由することで取得可能
irb(main):001:0> app.edit_profile_url
=> "http://www.example.com/profile/edit"
irb(main):002:0> app.edit_profile_path
=> "/profile/edit"
irb(main):003:0> app.publisher_url(id: 1)
=> "http://www.example.com/publishers/1"
irb(main):004:0> app.publisher_path(id: 1)
=> "/publishers/1"

独自のヘルパーメソッドの定義とコンソールでの動作確認

  • HTMLタグの付与や整形などビューに特有の加工をする場合はモデルクラスに処理を書くよりヘルパーメソッドを利用するのが一般的
  • 独自のヘルパーメソッドの定義はapp/helpers配下に定義する
app/helpers/application_helper.rb
module ApplicationHelper
  def to_hankaku(str)
    str.tr("A-Za-z", "A-Za-z")
  end
end
  • ヘルパーメソッドをコンソールで利用する場合は、helperオブジェクトを呼び出す
irb(main):002:0> helper.to_hankaku("A-Z")
=> "A-Z"

jbuilderでAPIとして返却するJSONデータを整形する

コントローラーのrebderメソッドはjsonへオブジェクトを変換できるが、より複雑なJSONデータを構築する場合は、Rails組み込みのjbuilderを利用する。その場合、コントローラー内ではrenderメソッドの呼び出しを止める。

app/controllers/books_controller.rb
class BooksController < ApplicationController
  def show
    respond_to do |format|
      format.html
-     format.json { render json: @book } # 単純なJSONを返却
+     format.json # jbuilderを利用する場合
    end
  end
end

対応するアクションごとの.json.jbuilderという拡張子のファイルを用意する。

app/views/books/show.json.jbuilder
# 指定したパラメータのJSONデータを構築できる
json.extract! @book, :id, :name, :price

# !で終わらないメソッドはそのままJSONのキーとなる
json.name_with_id "#{@book.id} - #{@book.name}" 

# ブロックを渡すことでネストしたJSONデータを構築
json.publisher do 
  json.name @book.publisher.name
  json.address @book.publisher.address
end

# Rubyのコードなのでifやunlessで制御できる
unless @book.high_price?
  json.low_price true
end

上記の出力は以下のようになる。

http://localhost:3000/books/1.json
{
  "id": 1,
  "name": "Book 1",
  "price": 1000,
  "name_with_id": "1 - Book 1",
  "publisher": {
    "name": "Gihyo inc",
    "address": "Ichigaya"
  },
  "low_price": true
}
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?