paranitips

Never stop learning! がモットーのゆるふわエンジニアブログ

railsで使えるメソッドとかハマったところとか

ちょっとたまってきたのでメモがてらまとめます。

1. Hashを逆順にする

あるハッシュ

h = { "1" => "a", "2" => "c", "3" => "y", "4" => "x" }

を逆順の

{ "4" => "x", "3" => "y", "2" => "c", "1" => "a" }

にしたい場合、Arrayreverseが使えます。

reversed_h = Hash[h.to_a.reverse]

ruby2.1以降であればもっとカンタン。

reversed_h = h.to_a.reverse.to_h

2. or and|| &&の優先順位に注意

演算子の優先順位がちがうので想定外の結果になることがしばしば。。

[1] pry(main)> a = true and false
[2] pry(main)> a
=> true
[3] pry(main)> a = true && false
[4] pry(main)> a
=> false

たとえば、次のような予期せぬ結果を生みます。

true_and_false = true and false
if true_and_false
  puts "true"
else
  puts "false"
end
#=> true

Railsのハマりどころで有名らしいのですが、なかなか気付きにくい。。 基本的にand orを使う場合は()で囲むか、|| &&を使っていく方針が良さそう。

3. カレンダーとかセレクトボックスで便利なメソッド

all_monthを使えばd.beginning_of_month..d.end_of_monthみたいに長ったらしいメソッドを書かなくてすむ。

[6] pry(main)> d = Date.today
=> Sat, 13 Jun 2015
[7] pry(main)> d.beginning_of_month..d.end_of_month
=> Mon, 01 Jun 2015..Tue, 30 Jun 2015
[8] pry(main)> d.all_month
=> Mon, 01 Jun 2015..Tue, 30 Jun 2015

ほかにもall_week all_quarter all_yearがあります。

4. CSV.foreachで行数を取得する

たとえば、一行目をスキップしたい場合などに使えます。

require 'csv'

CSV.foreach('test.csv') do |csv|
  next if $. == 1
  ....
end

5. メソッド呼び出しをスマートに

オブジェクトのプロパティにアクセスする際、nilクラスの場合を考慮して以下のように書くことが多いのですが、

name = user.present? user.name : "名無しさん"

tryを使うともっとスマートに書けます。

name = user.try(:name) || "名無しさん" 

6. 値の有無チェックをスマートに

とりわけparamsの値チェックで重宝します。通常はpresent?で有無をチェックして、存在すればその値を入れますが、

name = params[:name].present? ? params[:name] : "名無しさん"

presenceを使うとスマートに書けます。

name = params[:name].presence || "名無しさん"

7. layoutをある条件で切り替えたい

単純にactionだけで切り替えるのではなく、特定の条件で(たとえばスマートフォンの場合だけ)レイアウトを変更したい場合は以下のようにします。

before_action set_hoge_layout

def set_hoge_layout
  self.class.layout "hoge" if request.mobile
end

今回は以上です。またたまってきたらまとめよう。

参考

秩父にキャンプにいってきました

f:id:paranishian:20150516090608j:plain

最近キャンプにハマってます。

週末に秩父にある秩父巴川オートキャンプ場に行ってきました。

秩父には東京から都内から車で2〜3時間くらいで行けます。

行きに小松沢レジャー農園に寄り、しいたけ狩りをしてBBQ食材を調達しました。

f:id:paranishian:20150516112928j:plainf:id:paranishian:20150516113115j:plain

ここでは、しいたけ狩りだけではなくいちご狩りやマス掴みなどいろんな体験ができます。また、炭火焼きコーナー(無料)があるので、食材を取ってすぐに焼けます。しいたけめっちゃ旨いです。ちょーオススメです。

 

そのあと近くのスーパーで買い出しをして、 秩父巴川オートキャンプ場に到着。

川の目の前のサイトにリビシェルとピルツを設営して環境構築完了!

f:id:paranishian:20150516151457j:plain

あとは旨い飯を食べながらお酒を飲むだけ!

焚き火をしながら優雅な気分で。w 

f:id:paranishian:20150516194533j:plain

 

2日目は近くにあるフォレストアドベンチャー秩父でアドベンチャーコースを体験!コースを制覇するのに3時間くらいかかりました。。

f:id:paranishian:20150517135341j:plain

 

フォレストアドベンチャー秩父が入ってるPICA秩父で昼ごはんを食べ、温泉に入ってゆっくりしてから帰宅。

なかなかに充実した週末でした。

やっぱりエンジニアという職業柄インドアになりがちなのでアウトドアでどんどん体験していこうとおもいます!

 (今回のスポットでマイマップ作ってみました。)

 

参考

 

omniauthでfacebook, google+のSNS連携を実装する

作業環境

$ ruby --version
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin14.0]
$ rails --version
Rails 4.1.1

実装手順

必要なgemのインストール

まずはomniauthをgemでインストールします。

gem 'omniauth'
gem 'omniauth-facebook'
gem 'omniauth-google-oauth2'
$ bundle

initializerの作成

config/initializer/omniauth.rbを作成します。

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :facebook, ENV['FB_APP_ID'], ENV['FB_SECRET']
  provider :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET'], name: :google
end

これで、/auth/:providerで各providerの認証ページにリダイレクトされるようになります。 google_oauth2name: :googleを設定しておくと、認証URLやコールバックURLでproviderがgoogleになるので便利です。

ENVの内容は各SNSでアプリやプロジェクトを作成して入手して書き換えてください。

モデルの作成

認証情報のモデルを作成します。

$ rails g model SocialProfile

migrationはここを参考に作っておけば大丈夫でしょう〜。

class SocialProfile < ActiveRecord::Base
    belongs_to :member
    store :other
    validates_uniqueness_of :uid, scope: :provider

    def set_values(omniauth)
        return if provider.to_s != omniauth['provider'].to_s || uid != omniauth['uid']
        credentials = omniauth['credentials']
        info = omniauth['info']

        self.access_token = credentials['token']
        self.access_secret = credentials['secret']
        self.credentials = credentials.to_json
        self.name = info['name']
        self.nickname = info['nickname']
        self.email = info['email']
        self.image_url = info['image']
        self.description = info['description'].try(:truncate, 255)
        case provider.to_s
        when 'google'
            self.nickname ||= info['email'].sub(/(.+)@gmail.com/, '\1')
        when 'facebook'
            self.url = info['urls']['Facebook']
        end

        self.set_values_by_raw_info(omniauth['extra']['raw_info'])
    end

    def set_values_by_raw_info(raw_info)
        case provider.to_s
        when 'google'
            self.url = raw_info['link']
        when 'facebook'
            # 特に追加する項目なし
        end

        self.raw_info = raw_info.to_json
    end
end

コントローラーの作成

SNSでの認証のコールバックを受けるコントローラーを作成します。

$ rails g controller sessions
class SessionsController < ApplicationController

  def callback
    omniauth = request.env['omniauth.auth']
    if omniauth.present?
      # 認証が成功したときの処理
      omniauth = request.env['omniauth.auth']
      if omniauth.present?
        profile = SocialProfile.find_or_initialize_by(provider: omniauth['provider'], uid: omniauth['uid'])
        profile.set_values(omniauth)
        # ...(ユーザ登録、ログイン等をしておく)
      end
    else
      # 認証情報がないときの処理
      # ...(エラーレンダリングとかしておく)
    end
  end

  def failure
    # 認証が失敗したときの処理(キャンセルを押された時とか)
    # ...(エラーレンダリングとかしておく)
  end
end

ルーティングの追加

...
get  '/auth/:provider/callback' => 'sessions#callback'
post '/auth/:provider/callback'  => 'sessions#callback'
get  '/auth/failure' => 'sessions#failure'
...

各providerの認証コールバックURLに/sessions/facebook/callback/sessions/google/callbackを設定すればOKです。

リンクの設置

<%= link_to 'Facebook連携', '/auth/facebook' %>
<%= link_to 'Google連携', '/auth/google' %>

以上です。omniauthかんたんですね!

参考