アクセスメソッドを使ってみる
アクセスメソッドとは?
オブジェクトからインスタンス変数にアクセスするためのメソッドのことです。
種類は以下の3つです。
- attr_reader
- attr_writer
- attr_accessor
attr_readerを使ってみる
class SelfIntro def initialize(name='名無しさん') @name = name end end self_intro = SelfIntro.new('太郎') puts self_intro.name
アクセスメソッドattr_reader
を使っていないため、エラーが発生します。
class SelfIntro def initialize(name='名無しさん') @name = name end # 追記 attr_reader :name end self_intro = SelfIntro.new('太郎') puts self_intro.name
今回はattr_reader
を追記したため、処理が成功します。
attr_writer を使ってみる
class SelfIntro def initialize(name='名無しさん') @name = name end attr_reader :name end self_intro = SelfIntro.new('太郎') self_intro.name = 'たろう' puts self_intro.name
アクセスメソッドattr_writer
がないため、インスタンス変数を更新することができません。
class SelfIntro def initialize(name='名無しさん') @name = name end attr_reader :name # 追記 attr_writer :name end self_intro = SelfIntro.new('太郎') self_intro.name = 'たろう' puts self_intro.name
今回はattr_writer
を追記したため、処理が成功します。
attr_accessor を使ってみる
class SelfIntro def initialize(name='名無しさん') @name = name end attr_accessor :name end self_intro = SelfIntro.new('太郎') self_intro.name = 'たろう' puts self_intro.name
attr_accessor
はattr_reader
とattr_writer
の両方を有効にすることが出来ます。
これは直接インスタンス変数を操作できるようになったわけではなく、インスタンス変数を操作するメソッドが自動的に追加されているというイメージです。
Draperを使ってみる
Draperとは?
Draperはデコレーター(ビューとモデルの中間の処理を引き受ける)で、railsのプレゼンテーション層を担う。 表示に関するロジックをプレゼンテーション層に引き渡すことで、以下のようなことが避けられる。
- モデルに表示ロジックを記述
- ビューファイル内のif文多用
- helperの名前空間の衝突
結果、コードの可読性、保守性を向上することができる。
draperをインストール
gem 'draper', '~> 1.3'
$ bundle install
土台となるアプリケーションを作成
$ rails g scaffold Blog title:string content:text
draperをインストールしているため、decoratorsも作成されます。
$ rails db:migrate
生成されたコード
class BlogDecorator < Draper::Decorator delegate_all # Define presentation-specific methods here. Helpers are accessed through # `helpers` (aka `h`). You can override attributes, for example: # def created_at helpers.content_tag :span, class: 'time' do object.created_at.strftime("%a %m/%d/%y") end end end
delegate_all
とは、decoratorに存在しないメソッドがコールされた場合、モデルの処理が実行される。
controllerにてdecoratorインスタンスを作成する。
オブジェクトをデコレートする(decorator内で利用できるようにする)ためには、以下の方法を利用します。
- 複数のオブジェクトの場合、decorate_collection
- 単体のオブジェクトの場合、decorate
class BlogsController < ApplicationController before_action :set_blog, only: [:show, :edit, :update, :destroy] # GET /blogs # GET /blogs.json def index @blogs = BlogDecorator.decorate_collection(Blog.all) end ... private # Use callbacks to share common setup or constraints between actions. def set_blog @blog = BlogDecorator.decorate(Blog.find(params[:id])) # これでもいける(model名からdecoratorを推察してくれる) # Blog.find(params[:id]).decorate end end
このようにデコレーターインスタンスを生成します。
ビューからdecoratorメソッドを利用する。
app/views/blogs/index.html.erb
を編集。
<p id="notice"><%= notice %></p> <h1>Blogs</h1> <table> <thead> <tr> <th>Title</th> <th>Content</th> <th colspan="3"></th> </tr> </thead> <tbody> <% @blogs.each do |blog| %> <tr> <td><%= blog.title %></td> <td><%= blog.content %></td> <td><%= blog.created_at %></td> <td><%= link_to 'Show', blog %></td> <td><%= link_to 'Edit', edit_blog_path(blog) %></td> <td><%= link_to 'Destroy', blog, method: :delete, data: { confirm: 'Are you sure?' } %></td> </tr> <% end %> </tbody> </table> <br> <%= link_to 'New Blog', new_blog_path %>
表示を確認する
draperで定義したメソッドcreated_at
がコールされていることが確認できる。
参考
こちらを参考にさせていただきました。
http://ruby-rails.hatenadiary.com/entry/20150415/1429031791
HashWithIndifferentAccessを使ってみる
HashWithIndifferentAccessとは?
HashWithIndifferentAccess
を使うことで、シンボルでも文字列でもハッシュにアクセス可能となる。
hoge = ActiveSupport::HashWithIndifferentAccess.new(hoge: 'ほげ') # シンボル hoge[:hoge] => "ほげ" # 文字列 hoge['hoge'] => "ほげ" hoge = {hoge: "ほげ"}.with_indifferent_access # シンボル hoge[:hoge] => "ほげ" # 文字列 hoge['hoge'] => "ほげ"
ActiveJobとは?
Active Jobとは?
バックグランドで実行するjobや、キューを操作するためのフレームワークのことです。
$ bin/rails g job hoge
上記のコマンドを実行すると
app/jobs/hoge.rb
というjobが作成されます。
# app/jobs/hoge.rb class HogeJob < ActiveJob::Base queue_as :default def perform(引数) # 後で行う処理を記述する end end
# Jobを定義できたら以下のコードをトリガーとして実行する # キューに空きができたら実行する HogeJob.perform_later(引数) # 1週間後に実行 HogeJob.set(wait: 1.week).perform_later(引数) # 明日の正午に実行 HogeJob.set(wait_until: Date.tomorrow.noom).perform_later(引数)
アダプタがセットされていない場合は即座にJobが実行されます。
例外
ActiveJobの例外キャッチ方法はrescue_from
の1つのみ提供されている。
rescue_from(ActiveRecord::RecordNotFound) do |exception| # 例外処理を記述 end def perform(引数) # 後で行う処理を記述する end
Regexpを使ってみる
Regexpとは?
正規表現のクラスのことです。
hoge = Regexp.new('hogehoge') # => /hogehoge/
このように正規表現のスラッシュで囲まれた形式でオブジェクトを作成します。
# 配列を用意 array = %w(hoge fuga) # => ["hoge", "fuga"] # 配列を|(OR条件)で結合した、正規表現を返す regexp = Regexp.new(array.join('|')) # => /hoge|fuga/
union
# 配列を用意 array = %w(hoge fuga) # => ["hoge", "fuga"] # 配列を|(OR条件)で結合した、正規表現を返す regexp = Regexp.union(array) # => /hoge|fuga/
配列操作をしなくても、unionを使うとこで、直感的に正規表現を作成することができます。
punditを使ってみる
punditとは
punditは認証系のgemの一種であり、対象のリソースに対して何を(誰を)許可するのかを定義することができます。
punditをインストール
gem 'pundit'
$ bundle install
punditの初期設定
app/controllers/application_controller.rb
にPunditをincludeする。
(対象controllerの継承元でpunditをincludeしておく。)
include Pundit
$ rails g pundit:install
を実行すると、app/policies
ディレクトリが作成されます。
例えばhogehogeコントローラーへのアクセス制御を掛けたいとき、
$ rails g pundit:policy hogehoge
を実行し、policyファイルapp/policies/hogehoge_policy.rb
を作成されます。
認証に失敗する
hogehoge_controller.rb
のindexアクションで、authorize貼ってみる。
# コントローラーのindexアクションにてauthorizeメソッドを呼び出す def index authorize HogeHoge end # app/policies/hogehoge_policy.rbでindexをfalse(認証拒否)にしておく class HogeHogePolicy < ApplicationPolicy def index? false end
認証拒否しておくとPundit::NotAuthorizedError
が発生します。
認証に成功する
# hogehoges_controller def index authorize HogeHoge end def new @hogehoge = HogeHoge.new authorize @hogehoge end def create @hogehoge = HogeHoge.new(permitted_attributes(HogeHoge)) end def update @hogehoge = HogeHoge.find(params[:id]) @hogehoge.update(permitted_attributes(@hogehoge)) end policy(:hogehoge).fugafuga?(引数) # app/policies/hogehoge_policy.rb class HogeHogePolicy < ApplicationPolicy # indexアクション時のuser権限を確認しています。 def index? user.staff? || user.admin? end # create, editアクションを実行できるかをチェックしています(newができればcreateもできる、editができればupdateもできる) def new? create? end def edit? update? end # 独自でメソッドを作ることもできる def fugafuga?(引数) end private # pundit側でストロングパラメータを設定できる def permitted_attributes [:strong_parameterA, :strong_parameterB] end end
Decoratorとは?
Railsでは責務を分割することによって、可読性、保守性の高いアプリケーションを作ることができます。helperにはビュー表示の責務を持たせ、modelには対象リソースに関する処理を責務として持たせます。
そのなかで、Decoratorにはhelperとmodelの中間のような責務を持たせます。モデルの内容を少し加工してビューに表示させる場合(model
には表示に関する責務を持たせたくない、viewには表示に関するコード以外は書きたくない)などは、helperやmodelではなくDecoratorにコードを記述します。
active_decoratorをインストール
gem 'active_decorator'
$ bundle install
decoratorファイルを作成
$ rails g decorator question
‘app/decorators/question_decorator.rb'というファイルが作成されます。
ファイル名は対象のモデルに合わせてください。
module QuestionDecorator # 3日後の日付を返すメソッドを定義します。 def three_days_later self.updated_at.since(3.days) end end
3日後の日付を返すことに意味があるのか?ビューでsince(3.days)
を使ってもいいのでは?
そこらへんはひとまず置いておきます。
ビューから呼び出す
<% @questions.each do |question| %> <%= question.three_days_later %> <% end %>
このようにDecoratorを使うことで、Railsに新たな責務を追加することができます。