リア充爆発日記

You don't even know what ria-ju really is.

Railsのenumをmodel横断的に使おうとしたときのメモ

複数のモデルにステータスなどの共通した値と処理を持たせたい!と思ってRails4.1のenumを使いつつ、concernなmoduleに切り出そうと思ったら、enumActiveRecord所属だったので、困ってしまったときのメモ。

しょうがないので、ActiveRecordを継承したクラスを作ってそこに処理をまとめようとした。

class StatusRecord < ActiveRecord::Base
  before_create :set_status

  enum status: {draft: 0, published: 1}

  private

  def set_site
    self.status = some_helper_method
  end
end

class Article < StatusRecord
~snip~
end

そしたら、statusってテーブルがねーよッ、というニュアンスにエラーがでた。

ActiveRecord::StatementInvalid:
Mysql2::Error: Table 'hoge.status' doesn't exist: SHOW FULL FIELDS FROM `status `

調べてみると、
self.abstract_class = true
として、紐づくテーブルがないことを宣言する必要があった。

class StatusRecord < ActiveRecord::Base
  self.abstract_class = true
  before_create :set_status

  enum status: {draft: 0, published: 1}

  private

  def set_site
    self.status = :draft
  end
end


これでOK牧場

Railsで送信するメールのSubjectに一括で定型文を入れたいときのメモ

Webサービスから配信されるメールって最初にサービス名が入っているじゃないですか。

[HogeFuga] 会員登録のお知らせ

みたいに。

で、そのタイトルを毎回指定するのを忘れた、とか、忘れたわけじゃなくて、イチイチ入れるのってバカじゃないの?とかそういうケースの話。

ActionMailerのinterceptorを使う。
http://api.rubyonrails.org/classes/ActionMailer/Base.html#label-Observing+and+Intercepting+Mails

config/initializers/mail_subject.rb

class EmailSubject
  def self.delivering_email(mail)
    mail.subject = "[HogeFuga]" + mail.subject
  end
end
ActionMailer::Base.register_interceptor(EmailSubject)

これで、全部のメールタイトルの先頭に[HogeFuga]が挿入されるよ!

やったね!たえちゃん!

Coffeescriptでページを離れる前に警告を表示する方法

入力フォームとかで、うっかりバックスペースとか押しちゃって入力内容パー、みたいな事態を防ぎたいケースの話し。

beforeunloadというイベントを使う。

    $(window).on('beforeunload', (evt)->
      return 'hogehoge'
    )

これでリンク踏んで画面遷移するときはもちろん、リロードもブラウザを閉じたときも発火してアラートがでる。

一部のリンク押下では出したくない場合は以下のようにやればかなり対応できる。

    @$('.js-no-beforeunload').on('click', ->
        $(window).off('beforeunload')
    )
    $(window).on('beforeunload', ->
      return 'hogehoge'
    )

こんな感じで、クリックイベントを取ってbeforeunloadイベントを外す。

リロードを完全に制御するのはブラウザ付属のリロードボタンクリックを判別しなければいけないので、無理かもしれない。どっかの誰かがクリックの座標で判断するってやってたのを見たけど、やる気がおきなかった。

rspecのcontrollerのテストでログインチェックのテストを共通化したメモ

ログインがあるアプリだと、各コントローラでログインしている場合はこう!ログインしてない場合はこう!というテストが書きたくなる。
具体的なテストコードはこんな感じでござる。

describe FoosController do
  let(:user) { FactoryGirl.create(:user) }
  describe 'GET #new' do
    describe 'GET #new' do
    context 'by anonymous user' do
      before do
        get :new
      end
      it { is_expected.to redirect_to signin_path }
    end
    context 'by login user' do
      before do
        sign_in user
        get :new
      end
      it { is_expected.to render_template('new') }
    end
  end
end

これがいろんなところにできていたので、まとめたくなった。
要はgetとかのaction部分と、結果のテンプレートの種類あたりが可変にできればよいのだ。

こんなときの解決法の1つとしてshared exampleがある。

describe FoosController do
  let(:user) { FactoryGirl.create(:user) }
  describe 'GET #new' do
    it_should_behave_like 'authentication required' do
      let(:action){ get :new }
      let(:template) {'new'}
    end
  end
end

support/authentication_required.rb

require 'spec_helper'

shared_examples 'authentication required' do
  context 'by anonymous user' do
    before do
      action
    end
    it { is_expected.to redirect_to signin_path }
  end
  context 'by login user' do
    before do
      sign_in user
      action
    end
    it { is_expected.to render_template(template) }
  end
end

Rails4のconcernsなmoduleのテストをrspecで書く方法で書いたけど、shared_examplesをsupportの下に配置しているのは、ここだとspec実行時にロードされるから。

これでけっこうDRYになったね。

paperclipをAWSのS3+Cloudfrontで使うときの設定メモ

ワリと時間かかったのでメモ。

config/environments/production.rb

  config.paperclip_defaults = {
    storage: :s3,
    s3_host_alias: 'your.cloudfront.net',
    path: '/:class/:attachment/:id/:style/:hash.:extension',
    url: ':s3_alias_url',
    s3_host_name: 's3-ap-northeast-1.amazonaws.com',
    s3_protocol: '',
    s3_credentials: {
      bucket: 'your_backet_name'
    }
  }

config/initializers/paperclip.rb

Paperclip::Attachment.default_options[:hash_secret] = 'abutorudamuraruomunisunomunisuberuesuhorimaku'
Paperclip::Attachment.default_options[:default_url] = 'no_:style.png'


ポインツ

  • initializersには共通の設定を書くが(書かなくてもいいけど)、envrionmentsで上書きする前提で書くと、場合によってはハマるからあまりおすすめしない
  • s3_host_nameは東京リージョンのときは必須
  • http,httpsを状況によって出し分けるには、s3_protocolに空文字を渡しておく
  • クレデンシャル関係はこのケースではEC2自体に権限設定してあるが、色んなやり方があるので好きようにする。

パーフェクト Ruby on Rails

パーフェクト Ruby on Rails

今使っている+今度使ってみたいGemリスト 2014年 夏 ver.

使っているやつ

使っているやつはGemfileを晒す。なお、複数プロジェクトのGemfileをマージしたものなので、全部同時に使ってるわけじゃない。

gem 'rails', '~> 4.1.4'
gem "mysql2", "~> 0.3.16"
gem 'bootstrap-sass', '~> 3.1.1.0'
gem "sass-rails", github: 'rails/sass-rails'
gem 'normalize-rails', '~> 3.0' # reset css
gem 'bourbon', '~> 3.2.3'
gem 'neat', '~> 1.6.0'
gem 'bitters', '~> 0.10.0'
gem 'therubyracer', '~> 0.12.1'
gem 'uglifier', '~> 2.5.3'
gem "coffee-rails", "~> 4.0.1"
gem "jquery-rails", "~> 3.1.1"
gem 'jbuilder', '~> 2.1.3'
gem 'i18n-js', '~> 3.0.0.rc6'
gem 'backbone-on-rails', '~> 1.1.1.0'
gem 'jquery-ui-rails', '~> 5.0.0'
gem 'jquery-modal-rails', '~> 0.0.4'
gem 'omniauth', '~> 1.2.2'
gem "omniauth-twitter", "~> 1.0.1"
gem "omniauth-facebook", "~> 1.6.0"
gem 'faker', '~> 1.4.2'
gem 'tokens', '~> 2.1.1'
gem "settingslogic", "~> 2.0.9"
gem "bcrypt-ruby", "~> 3.1.5"
gem 'kaminari', '~> 0.16.1'
gem 'paperclip', '~> 4.2.0'
# https://bugs.ruby-lang.org/issues/859, http://stackoverflow.com/questions/22660147
gem 'open_uri_redirections', '~> 0.1.4'
gem 'active_decorator', '~> 0.3.4'
gem 'counter_culture', '~> 0.1.24'
gem 'countries', '~> 0.9.3'
gem 'country_select', '~> 1.3.1'
gem 'activerecord-import', '~> 0.5.0'
gem 'mail_form', '~> 1.5.0'
gem 'cells', '~> 3.11.1'
gem 'impressionist', '~> 1.5.1'
gem 'public_activity', '~> 1.4.1'
gem 'retina_rails', '~> 2.0.1'
gem 'remotipart', '~> 1.2.1'
gem 'unicorn', '~> 4.8.3'
gem 'rails_autolink', '~> 1.1.6'
gem 'newrelic_rpm', '~> 3.9.0.229'
gem 'whenever', '~> 0.9.2', require: false
gem 'aws-sdk', '~> 1.48.1'
gem "awesome_nested_set", "~> 3.0.0.rc.2"
gem 'paranoia', '~> 2.0'
gem 'mini_magick', '~> 3.7.0'
gem "ngram", "~> 1.0.0"
gem "moji", "~> 1.6"
gem "unread", "~> 0.3.1"
gem "ransack", github: "activerecord-hackery/ransack", branch: "rails-4"


group :development do
  gem "letter_opener", "~> 1.2.0"
  gem 'quiet_assets', '~> 1.0.3'
  gem 'capistrano', '~> 3.2.1'
  gem 'capistrano-rails', '~> 1.1.1'
  gem 'capistrano-rbenv', '~> 2.0.2'
  gem 'capistrano-bundler', '~> 1.1.2'
  gem 'capistrano3-unicorn', '~> 0.1.1' # 0.2.1にすると、deploy後、リロードのたびに新旧のページが入り乱れる(プロセスの再起動が上手く行っていない?)
  gem 'better_errors', '~> 1.1.0'
  gem 'rubocop', '~> 0.24.1', require: false
end

group :development, :test do
  gem 'rspec-rails', '~> 3.0.2'
  gem 'rspec-mocks', '~> 3.0.3'
  gem 'spring', '~> 1.1.3'
  gem 'spring-commands-rspec', '~> 1.0.2'
end

group :test do
  gem 'capybara', '~> 2.4.1'
  gem 'poltergeist', '~> 1.5.1'
  gem 'factory_girl_rails', '~> 4.4.1'
  gem "shoulda-matchers", "2.6.1", require: false # 2.6.2に上げるとテストが通らなくなる。原因は追ってない。
  gem "database_cleaner", "~> 1.3.0"
  gem 'rake_shared_context', '~> 0.2.1'
  gem 'timecop', '~> 0.7.1'
end

group :doc do
  gem 'sdoc', require: false
end

人気があるようだけど、使ってみてやめたやつ

  • https://github.com/plataformatec/devise
    • デフォルトで全部間に合わすならいいけど、そうでない場合は実装の詳細を把握してる時間で、実装できちゃう機能がほとんど。少しいじるたびに実装調べる時間がもったいない。
  • https://github.com/ctran/annotate_models
    • そのうち再実行する忘れて実態からかけ離れることが多く、自動化するレベルのこととも思えない。加えてファイルのスペース取られるのがイヤ。テーブル構成なんか最初だけで、しばらくやってればだいたい頭に入るのでmigration見るので充分かな。

選択の基準

何かのイケてそうなGemを見つけたら、https://www.ruby-toolbox.com

  • 競合がないか
  • 活動は活発か
  • 使っている人は多いか

などを確認してから採用に踏み切る
migrationが絡むやつはより慎重に・・・。


パーフェクト Ruby on Rails

パーフェクト Ruby on Rails

Androidアプリ開発の手引 2014年 君がいた夏ver.

最後にAndroidアプリをいじっていたのはもう2年近く前のことだ。

2年も経てばスタンダードも大きく変わっているだろうと再度初心に返り、イチからプロジェクトを作ってみたいと思うこの夏。

開発マシン

OSX10.9.4

参考

http://developer.android.com/index.html
まずは公式ですよ、奥さん!質が高いドキュメントがそろってますから!

ここを読んでない輩は、こんなクズブログ読んでないで、ひとそろい公式読んでからまた来なさい。
まぁ、そのときは来ても意味なくなってると思うけどな!

JAVA

そもそもJAVAの最新バージョンってなんだっけ、と思ってJAVAのサイトいったら「あなたとJAVA」とか出てきてこのコピー必要だったの?ってモヤッた。

がともかく、2014年8月時点ではJDK8が最新だった。

で、Androidの対応バージョンはどうなんだ。2年前は6だったけど、7くらいは使えるようになってんじゃねーの?と思ったら未だに6だった。
http://developer.android.com/sdk/index.html

あれー、7に対応したってのをどっかで見かけたような気がしたんだけどなぁ。別にstringのswitchくらいしか使いそうな機能はないんだけど。

と思ったら一部を除いて使えるみたい。
http://qiita.com/hidekuro/items/6a252c82132ed5d279a4

stackoverflowなど、観測範囲では特に7によるトラブルは見当たらなかったけれども、公式は6推しのようなので、受託とかなら6を使っておいたほうがいいかもね。

まあ、今回は7でいくけど。

ここからdmgゲット。
http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html

で、GUIインストーラでインストールするだけでOK。

$ java -version
java version "1.7.0_65"
Java(TM) SE Runtime Environment (build 1.7.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)

IDE

何を使うかだけど、今はAndroidStudioってのがあるらしいね!しかもIntelliJのところが作ってんだね!公式もやや推し気味だね!
で、そんなものがないときから、IntelliJでやってたぼくは当然IntelliJAndroidプラグインを使う。

貧乏な人はAndroid Studioを使えばいいんじゃないでしょうか。
ってか、違いってあるんかね。

http://blog.jetbrains.com/idea/2013/05/intellij-idea-and-android-studio-faq/

Is Android Studio a fork of IntelliJ IDEA?

No. Android Studio and the Android plugin for IntelliJ IDEA are built from the same code, and all of the changes in Android Studio are, and will continue to be, available in IntelliJ IDEA releases.

ということで、Android StudioAndroidプラグインも同じなんで、AndroidStudio使ったからって損することはないらしい。

ただ、さっきのリンクの他のFAQでAndroid依存でないところの基本的な機能はIntelliJにしか乗らないものはあるのでIntelliJを使っている人はIntellijを使ったほうがいいって言ってた。
なお、プロジェクトは同じ形式なので、どっちからどっちに乗り換えても問題ないらしい。


Android SDK

このケースだと、スタンドアロンで入れることになるんだと思う。

http://developer.android.com/sdk/installing/index.html?pkg=tools
この通りにすればいいと思う。
Zipダウンロードして、回答して、~/Developmentあたりに置いとけばいいんじゃないでしょうか。
その後、パスを通してコンソールでandroidって打つと、SDKマネージャが立ち上がるのでバリバリインストールしたいバージョンのライブラリを入れておくべし。

$ export PATH=$PATH:~/Development/android/sdk/platform-tools:~/Development/android/sdk/tools
$ android

こんな感じでいいと思う。
というのも、ぼくは、既に入っていて記憶に無いけど4.4.2まで入っているのでこのプロセスは実施してないのでちょっと違うところがあるかも。

※追記)今はhomebrewで入れられるらしい

プロジェクト作成

とりあえずIntelliJで新しいプロジェクトを作る

Create New Project > Android > Application Module
で、アプリ名とかパッケージ名とかいれるところは今回はとりあえずそのままで行く。ついでにHello world activityも作ってもらおう。
で、SDK指定するところがあるので、さっき入れたSDKのディレクトリを指定すると、APIレベルの候補を出してくるので好きなのを選ぶ。今回は現時点で最新のAPI19を選んでおいた。

で、完了すると、何もでない。が、これは時間がかかっているだけなので、待つべし。

ロードが完了したら設定をいじる。

ProjectSettings(コマンド+;)で、

  • SDK > JDKをさっきインストールした1.7に変更する。
  • Project > Project language levelを7.0に変更する。

エミュレータ

2年前は死ぬほどおっそいエミュレータしか提供しておらず、やっとこさ爆速エミュレータが不安定ながらも登場したてのほやほやでしたが、今はどうなんでしょうか。

で、調べてみるとGENYMOTION という名前をよく見かけたので試してみることにした。
http://www.genymotion.com/
https://shop.genymotion.com/index.php?controller=order-opc

Freeプランでも問題ないと思う。Pixel Perfectだけ若干気になるけど、このへんは実機で確認すればいいべ。

もろもろ手続きしてダウンロードする。あっ。IntelliJ IDEA Pluginもある!
あと、VirtualBoxが必須なのでこいつもダウンロードしておく。
https://www.virtualbox.org/wiki/Downloads

で、これらをインストールしてGENYMOTIONを起動してみる。

すると、GalaxyS4のイメージをインストールするか聞かれたので、それを選んだらなぜかエラーになった。調べる気がおきなかったので、あとからGoogle Nexusのイメージを追加した。

追加している間、Genymotionがステキさをアピールしてくる。

Genymotion is fast! CPU and GPU hardware accelerated. Boot more than 3 times faster, deploy your app 2 times faster!

イメージカラーが赤いのでやっぱり3倍速いらしい。


インストール後、エミュレータを起動してみる。うん、なかなか速い。

Hello World

で、プロジェクト作成時にHello World activityを自動生成するようにしたので、とりあえずアプリとしては成立している状態のはず。
起動してみる。
Run > run 'myapp'

すると、さっき追加したエミュレータがdeploy先の選択肢に出てきたので選択したら・・・

できた!


なお、さっきHello World activityを生成するときに、APIレベルを19に設定しているので、エミュレータもAPI19をサポートしているやつじゃないと動かない。それ以外のエミュレータを入れてしまった場合は、AndroidManifestのandroid:minSdkVersionをいじればOK。

次は、テストとかその辺かな・・・。


良いAndroidアプリを作る139の鉄則

良いAndroidアプリを作る139の鉄則