higan96技術メモ

https://github.com/higan96

sessionに保存されたHashの挙動がストア前後で変わる。

sessionに保存されたHashの挙動がストア前後で変わる。

session[:test_data] = {hoge: ‘fizz’, fuga: ‘buzz’ }

としたとき、session[:test_data]の中身は

{:hoge =>’fizz’, :fuga => ‘buzz’}

となる。
しかしこれが別のアクションで使用するとき、つまり一度ストアされると、

{‘hoge’ =>’fizz’, ‘fuga’ => ‘buzz’}

このように、keyがシンボルから文字列に変わっている。

これ、stackoverflowにも質問がありました。
session - Ruby on Rails sneakily changing nested hash keys from symbols to strings - Stack Overflow
回答

Sessions, if you're using cookie ones, do not live in Ruby - they are transmitted back and forth across the network. The session object you stored your data in is not the same session object that you tried to read it from. And while in cookie form, there is no difference between strings and symbols. Use Hash#symbolize_keys! to be sure you have your keys as you wish, or just use the string keys consistently.

解決方法としては

  • シンボルではなく文字列を使う
  • symbolize_keys!を使用する

ということらしい。

cookieの仕様っぽいですね。

使っていないminitestでWarningが出たよ問題

version:
rails: 4.1


rails4.1にupdateしたら、使っていないはずのminitestを要求されて、困惑しました。

Warning: you should require 'minitest/autorun' instead.
Warning: or add 'gem "minitest"' before 'require "minitest/autorun"'

shoulda-matcherが原因でしたアップデートしましょう。

shoulda-matcher: 2.5

shoulda-matcher: 2.6

paperclipでlocaleに関するエラーが出たので対処

Rails 4.0.3
paperclip 4.1.1

ファイルアップロードのライブラリとしてpaperclipを使っているのですが、 ファイルサイズについてのバリデーションをModelに加え、テストも加えたのですが、どうにもlocaleファイルが無いよ、とテストを走らせるとエラーが出てしまいました。

Failure/Error: it { should validate_attachment_size(:avatar).
I18n::MissingTranslationData:
translation missing: ja.number.human.storage_units.format

で、ソースを追うと、enについてのlocale fileしか無いのでエラーが出ている様子
github

#paperclip/lib/paperclip/locales/en.yml
en:
  errors:
    messages:
      in_between: "must be in between %{min} and %{max}"
      spoofed_media_type: "has an extension that does not match its contents"

  number:
    human:
      storage_units:
        format: "%n %u"
        units:
          byte:
            one:   "Byte"
            other: "Bytes"
          kb: "KB"
          mb: "MB"
          gb: "GB"
          tb: "TB"

まあ、特にenでも問題なさそうなんで、validates_attachment_size にlocaleオプションでenを設定して、解決しました。

#Model
validates_attachment_size :avatar, less_than: 1.megabytes

#Model
validates_attachment_size :avatar, less_than: 1.megabytes, locale: :en


追記:
https://github.com/svenfuchs/rails-i18n/
このへん入れるだけでも、localeオプション無しでエラーでなくなります。

#Model
validates_attachment_size :avatar, less_than: 1.megabytes

プロジェクトのリモートリポジトリで他のメンバーのプルリクがmergeされたら

他のメンバーの作業ブランチがリモートレポジトリでmasterブランチにマージされた

自マシンのローカルレポジトリのmasterブランチをgit pullで同期

git checkout master
git pull


(その後、自分がプルリクエストを送りたい場合)

対象の作業ブランチでmerge masterする

git checkout some-branch
git merge master


mergeする際にコンフリクトが発生するとそのファイルはaddされず、ステージされない

コンフリクトを解決して、そのコンフリクトしていたファイルをaddしてcommit
(コンフリクトは解決しなくても、addすればコミット+マージ自体は行えるので注意)

git add .
git commit


(コミットメッセージの編集画面が表示される)

コミットメッセージにコンフリクトの内容が含まれるので、必要なら残す

普通にpushして、プルリクエスト等を送る

git push origin some-branch


おしまい

Devise使っててNameError: wrong constant name mailersが出た時の対処

version:
rails: 4.0.3
devise: 3.2.2

config/initializers/devise.rb

#config.mailer = 'Devise::Mailer'

config.mailer = 'Devise::Mailer'

「config.mailer = 'Devise::Mailer'」のコメントを外したら動くようになりました。

エラーの状況が発現したのが、自分でMailer実装した後だったんで、あたりをつけて設定書き換えたら動きました。理由はあんま深くまで追っていないので想像ですが、Devise側で暗黙に決まっていた定数が新しく追加したメーラで書き換えられたとかなのかな、と。

deviseのRemberable機能をデータベースにカラムを用意して使用する方法

deviseでは様々な機能がはじめから用意されています。それら機能はモジュール化されており開発者の用途に合わせて選択できるようになっています。


その中に「rememberable」という、所謂remember meの機能も用意されていて、その機能なのですが、少し変わった設計でして、定石通りDB上にカラムを用意してtokenを保存するという仕様にはなっていません。


具体的な仕様は、DBに保存されたencrypted_passwordというハッシュ化されたパスワードを使用して、remeber meの機能を実現しています。
参考URL:
Devise3.2.2 のデフォルト設定では、Rememberable の remember_token のカラムがないのでソースを解読してみた | EasyRamble


で、この仕様、Omniauthなんかを使ってOauthのSNS認証でユーザー機能を実装しようとすると、deviseのfriendly_tokenなんかを使ってダミーパスワードを作らないとRemember me機能が使えなくなります。


で、この問題、DeviseではオーソドックスなDB上にtokenを保存する仕様に変更できるようになっています。


その手順はいたって簡単。

remember_tokenというカラムをUsersテーブルにつくる


この情報、GithubWikiに記載がありました。その部分だけ引用します。

have a remember_token column in your model

Omniauthable, sign out action and rememberable · plataformatec/devise Wiki · GitHub

こんだけしか記載がありません。

以上のようにremember_tokenのカラムを用意すれば、ユーザーのレコードをcreateするときにfriendly_tokenを使ってpasswordを指定する必要はありません。

Rails4なのにMassAssignに関するエラーが出た理由

症状

Rails4 + Devise + Omniauthを使って認証機能なんかを作っていたのですが、何故かMassAssignに関するエラーが出てしまい、新規ユーザーのレコードが保存できない事態に陥ってしまいました。

WARNING: Can't mass-assign protected attributes for User: name, password

Rails4ではコントローラ側のStrongParametersでユーザーレコードの更新に使用するParameterを許可するはずで、なんでだー!Model側のエラーじゃないかー!と2日くらい悩んでいたのですが、理由は簡単でした。

理由

じぶんで「protected_attributes」のgemをインストールしていたから。

対策

なので、Gemfileからprotected_attributesを削除し、アンインストール。

反省
  • 今回の事態を引き起こした理由

不用意なコピペ
特に意味も確かめずにコピペしていました。これではいけない。自分のコードについて、その意図をすべて説明できるようでなければならない。

  • 今後の対策

不用意なコピペをしない、参照先のコードの意図を読み取る。ソースを深く読む。


なんか日本昔ばなしとかでありそうな話だ。思慮の浅い若者が、良かれと思ってとった不用意な行動によって墓穴を掘るみたいな。