クラスメソッドについて
クラスメソッドの定義を見ていきます。
class Hoge def self.hello puts 'hoge' end end Hoge.hello =>hoge
これは標準的な書き方だと思います。
この時のself
はクラス自身(ここではHoge)を見ています。
class Hoge def Hoge.hello puts 'hoge' end end Hoge.hello =>hoge
Hoge
に対しての特異メソッド
になります。
これが成り立つのならば下も成り立ちます。
class Hoge end def Hoge.hello puts 'hello' end Hoge.hello
クラスメソッドは、クラスオブジェクトに対しての特異メソッド
ということです。
classを動的に作成する
こんなやり方をすると可読性がなくて、よくないと思うのですが、紹介します。
klass = nil FooClass = Class.new do |f|←ブロック内で定義する klass = f f == self def hello puts 'hello' end end←ここで定義終了 => FooClass x = klass.new => #<FooClass:0x007ff5330a89c8> x.hello => :hello
以上。
コールバックの処理が増えてきたら、メソッド化する
コールバックの処理が増えてきて、可読性が悪くなる場合はまとまりをメソッド化にしましょう。
例えば、下記のようなものがあったとします。
before_save : hoge, :foo, :bar, .... if: :test
これがどんどん膨らんでいくことは、想像できます。
なので、hoge..bar
の処理をメソッドにします。
before_save :before_save_action, if: :test def before_save_action hoge foo bar end
増えてきてもbefore_save_action
に加えていけば大丈夫です。
以上です。
moduleについて
moduleについてなんとなーくでやっていたので、まとめます。
classとの違い
- インスタンスを生成することはできない
- 継承することはできない
用途
- 名前空間を作る
- モジュールのメソッドを、あるクラスのインスタンスメソッドとして取り込む
- モジュールのメソッドを、あるオブジェクトの特異メソッド(クラスメソッド)として取り込む
- モジュール関数を定義して使う
特異メソッドとして使用
インスタンス化はできないですが、特異メソッドとして使用することはできます。
self.
をつけて定義したメソッドはモジュールの特異メソッドです。
module Greet def self.hello(name) puts "#{name}さん、こんにちは#{self.class}" end end Greet.hello('foo') =>fooさん、こんにちはModule
メソッドをクラスのインスタンスメソッドとして取り込む
module Greet def self.hello(name) puts "#{name}さん、こんにちは#{self.class}" puts '特異メソッド' end def hello(name) puts "#{name}さん、こんにちは#{self.class}" puts 'メソッド' end end class Japanese include Greet end foo = Japanese.new foo.hello('foo') =>fooさん、こんにちはJapanese =>メソッド
ここで特異メソッドは使用できるのか?という疑問が浮かびました。
実験してみましょう。
Japanese.hello('japan') =>undefined method `hello' for Japanese:Class (NoMethodError)
どうやら特異メソッドはinclude
するだけではダメなようです。
特異メソッドを使用できるようにする
moduleの特異メソッドを使用するには、extend
を使用します。
class Japanese include Greet extend Greet end Japanese.hello('japan') =>japanさん、こんにちはClass =>メソッド
selfの方が呼ばれないのは、selfはあくまでも、moduleに関しての特異メソッドなんですね。
extendはクラスメソッド(特異メソッド)として使用できるようにしてくれます。
以上です。
特異メソッド
特異メソッドは、特定のオブジェクト固有のメソッドを作成することができます。
class Japanese def hello(name) puts "#{name} こんにちは" end end foo = Japanese.new foo.hello("foo") =>foo こんにちは bar = Japanese.new bar.hello("bar") => bar こんにちは def foo.hello(name) puts "#{name}は特異メソッドを使用した" end foo.hello("foo") =>fooは特異メソッドを使用した←foo固有のメソッドになっています。 bar.hello("bar") => bar こんにちは
fooのみ、メソッドが変化しています。
ちなみに特異メソッドはオーバーライドもできます。
def foo.hello(name) super puts "#{name}は特異メソッドを使用した" end foo.hello("foo") =>foo こんにちは =>fooは特異メソッドを使用した
特異メソッドを辿っていくと、rubyの仕組みを深めれるようですが、そこまでは分かってないので、特異メソッドがあるということだけの報告です。
加工したデータのf.selectの作成方法
f.collection_select
を使いたいけど、なんか違う・・・
少し加工したデータをセレクトで表示したいという時の方法です。
状況
選手名(Playerモデル)のデータを表示しようとしています。
first_name
,last_name
とカラムが分かれているfull_name
というメソッド(first_name, last_nameをつなげる)があるので、姓名をまとめて表示したい
こういう状況が発生しました。
やり方
controller
before_action :set_players def set_players @players = Player.all.map { |x| %W(#{x.full_name} #{x.id}) }←ここで必要な情報を作成する end
view
= f.select :player_id, @players
最終的な結果を得るための方法(雑談)
最近は行数を減らすのにはまっています。
どういう風に他の人が考えているのかわからないですが、自分のやり方です。
まずは、動いている結果を見ます。
=> [["ダルビッシュ有", "1"], ["田中将大", "2"]]
上記のようになっていたので、上記のように加工したかったのです。
動く形を作成。
Player.all.map do |player| x = [] x << player.full_name x << player.id x end
無駄に行数が多いので、なんとか削除したい・・・
x <<
の部分は配列で処理できるんじゃないのか?
Player.all.map do |player| x = [] x = %W(#{x.full_name} #{x.id}) end
%Wが配列を作成してくれるので、初期値いらなくない?
なら、{}で一行で書けるな。
Player.all.map { |x| %W(#{x.full_name} #{x.id}) }
という風に作成しました。
他の人はどうやって処理を簡潔に書こうとしているのだろうか?
最近はとりあえず動かすってのを意識して、後から処理を変更するようにしています。
ブロックについて
今までブロックについて意識することができていませんでした。
do..end
もしくは{}
の範囲内って認識でした。
備忘録的として書いておきます。
ブロックとは
上で説明しているようにdo..end
もしくは{}
の範囲内がブロックです。
languages = %w(Html PHP Ruby) languages.each do(ここから) |language| puts language end(ここまで)
仮引数としてブロックを受け取る
ブロックに引数を渡して処理をさせることができます。
&
をつけることで、ブロックの引数として認識されます。
block.call
で戻り値を返します
def section_block(&block) puts 'foo' puts block.call end section_block do bar end =>foo =>bar
あくまでもブロックのみ認識するということならば、当然下記でも反応します。
section_block {"bar"} =>foo =>bar
{}
もブロックなので、成り立ちます
ブロックの戻り値
これは最後に評価された式の値を返します。
section_block do 'bar' 'hoge' end =>foo =>hoge
bar
の中身は評価されてないですね。
wat-aroさんからの指摘を受けて、間違えていたので修正します。
barの中身は評価はされています。
例えば、下記の場合は標準出力に反映されます。
def section_block(&block) puts 'foo' puts block.call end section_block do puts 'bar' 'hoge' end =>foo =>bar =>hoge
オブジェクトをブロックとして渡す
&
をつけることで、Procオブジェクトをブロックとして渡せます。
bar = Proc.new {'bar'} section_block &bar =>foo =>bar
Procオブジェクトはブロックをオブジェクト化したものです。
メソッドのオーバーライド
親クラスから小クラスへと継承した際に、元のメソッドをオーバーライドすると、くさいコードが消えました。
そこで、オーバーライドについて調べました。
例
例えば、下記のようなクラスがあったとします。
class Japanese def hello puts 'こんにちは' end end class American < Japanese end japanese = Japanese.new japanese.hello =>こんにちは american = American.new american.hello =>こんにちは
こういうことになります。
これだと、アメリカ人が日本語をしゃべるので、英語で挨拶をしたいのに!ってなります(そういう設定)
なので、Japanese
のメソッドをオーバーライド(上書き)します。
class Japanese def hello puts 'こんにちは' end end class American < Japanese def hello puts 'hello' end end japanese = Japanese.new japanese.hello =>こんにちは american = American.new american.hello =>hello
いやいや、継承しているので、バイリンガルでしょ?って場合はこういう風にします。
class Japanese def hello puts 'こんにちは' end end class American < Japanese def hello super puts 'hello' end end japanese = Japanese.new japanese.hello =>こんにちは american = American.new american.hello =>こんにちは hello
追記
オーバーライドした方に引数がある場合です
その場合は元のメソッドにはないので、super()
と書いてあげます。
class Japanese def hello puts 'こんにちは' end end class American < Japanese def hello(name) super() puts "#{name} hello" end end american = American.new american.hello("foo") =>こんにちは =>foo hello
以上です。
特定のcontroller配下で指定のレイアウトを使用する方法
railsでadmin
配下のレイアウトはapplication.html.slim
とは別のものを使用したいため、テンプレートを分けたいということがありました。
やり方
- 対象のcontrollerのviewを
layouts
以下に作成する - 特定のcontrollerの配下で使用するため、layoutsを指定するようにする
まずは対象となるadmin controllerのlayoutsを変更します。
layouts/admin.html.slim
doctype html html head title | Hoge = stylesheet_link_tag 'pc/application', media: 'all', 'data-turbolinks-track' => true = javascript_include_tag 'application', 'data-turbolinks-track' => true = yield :javascript = csrf_meta_tags body = render "header" .l__admin_container = render "admin/sidebar" = yield
このように、admin専用のlayoutsを作成します。
これでadimin controllerでは呼ばれるようになります。
ただし、adminを継承したcontrollerには適用されません。
そこで、継承で使用できるようにlayout
を指定してあげます。
class AdminController < ApplicationController layout 'admin' end
これでAdminController
を継承したcontrollerはlayoutのテンプレートがlayouts/admin.html.slim
が適用されます。
coffeescriptで引数にメソッドの返り値を渡す
メソッドの引数で、めんどくさいんで返り値にメソッドを渡せないのかなと思っていたのですが、可能でした。
javascriptでも返り値に引数にメソッドの値を渡せるんですね。
$ -> delete_submit(blog_count ->) $('[data-delete-blog-no]').on 'click', -> if(confirm("削除してよろしいですか?")) $(this).closest('[data-blog-no]').remove() delete-submit(blog_count ->) else false delete_submit = (count) -> if count == 0 $('[data-send]').remove() blog_count = -> $('[data-blog-no]').length
blog_count
は要素数を返すだけのメソッドです。
delete_submit
は引数の要素数が0
なら送信ボタンを削除するというものです。
引数の中で関数を使えば、そのまま返せます。