• 検索結果がありません。

ここでの目的は、 book.published_on がnilでないとき、カッコ内に与えられたメソッ ドを実行するというものです(.tr yメソッドの使い方としては他にもあります)。この使い方に

ドキュメント内 Rails1.indd (ページ 61-68)

ほぼ置き換えられるものとして、ruby2.3から &. 通称、ぼっち演算子という機能が追加さ れました。このぼっち演算子を使うと、コードはこのようになります。

コラム: &. (

アンパサンド ドット、通称:ぼっち演算子

)と .try メソッド

<td><%= book.published_on&.strftime('%Y年 %m月') %></td>

当然、rubyのバージョンが2.3より古いものでは、ぼっち演算子は使えません。対応する Rubyのバージョンがいくつかを意識して、ぜひ新しいものも取り入れていってください。

④ リダイレクトの変更

Tagの画面遷移で詳細ページを省略することにしたのでした。デフォルトは、新規登録のあ とと編集の後に、詳細ページへ遷移するようになっています。これらはコントローラーで設 定を変更することができます。

設定前(デフォルト)

• tags#new -> tags#create -> tags#show

• tags#edit -> tags#update -> tags#show

設定後

• tags#new -> tags#create -> tags#index

• tags#edit -> tags#update -> tags#index

app/controllers/tags_controller.rb

を開いてください。

def create

@tag = Tag.new(tag_params) respond_to do |format|

if @tag.save

format.html { redirect_to @tag, notice:

'Tag was successfully created.' }

format.json { render :show, status: :created, location: @tag } else

format.html { render :new }

format.json { render json: @tag.errors, status: :unprocessable_entity }

end end end



if @tag.save

のところでタグ のデ ータを保 存しています。これが 成 功したら、

ま保存したデータのことを指していますので、保存したデータの詳細ページへ遷移しま す。この指定方法は省略した書き方で、

tag_path(@tag)

と同じ意味です。これを

tags#index

へ遷移するように書き換えます。

format.html { redirect_to tags_url, notice:

'Tag was successfully created.' }

これも遷移先を示す別の書き方ですが、tags_pathと遷移するところは同じです。ただし、

2.3.0 :004 > app.books_url

=> "http://www.example.com/books"

2.3.0 :005 > app.books_path => "/books"

このように、httpで始まるurlなのか、そのうしろのpathだけなのかという違いがあります。 viewのようなテンプレートでは_path でも大きな問題にはなりませんが、このリダイレク トはhttpステータスコードの300番台のことですので、ここでは _url を指定しておく方

が好ましいでしょう。

commit

⑤ 中間テーブルの実装

sample_designのbooks_show.htmlを見てください。ここにタグ付け(Tagging)

情報を載せています。テンプレートを修正しただけでは、データはうまく保存されません。

いままでは、BookやTagモデル単体で画面遷移をしてデータを作成する方法ばかりでし たが、コントローラやモデルを変更して、中間テーブルのデータを作成する方法を説明しま す。方法はいろいろありますが、ここでは片方(Book)の情報に依存したやり方を解説します。

まず、Taggingモデルの内容を確認しましょう。 app/models/tagging.rb を開い てください。

class Tagging < ApplicationRecord belongs_to :book

belongs_to :tag end

Taggingのデータには、bookとtagの両方の情報が必要です。scaffoldをすると き、

db/migrateのファイルにフィールドに関係を表す references

を指定すると、中

Tagモデルから見た関係は自動では追加してくれませんので、以下のように追記してくだ さい。

app/models/book.rb class Book < ApplicationRecord has_many :taggings end

a p p / m o d e l s / t a g . r b



c l a s s T a g < A p p l i c a t i o n R e c o r d h a s _ m a n y :taggings end

ここで、BookとTagはリレーションで多対多の関係ですので、以下のようにBook とTagの 関 係 も 追 加して お き ましょう。

app/models/book.rb class Book<

ApplicationRecord has_many :taggings has_many :tags, through:

:taggings end

app/models/tag.rb class Tag

< ApplicationRecord has_many :taggings

has_many :books, through: :taggings end

これらのリレーションの設定はいろいろな機能の実装前に忘れずに設定してください。

commit

では、sample_designのtaggings_form.htmlを見てください。前提として関係 先のBookの情報があり、それに付随するタグを追加するというやり方です。タグを選択 する部分は、以下のように書き直してください。

変更前

<select name="tagging[tag_id]" id="tagging_tag_id">

<option value="1">文学・小説</option>

<option value="2">科学・テクノロジー</option>

<option value="3">文庫</option>

<option value="4">ハードカバー</option>

<option value="5">雑誌</option>

</select>

 変更後

<%= f.select :tag_id, Tag.all.map{|t| [t.name, t.id]}, class: "form-control" %>

Tag.all

でタグ情報をすべて取り出し、

.map

メソッドで配列に直します。 f.select は、

配列でデータを渡すことでセレクトボックスを作ってくれます。配列の1つ目が表示する文字、

2つ目がvalueです。このとき、valueへは文字を渡さずにデータのidを渡すようにして ください。このvalueが:tag_idとしてコントローラへ送信されます。

tag_id

は、こうしてセレクトボックスから情報をもらいます。もう1つの

book_id

は、

urlから情報をもらいます。このページのurlは次のところです。

new_book_tagging GET /books/:book_id/taggings/new(.:format) taggings#new book_taggings POST /books/:book_id/taggings(.:format) taggings#create

ここに、:book_id があります。この情報は、コントローラのアクション内で取得すること ができますので、それを利用します。

まず、テンプレートでタグ のセレクトボックスの 上に表 示しているBookの 情 報は、

tagging#new

から インスタンス 変 数 で 取 得しましょう。

app/controllers/

taggings_controller.rb

のnewアクションを次のように変更します。

def new

@tagging = Tagging.new

@book = Book.find(params[:book_id]) # 追加 end



こうして取得した@book を使って、テンプレートで本のタイトルなどを表示してみてくださ い。最後に、formタグですが、ここに :book_id を渡してcreateのpathを作ります。

いま、コントローラで @book を取得したのでこれを使って簡単に設定することができます。

以下のように form_for の行を変更してください。

変更前(デフォルト)<%=form_for(tagging)do|f|%>

変更後<%=form_for([@book,tagging])do|f|%>

あとはapp/views/books/_form.html.erb などを参考にしながら、taggingのテンプレー ト全体を修正してみてください。

commit

コントローラに情報を渡すテンプレートの準備ができたので、taggings#createを修 正しましょう。

変更前 def create

@tagging = Tagging.new(tagging_params) respond_to do |format|

if @tagging.save

format.html { redirect_to @tagging, notice:

'Tagging was successfully created.' } format.json { render :show, status:

:created, location: @tagging }

else

format.html { render :new }

format.json { render json: @tagging.

errors, status: :unprocessable_entity } end

end end

まず、tag_idはストロングパラメータとしてtagging_paramsに含まれて渡されますので、

このままで大丈夫です。book_idは、newアクションと同じように、@bookを追加し て取得しましょう。createしたあとのリダイレクト先の変更も忘れないでください。そうす ると、createアクションは次のようになります。

変更後 def create

@book = Book.find(params[:book_id]) @tagging = Tagging.new(tagging_params) @tagging.book_id = @book.id

respond_to do |format|

if @tagging.save

format.html { redirect_to @book, notice:

'Tagging was successfully created.' } format.json { render :show, status:

:created, location: @tagging }

else

format.html { render :new }

format.json { render json: @tagging.

errors, status: :unprocessable_entity } end

end end

これで books#show -> taggings#new -> taggings#create ->

commit

同じようにbooks#show -> taggings#edit -> taggings#update ->

books#show の流れも修正してみてください。editとupdateアクションは次のように なります。

def edit

@book = Book.find(params[:book_id]) end

def update

@book = Book.find(params[:book_id]) respond_to do |format|

if @tagging.update(tagging_params)

format.html { redirect_to @book, notice:

'Tagging was successfully updated.' }

format.json { render :show, status: :ok, location: @tagging } else

format.html { render :edit }

format.json { render json: @tagging.errors,

status: :unprocessable_entity }

end end end

updateアクションでは、すでに@taggingに book_id が入っていますから、ここで は代入する必要はありません。リダイレクトのために @book を用意します。

commit

初めてデフォルトのコントローラのshowやeditアクションを見ると、何もないアクションで面食 らうと思います。もうご存知のとおり、フィルタと呼ばれるbefore_ actionで設定しているから です。ここではaf ter_ actionというものも使えます。また、モデルにはコールバックと呼ばれる ものがあります。before_ save,af ter_ save,before_create,af ter_createなど、

いろいろなタイミングのものがあります。さらに、Rubyは他のクラスやモジュールを継承しますの で、その元/先で何か処理をしているときもあります。いろいろなプロジェクトに関わっていくと、コ ントローラのアクションだけ見ていると、保存しているつもりが保存されなかったり、意図しない(よ うに見える)データに変換されてしまったりして、びっくりすることもあります。テキストでプログラミ ングを学ぶと、どうしてもその部分だけを注目しがちですが、Rail sがどういうふうに動作している か全体をイメージしながら実装していくと、思わぬ動作になったときに予測がつけられるようになり ます。そうして俯瞰できるようになるのが、上級者の第一歩です。

コラム:フィルタとコールバックと継承を俯瞰する

3. 管理者ログイン認証

(1) . Gemを利用したログイン認証

誰でもアクセスできる状態をなくすために、ログイン認証を実装しましょう。ここでは便利な gemにお任せです。今までのようにrailsgenerateを利用して、そこに機能を追加す る方法が一般的ですが、gemに実装されている機能を使って実装する方法を紹介します。

余談ですが、ここに書いている方法は、gemのREADMEに書いてあります(もちろん英 語です)。他のgemもそうですが、使い方を自分で読んで使えるようになることを目指して ください。

  ① gem deviseのインストールとユーザーモデルの設定

ドキュメント内 Rails1.indd (ページ 61-68)

関連したドキュメント