edy hub

プログラミングやライフスタイルについて書き綴っています

Redis ObjectsをRailsで使ってみる

はじめに

これはRedis導入後に、Redis Objectsの使い方を学ぼうと思った一人の若者の備忘録です。

GitHubリポジトリを参考にしています。

GitHub - nateware/redis-objects: Map Redis types directly to Ruby objects

Gemの導入

はじめに、Gemfileにgemを追加します。

gem 'redis-objects'

モデルクラスに組み込んでみる

Redis::Objectsをモデルクラスにインクルードします。 Redis::Obejcetsは ユニークな値を返すメソッドであるid を備えているクラスであれば効果的に活用できます。 そして、自動的に各オブジェクトに対してユニークなキーを発行してくれたりします。

例:下記のようなフォーマット

model_name:id:field_name

Userクラスで試してみる

class User
  include Redis::Objects
  counter :my_posts
  def id
    1
  end
end

user = User.new
user.id  # 1

user.my_posts.increment
user.my_posts.increment
user.my_posts.increment
puts user.my_posts.value # 3

user.my_posts.reset
puts user.my_posts.value # 0

user.my_posts.reset 5
puts user.my_posts.value # 5

スタンドアロンな用法

Counters

任意のcounter_nameをキーとしてRedisに保存される仕組み。

@counter = Redis::Counter.new('counter_name')
@counter.increment  # or incr
@counter.decrement  # or decr
@counter.increment(3)
puts @counter.value

Values

シンプルな値も簡単に取り扱えます。

@value = Redis::Value.new('value_name')
@value.value = 'a'
@value.delete

Lists

ListsRubyの配列のような働きをします。 配列を扱う際に登場するメソッドが同じように使えて便利。

@list = Redis::List.new('list_name')
@list << 'a'
@list << 'b'
@list.include? 'c'   # false
@list.values  # ['a','b']
@list << 'c'
@list.delete('c')
@list[0]
@list[0,1]
@list[0..1]
@list.shift
@list.pop
@list.clear
# etc

配列の最大保持数も指定できます。 ※ :maxlengthオプションを使います。最も古い要素を配列外に出します。

# 最大10個の要素だけ保持したいとき。
@list = Redis::List.new('list_name', :maxlength => 10)

Hashes

HashesもRubyのHashのような働きをします。Redis独自の仕様もあります。 RubyのHashとの衝突を避けるために、HashKeyという命名になっています。

@hash = Redis::HashKey.new('hash_name')
@hash['a'] = 1
@hash['b'] = 2
@hash.each do |k,v|
  puts "#{k} = #{v}"
end
@hash['c'] = 3
puts @hash.all  # {"a"=>"1","b"=>"2","c"=>"3"}
@hash.clear

Redis上では、数字は文字列になることに注意してください。

Sets

SetsはRubyのSetクラスのようなものです。 順序立てられたものではないですが、要素の一意性が担保されます。

@set = Redis::Set.new('set_name')
@set << 'a'
@set << 'b'
@set << 'a'  # dup ignored
@set.member? 'c'      # false
@set.members          # ['a','b']
@set.members.reverse  # ['b','a']
@set.each do |member|
  puts member
end
@set.clear
# etc

Sorted Sets

プロパティーの一意性に伴い、Sorted Setsはハッシュと配列の両取りをしたような働きをします。 ハッシュのように割り当てることができ、取り出すときは配列風になります。

@sorted_set = Redis::SortedSet.new('number_of_posts')
@sorted_set['Nate']  = 15
@sorted_set['Peter'] = 75
@sorted_set['Jeff']  = 24

# Array access to get sorted order
@sorted_set[0..2]           # => ["Nate", "Jeff", "Peter"]
@sorted_set[0,2]            # => ["Nate", "Jeff"]

@sorted_set['Peter']        # => 75
@sorted_set['Jeff']         # => 24
@sorted_set.score('Jeff')   # same thing (24)

@sorted_set.rank('Peter')   # => 2
@sorted_set.rank('Jeff')    # => 1

@sorted_set.first           # => "Nate"
@sorted_set.last            # => "Peter"
@sorted_set.revrange(0,2)   # => ["Peter", "Jeff", "Nate"]

@sorted_set['Newbie'] = 1
@sorted_set.members         # => ["Newbie", "Nate", "Jeff", "Peter"]
@sorted_set.members.reverse # => ["Peter", "Jeff", "Nate", "Newbie"]

@sorted_set.rangebyscore(10, 100, :limit => 2)   # => ["Nate", "Jeff"]
@sorted_set.members(:with_scores => true)        # => [["Newbie", 1], ["Nate", 16], ["Jeff", 28], ["Peter", 76]]

# atomic increment
@sorted_set.increment('Nate')
@sorted_set.incr('Peter')   # shorthand
@sorted_set.incr('Jeff', 4)

Rubymineの「typo」警告を特定のワードの場合に無くしたい

どんなケース?

これはtypoに見せかけて、プロジェクト内では列記とした単語なんじゃ!という場合。 毎回警告が出るとうざいですよね。 f:id:yuki-eda0629:20190323150041p:plain

解決方法

該当ワードで右クリック すると、Spellingという項目が出てきます(自分の場合は、トップに出てきました) f:id:yuki-eda0629:20190323150309p:plain

さらに「Spelling」> 「Save '該当ワード' to project-level directory」を選択 f:id:yuki-eda0629:20190323150406p:plain

さいごに

波線と警告がなくなりました!!めでたし! f:id:yuki-eda0629:20190323150603p:plain

Goのセットアップを行う

はじめに

普段は業務でRubyを使っているが、多言語に対応して一丁前のエンジニアになるべく、Goの学習をしてみる(週末限定)

リファレンス

このサイトが非常に役に立った。

cuto.unirita.co.jp

Goのインストール

自分はMacを使用しているため、homebrewでGoをインストールする。

$ brew install go

これで完了!

GOPATHの設定

bash_profile(又は、bashrc)に環境変数を記述する。

export GOROOT=$HOME/go

GOPATHの指定としては、選択肢として、①ルートディレクトリ配下②home以下にgoディレクトリを作成 の2パターンがありそうです。

参考

Go言語の開発環境セットアップ - Qiita

インストールの確認

適当なファイルを生成し、下記の内容を記述する。

今回はhello.goというファイルを作成。

package main
import "fmt"

func main(){
    fmt.Printf("Hello, World!\n")
}

続いて、チェックを行う。 下記コマンドと期待する出力が得られれば完了!

$ go version
go version go1.12 darwin/amd64

$ go run hello.go
Hello, World!

これ以降は...

Goの学習用にA Tour of Goというサイトが設けられています。

インタラクティブに学習を進められるので、環境構築前に触りたい人にオススメです。

go-tour-jp.appspot.com

Railsのテーブル定義書を吐き出したい

はじめに

プロジェクトメンバーにエンジニア以外の関係者がいるときに、テーブル定義書を用意することになった。

テーブル定義書とは?

方法

下記を参考にrakeタスクを作成する。

gist.github.com

とりあえず動かしてみる

lib/tasks内にrakeタスクを作成する。

lib/tasks/dbdoc.rake




エラーが発生!

def get_schema_info(klass)
    table = Table.new
    table.name = klass.table_name
    table.columns = []
    table.indexes = []
    table.comment = klass.connection.retrieve_table_comment(klass.table_name) if defined? MigrationComments

    # 省略
end

ここで、klass(つまりmodels配下の*.rbファイル)とデータベースの整合性が合わない場合に、table_nameでNo Method Errorが発生した。

確認してみると、google_place.rbというGoogleMap用に設けていたモデルファイルが存在していた。

また、appliaction_record.rbというファイルについては、klassがnilで返ってきた。

そのため、もともとの配列から削除してあげることにした。

task dbdoc: :environment do
    klasses = Dir["app/models/**/*.rb"].
      reject{|f| f["concerns/"] }.
      reject{|f| f["app/models/google_place.rb"]}. # 追加
      reject{|f| f["app/models/application_record.rb"]}. # 追加
      map{|f| f.gsub(/^app\/models\/(.+?)\.rb$/, '\1') }.
      map{|m| ActiveSupport::Inflector.camelize(m) }.
      map{|k| ActiveSupport::Inflector.constantize(k) }
    datum = klasses.map{|k| get_schema_info(k) }
    # 省略
end

これで綺麗なklassesの配列が出来上がった。

datum内を覗いてみると、

=> [#<struct Table
  name="hoge_table_names",
  comment=nil,
  columns=
      [#<struct Column name="id", type="bigint(20)", not_null=false, default=nil, primary_key=true, comment=nil>,
    #<struct Column name="hoge_id", type="int(11)", not_null=true, default=nil, primary_key=false, comment=nil>,
    #<struct Column name="huga_id", type="int(11)", not_null=true, default=nil, primary_key=false, comment=nil>,
    #<struct Column name="created_at", type="datetime", not_null=false, default=nil, primary_key=false, comment=nil>,
    #<struct Column name="updated_at", type="datetime", not_null=false, default=nil, primary_key=false, comment=nil>],
  indexes=[]>,
  #<struct Table
    name="contract_plans",
    comment=nil,
    columns=....

というような配列が返ってきた(良い感じ)

しかし、またもやエラーが発生

安堵していたのも束の間、別のエラーが発生した。

rake aborted!
NameError: uninitialized constant Axlsx

何やら不明なAxlsxがあるらしい。

Axlsxとは?

AxlsxはExcelファイルの出力用に用いるらしい。

qiita.com

これを参考にした。

対策

GemfileにExcelファイルを扱うためのGemを導入した。

gem 'axlsx'
gem 'zip-zip'

gem 'zip-zip'を含めないと、axlsxとの依存関係によりエラーが発生します。

これで動くだろう

rakeタスクを実行してみます。

$ bundle exec rake dbdoc:dbdoc

これで、xslxの拡張子付きのテーブル定義書が発行されました〜

Railsのベストプラクティスを教えてくれ

はじめに

こちらの記事は現場でRuby on Railsを用いている筆者が、独断と偏見でRailsのTipsをまとめたサイトを収集する記事です。

基本的に「まとめのまとめ」のスタンスを取ります。

つまり、私の備忘録です。

1. Rails Best Practices

一発目から海外の英語記事ですが()

rails-bestpractices.com