Railsのxxx_pathとかxxx_urlの引数を調べた

リファレンス読んでもいまいちわからなかったので、そういうときはRailsそのもののソースを読むに限る。

_pathgrepしてみると、

# actionpack/lib/action_dispatch/routing/route_set.rb

  def add(name, route)
    key       = name.to_sym
    path_name = :"#{name}_path"
    url_name  = :"#{name}_url"

    if routes.key? key
      @path_helpers_module.send :undef_method, path_name
      @url_helpers_module.send  :undef_method, url_name
    end
    routes[key] = route
    define_url_helper @path_helpers_module, route, path_name, route.defaults, name, PATH
    define_url_helper @url_helpers_module,  route, url_name,  route.defaults, name, UNKNOWN

    @path_helpers << path_name
    @url_helpers << url_name
  end

bundle exec rake routes したときに出てくるルート情報っぽいものを作ってる場所なんだけど、そこで define_url_helper ってのがあった。きっとこれだ。

# actionpack/lib/action_dispatch/routing/route_set.rb

  # Create a URL helper allowing ordered parameters to be associated
  # with corresponding dynamic segments, so you can do:
  #
  #   foo_url(bar, baz, bang)
  #
  # Instead of:
  #
  #   foo_url(bar: bar, baz: baz, bang: bang)
  #
  # Also allow options hash, so you can do:
  #
  #   foo_url(bar, baz, bang, sort_by: 'baz')
  #
  def define_url_helper(mod, route, name, opts, route_key, url_strategy)
    helper = UrlHelper.create(route, opts, route_key, url_strategy)
    mod.module_eval do
      define_method(name) do |*args|
        last = args.last
        options = \
          case last
          when Hash
            args.pop
          when ActionController::Parameters
            args.pop.to_h
          end
        helper.call self, args, options
      end
    end
  end

ここでさらに UrlHelper というのが出てくる。

# actionpack/lib/action_dispatch/routing/route_set.rb

  def initialize(route, options, route_name, url_strategy)
    @options      = options
    @segment_keys = route.segment_keys.uniq
    @route        = route
    @url_strategy = url_strategy
    @route_name   = route_name
  end

  def call(t, args, inner_options)
    controller_options = t.url_options
    options = controller_options.merge @options
    hash = handle_positional_args(controller_options,
                                  inner_options || {},
                                  args,
                                  options,
                                  @segment_keys)

    t._routes.url_for(hash, route_name, url_strategy)
  end

handle_positional_args… (そろそろメタっぽいコードを見るのが辛くなってきた)

# actionpack/lib/action_dispatch/routing/route_set.rb

  def handle_positional_args(controller_options, inner_options, args, result, path_params)
    if args.size > 0
      # take format into account
      if path_params.include?(:format)
        path_params_size = path_params.size - 1
      else
        path_params_size = path_params.size
      end

      if args.size < path_params_size
        path_params -= controller_options.keys
        path_params -= result.keys
      end
      inner_options.each_key do |key|
        path_params.delete(key)
      end

      args.each_with_index do |arg, index|
        param = path_params[index]
        result[param] = arg if param
      end
    end

    result.merge!(inner_options)
  end

本気で困ったときにもう一回見直すことにしよう・・。

imakaraでやりたかったことなど

昨日、imakaraっていうアプリをリリースしてみた。

play.google.com

きっかけ

「いまから行くからね〜」って言ってから、

「いまどこ?」「○○過ぎたとこ〜」

「いまどこ?」「電車が遅れてて、△△駅でとまってる」

f:id:YusukeIwaki:20170525110500p:plain

↑相手のイメージw

みたいなやりとりをいちいちメッセンジャーでやるのは面倒だ。 そんなやり取りをする時間があるなら、ふつうにネットサーフィンしていたい。

位置情報はべつにいつ抜かれても構わないから、相手が自分の位置を知りたいときに知れるシステムを作ろう、というのがきっかけでした。

やりたかったこと

いわゆる「待ち合わせアプリ」などは、常時測位している。これはものすごく効率が悪い。

GPS測位というのはスマホにおいては非常に電力を食う操作なので、 相手が私の場所を知りたいというのはせいぜい2,3秒であるとすると、その前後数秒だけ測位を行うようにするのが最も効率がいいのです。

サーバーの設計

カッコいいアーキテクチャを使おうとかは全然考えてなくて、 シンプルにRailsでHTTPサーバー1つ作るだけで完結させたい、という意図が強かった。Workerとかは状態管理が面倒なのでなるべく動かしたくない。ということで、

f:id:YusukeIwaki:20170525103823p:plain

イメージ的にはこんな感じでプッシュを使いつつ実現する、ということをやってみました。

アプリの設計

常時測位しない、というのが最大の特徴なのですが、AndroidFLP(Fused Location Provider)のAPI

のように、常時測位を前提としたものしかありません。 なので、

requestLocationUpdateして、1回でも位置情報が取れたらそこでremoveLocationUpdateする という測位サービスを作り、 「測位して〜」プッシュを受け取ったときに、そのサービスを一発叩くようにしました。

あとは、画面ベースでてきとうにつくりました。

より広く使ってもらうために

追跡URLにはディープリンクが仕込んであって、アプリがインストールされていたら、位置をワンショットで示すだけでなく「新しい測位結果」プッシュを受け取って最新の位置情報をつねに見ることができるようになっています。

ただ、「Google playからimakaraっていうアプリをインストールして、それからこのURLを見てね」っていうと、大抵の人はGoogle playでimakaraを見つけられず、単純にブラウザでURLを見て満足してしまいます。 そこで、Firebase Dynamic Linksというのを使って、「アプリが入っていない人にはストアに飛ばし、アプリインストール後、ディープリンクを開く」というのを実現しました。

これにより、Androidにそこまで詳しくない人とか面倒くさがりな人でも、Google Playに飛ばされたときに「インストール」するだけなので、かなりスムーズに追跡URLをアプリで見るところまで到達できます。

さいごに

デザインは超絶適当なんで、フィードバックとかぷるりとかお待ちしています(てきとうw

github.com

Android用のGitHubのIssue Viewerを作ってみた

実に1年11ヶ月ぶりの投稿。
Qiitaなんて使い始めたら、自分のブログを放置気味になってしまっていけませんね。
自分のことは自分のブログの上に書かないと。

2015年4月に転職してから本格的なアプリ開発を始めたものの、1年半でもう完全に飽きてきました。
もう自分のためになるアプリしか作りたくない、最近。
とはいっても、アプリ開発をしている以上は、ポートフォリオ的なものは持っておいたほうがいい。

ということで、とりあえず自分のためのGitHubのIssue Viewerつくりました。




明言しますが、やってることはJasperのパクリです。
あらかじめ検索クエリをいくつか登録しておいて、定期的にフェッチしてるだけっす。


  • スマホで通知がほしかった
  • Jasperは自分にはToo muchだった
ので、自分でてきとうに作りました。

表向きは自分用のアプリでしたが

  • GitHub OAuthの練習
  • 「Realm使ってます( ー`дー´)キリッ」の実績づくり
  • Kotlinの練習(をしようとしたけど面倒すぎたのでやめた)
  • Fastlaneの導入練習
  • iOSでも同じようなモノをつくるための前練習
という裏の目的もあります。
もちろんソースは公開です。
https://github.com/YusukeIwaki/GitHub-Issue-Viewer-2

ということで、2016年も今日で終わりですね。みなさま良いお年を!