Adequate Recordでキャッシュされないケースヘ(^o^)ノ

第65回 Ruby関西 勉強会に参加したよヘ(^o^)ノのつづき

スライドに、Adequate Recordでキャッシュされないケースを書いたけど、 ざっくりしすぎなのでまとめてみる( ˘ω˘)

find_byを例にactiverecordのコードを読みながら確認していく

コードはこんな感じ(コメントの*1とかは説明しやすいのでつけてるだけ)

# activerecord/lib/active_record/core.rb
def find_by(*args) # :nodoc:
  # *1  
  return super if current_scope || !(Hash === args.first) || reflect_on_all_aggregations.any?
  # *2  
  return super if default_scopes.any?

  hash = args.first

  # *3
  return super if hash.values.any? { |v|
    v.nil? || Array === v || Hash === v
  }

  # We can't cache Post.find_by(author: david) ...yet
  # *4  
  return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }

  ...
end

*1で判定していること

current_scopeがある

current_scopeでスコープがないことを確認してる

引数がHash以外

!(Hash === args.first)でチェックしてる

こんなのはキャッシュしてくれない

Post.find_by('created_at < ?', 1.weeks.ago)
composed_ofが設定されている

reflect_on_all_aggregations.any?でチェックしてる

設定されているだけでキャッシュしてくれない


*2で判定してること

default_scopeが設定されている

設定されているだけでキャッシュしてくれない


*3で判定していること

引数のハッシュ値(Value)がnil, Array,Hash

こんなのはキャッシュしない

Post.find_by(title: nil)
Post.find_by(title: ['ruby', 'rails'])
# Hashがくるケースが思い浮かばない...


*4で判定していること

Hashのキーにモデルのカラム以外が指定されている

以上の条件に当てはまる場合に、superすなわち本家のfind_byをよんでます

なので、単一テーブル継承(STI)やPolymorphicは、設定されているだけではキャッシュの対象外とはなりません

ここがややこしそうだ。。。

間違えてたら教えてくださいねー

Happy Hacking٩( ‘ω’ )و

神戸.rb Meetup #13に参加したよヘ(^o^)ノ

神戸.rb Meetup #13に参加しましたー

毎回思うがホント勉強になる

僕の思いもみんなに伝えられたし良かった

今日はActiveSupport::StringInquirerについて調べた

結構こんなの書いちゃいがちですよね?

if Rails.env == 'production'
  ...
end

それが、こう書ける

if Rails.env.production?
  ...
end

これを使ってこんなの実装してみた

priority_typeってフィールドがあって、'low'や'high'なんかの文字列がセットされてるとする

class Task < ActiveRecord::Base
  def priority
    priority_type.inquiry
  end
end

lowかどうかチェックしてみる

task.priority_type    #=> "low"
task.priority.low?    #=> true
task.priority.middle? #=> false

==で判定するよりグッと意図が伝わりやすくなってると思う(多分...

Happy Hacking٩( ‘ω’ )و

RubyのHashで要素数を取得するヘ(^o^)ノ

Hashで要素の数を取得してみる

Hash#lengthとHash#size

favorites_language = {
  bob: 'Ruby',
  jone: 'Ruby',
  tiger: 'Perl'
}
favorites_language.length #=> 3
favorites_language.size   #=> 3

Enumerable#count

favorites_language = {
  bob: 'Ruby',
  jone: 'Ruby',
  tiger: 'Perl'
}
favorites_language.count #=> 3

では、Valueが'Ruby'である要素の数を取得してみる

Hash#lengthとHash#size

favorites_language = {
  bob: 'Ruby',
  jone: 'Ruby',
  tiger: 'Perl'
}
favorites_language.select{|k, v| v == 'Ruby'}.size #=> 2

Enumerable#count{|obj| ...}

favorites_language = {
  bob: 'Ruby',
  jone: 'Ruby',
  tiger: 'Perl'
}
favorites_language.count{|key, v| v == 'Ruby'} #=> 2

そう!countにはブロックを渡せるのだー(今までマジで知らんかった...

もう少しおしゃれにしてみよう

Enumerable#count(item)

favorites_language = {
  bob: 'Ruby',
  jone: 'Ruby',
  tiger: 'Perl'
}
favorites_language.values.count('Ruby') #=> 2

まだまだ知らんこといっぱいですわー

がんばろっと

Happy Hacking٩( ‘ω’ )و

第65回 Ruby関西 勉強会に参加したよヘ(^o^)ノ

第65回 Ruby関西 勉強会に参加し、発表してきました。

発表内容はRails4.2の新機能について。

4.2がリリースされてから2ヶ月が経ちますが、ActiveJob中心に紹介させてもらいました。

発表中にデモする時があると思います

スライド見ながらタイプするの大変ですよねー( ̄▽ ̄;)

そんな時はtmuxですよ!

  • tmuxを起動

f:id:murajun1978:20150222191156p:plain

  • 新しいターミナルから、起動済みtmuxへアクセス
$ tmux attach -t 0
  • 普通に操作する

f:id:murajun1978:20150222192232g:plain

これで発表中のデモも楽ちんですねーヘ(^o^)ノ

Happy Hacking٩( ‘ω’ )و


みなさんの発表内容

Ruby 2.0 以降の変更をふりかえる

@sixeightさん


RubyでBCCWJを弄ぶ

@pico1aさん


Wakayama.rbボードの紹介

@momoongaさん


Rubyコミュニティx企業

@takamiya_amsさん


Medaka.rb活動概要

@matsushin11さん


Gemをコードリーディングしてみよう!

@taiyopさん


Rails見える化 開発(API編)

@ogomさん


Treasure DataでのRubyの利用

@repeatedlyさん


追記
  • 2014/02/27 @takamiya_amsさんのスライド追加

Gitのコンフリクト時にmergetoolで確認してマージするヘ(^o^)ノ

Gitでコンフリクトしたときに、GUIIDEだと差分が確認しやすいみたい。

でも、僕はVimなの...

そこでmergetoolですよ!

実際にやってみよう。

# hello.rb
class Hello
  def say
    "Hello"
  end
end

コミットして、ブランチを切ります。

$ git init
$ git add .
$ git commit -m 'first commit'
$ git checkout -b add_name

修正してみます。

# hello.rb
class Hello
  def say(name)
    "Hello #{name}"
  end
end

コミットして、masterブランチへ

$ git add .
$ git commit -m 'add name'
$ git checkout master

わざとコンフリクトさせてみましょう。

マージする前に、masterブランチのファイルを修正します。

# hello.rb
class Hello
  def say
    "Hello!"
  end
end

コミットして、マージします。

$ git add .
$ git commit -m 'add exclamation mark'
$ git merge add_name

コンフリクトしました!

Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Automatic merge failed; fix conflicts and then commit the result.

コマンドを実行します。

$ git mergetool
  • 左はマージする前の状態
  • 右はマージしたいところ
  • 中央は右のマージしたいところが作られる前の状態
  • 下はマージして保存するファイル

f:id:murajun1978:20150211004426p:plain

どうですか?

今のmasterブランチの状態と、マージ前の状態とマージしようとしているファイルの状態が

わかりやすいですよね?

masterブランチには'!'が、add_nameブランチにはnameが追加されています。

ファイルを編集して、保存します。

# hello.rb
class Hello
  def say(name)
    "Hello #{name}!"
  end
end

コンフリクトしたときのファイルはhello.rb.origで保存されています。

必要なければ削除して、コミットしましょう。

$ git commit -m 'merge add_name'

これで、コンフリクトのマージ作業が安全に行えそうですね。

Happy Hacking٩( ‘ω’ )و

d(゚Д゚ )☆スペシャルサンクス☆( ゚Д゚)b

Gitコンフリクト解消ガイド(git mergetoolの使い方)

神戸.rb Meetup #12に参加したよーヘ(^o^)ノ

神戸.rb Meetup #12に参加しました。

僕はKonachaについて調べてました。

会社でRailsJavaScriptをええー感じにテストしたい!ってことなので

# Gemfile
group :test, :development do
  gem 'konacha'
  gem 'selenium-webdriverd'
end

デフォルトのdriverはseleniumです。

実際にテストを書いてみる

# app/assets/javascripts/hello.js.coffee
class @Hello
  @say_hello: (name) ->
    "Hello #{name}!"
# rspec/javascripts/hello_spec.js.coffee

#= require hello

describe 'Hello#say_hello', ->
  it "returns 'Hello murajun1978!'", ->
    expect(Hello.say_hello('murajun1978')).to.eql("Hello murajun1978!")

テストを実行する

$ bundle exec rake konacha:run
.

Finished in 0.00 seconds
1 examples, 0 failed, 0 pending

テスト通ったねー

んじゃ、headlessでテストしてみる

# Gemfile
gem 'poltergeist'
# gem 'selenium-webdriver'
# config/initializers/konacha.rb
Konacha.configure do |config|
  require 'capybara/poltergeist'
  config.driver = :poltergeist
end if defined?(Konacha)

headlessでテストできたねーヘ(^o^)ノ

Happy Hacking٩( ‘ω’ )و


追記
  • 2015/02/23
    • hello_spec.js.coffeeでrequireしていなかったので追記
    • config.driverの指定が間違ってたので修正

神戸.rb Meetup #11 に参加したよヘ(^o^)ノ

Kobe.rbに参加してきたよヘ(^o^)ノ

今日のおやつ!! f:id:murajun1978:20150121003951j:plain f:id:murajun1978:20150121003947j:plain photo by @spring_aki

おいしかった♪

今日、僕が調べてたのはActiveDecorator + Capybara + RSpecです。

ActiveDecoratorでhelperを良く使いますよねー

例えばこんなの...

def full_name
  content_tag :td do
    "#{first_name} #{last_name}"
  end
end

Decoratorが自動生成するRSpecはこちら

describe UserDecorator
  let(:user) { User.new.extend UserDecorator }
  subject { user }
  it { should be_a User }
  [...]
end

毎回extendするのもアレなので、ActiveDecorator::RSpecを使います

# Gemfile
gem 'active_decorator-rspec'

# spec/decorator/user_decorator_spec.rb
describe UserDecorator
  # FactoryGirlでテストデータ作成
  let(:user) { build(:user) }
  subject { decorate user }
  it { should be_a User }
  [...]
end

いい感じですねー

キモのfull_nameメソッドをCapybaraでテストしてみましょう

describe UserDecorator
  [..]
  it 'has a tr tag and full_name' do
    expect(subject.name).to have_content(:td, "#{user.first_name} #{user.last_name}")
  end
end

実行すると怒られます。。。

undefined method 'content_tag' for ...

RSpecがhelperメソッドを認識してないもよう。

type: :heler or type: :viewを指定すればhelperメソッドが認識されますが、 こんどはCapybaraにおこられます( ̄▽ ̄;)

have_contentはCapybara::RSpecMatchersで定義されてるのでincludeしてみます

describe UserDecorator
  include Capybara::RSpecMatchers
  let(:user) { build(:user) }
  subject { decorate user }
  it { should be_a User }
  
  it 'has a tr tag' do
    expect(subject.name).to have_content(:td)
  end
end

これでテストを実行すればパスしますが、毎回includeはアレなのでrails_helperに追記

# spec/rails_helper.rb
RSpec.configure do |config|
  config.include Capybara::RSpecMatchers, type: :decorator
end
describe UserDecorator
  let(:user) { build(:user) }
  subject { decorate user }
  it { should be_a User }
  
  it 'has a tr tag', type: :decorator do
    expect(subject.name).to have_content(:td, "#{user.first_name} #{user.last_name}")
  end
end

これでCapybaraを使ってテストできますねー

Happy Hacking٩( ‘ω’ )و