motolog

Everything I love in my life.

Rails3でflashにリンクを組み込む方法

flashでリンク出てきたほうが親切だなと思い、やってみました。
少しだけハマるとこありました。

# users_controller.rb

def update
  link = "<a href=\"#{url_for(:controller => 'users', :action => 'show')}\">#{@hoge.name}</a>"
  if @hoge.save
    flash[:success] = "保存されました。#{link}".html_safe
    redirect_to dashboard_path
  end
end

分かりやすくするため、link 部分を変数にしました。ポイントは以下。

  • 'link_to' ではなく 'url_for' で指定してあげる
  • '.html_safe' でHTMLがエスケイプしないようにしてあげる(Rails3.x の時)

この2箇所かなと。
'link_to' を controller から利用するには、helper module が必要なので、'url_for' を採用。それから、Rails3では自動でエスケイプ処理が行われる仕様なので、それを'.html_safe'で制御。

おわり!

※ 無理矢理感は否めませんが、まあ動くというレベルですね…

プログラミングと数学の証明の共通点

プログラミング初心者の雑感だけれど、たまにプログラミングは数学の証明と類似しているなーと思います。

両者の共通項は次のような感じ。

  • 解くべき問題の条件が与えられており、
  • 証明すべき命題(完成形)を示すことが目的であり、
  • その道筋は当事者に委ねられている

3点目の、「どのように導くか」という点で技量が試されたりするところも、プログラミングと数学の証明で共通していると言えるでしょう。

高校時代のお話 - たくさんの問題に触れて引き出しを増やすこと

そういえば、僕の通っていた高校は、理系重視の方針もあり在学生の7割ほどは理系だったかなという感じなのですが、クラスで数学の証明なんかをやると、普通なら20行くらい必要なはずのところを、スラっと5行くらいで書いてしまう人がいたりしました。

先生も苦笑い。彼はプログラミングをやらせてもきっと綺麗でスマートなコードを書くんじゃないかなと思います。

そういえば、彼が何をしていたかと思い返してみると、いつも「大学の数学」を解いていた気がします。きっと僕なんかよりずっとずっと多くの問題に触れていました。

「たくさんの問題に触れて引き出しを増やすこと」

数学教師が口を酸っぱくして言っていた言葉がふと蘇りました。

Railsでサブドメイン間でログインを保持するためのセッション設定

Railsでサブドメインにアクセスすると、デフォルトの設定では、ログイン(セッション)が保持されません。

解決策は以下の通りです。
ググると間違った(or 古い)情報も散乱していたので、惑わされないようにそちらも一応のせておきます。

session_store.rbの設定

session_store.rb で以下のように設定します。




# session_store.rb
Appname::Application.config.session_store :cookie_store, key: '_user_session', domain: 'example.com'

少し解説すると、

domain: 'example.com'

のように、domainを指定するのがポイント。
production, staging, development で以下のように分岐してあげればいいかなと。

if Rails.env.production?
Appname::Application.config.session_store :cookie_store, key: '_user_session', domain: 'example.com'
elsif Rails.env.staging?
Appname::Application.config.session_store :cookie_store, key: '_user_session', domain: 'staging-example.com'
else
Appname::Application.config.session_store :cookie_store, key: '_user_session', domain: 'lvh.me'
end

ちなみに、stagingで用いている 'lvh.me' は、127.0.0.0 に割り当てらているドメインです。localhost だとサブドメインのチェックはできないので、lvh.me はすごく便利。

domainオプションを追記する際には、keyも変えるべし

ここはハマったところなのですが、domain: 'example.com' を追加すると、セッションの情報も変わります。しかし、keyの名前は同じ。

すると、既にログインしていたユーザーがログアウトできなくなるなどの不都合が生じてしまう可能性があります。(実装にも依ると思いますが)

なので、domainオプションを追加するタイミングで、session_key の名前も変更しておいたほうが無難だなーと思います。

関連記事



Railsでカスタムサブドメイン-本サイトとサブドメイン間のURL設定

Railsでサブドメインを実装した際に、本サイトとサブドメインサイト間の受け渡しで少しハマりました。

サブドメインサイトにいる状態で、root_path や root_url でリンク先を指定しても、本サイトではなく、そのサブドメインのトップに飛ばされます。

この記事では、url_for メソッドを利用して、サブドメインサイトと本サイト間を行き来する方法をご紹介します。



url_forでメソッド作成

subdomain_url_helper を以下のように作成

module SubdomainUrlHelper
  def with_subdomain(subdomain)
    subdomain ||= 'www'
    subdomain += "."
    [subdomain, request.domain].join
  end

  # - remove subdomain and go to the original site
  #    url_for(:subdomain => false)
  # - go to the specific subdomain site
  #    url_for(:requested_subdomain => 'subdomain')
  def url_for(options = nil)
    if options.kind_of?(Hash) && options.has_key?(:subdomain)
      options[:host] = with_subdomain(options.delete(:subdomain))
    elsif options.kind_of?(Hash) && options.has_key?(:requested_subdomain)
      options[:host] = with_subdomain(options.delete(:requested_subdomain))
      options[:controller] = 'users'
      options[:action] = 'show'
    end
    super
  end
end

メインは、2つめのurl_forメソッド。
with_subdomainメソッドは、引数の subdomain と request.domain を合わせるためのもの。なお、subdomain が存在しなければ、www が代わりに入る。
そのため、

url_for(:subdomain => false)

とすると、

# if request.domain is "example.com"
www.example.com

のようになる。

url_for については、渡された hashのkey で条件分岐してあるのは、見ての通りです。

コードがなかなか汚いのでだれかリファクタお願いします。

関連記事



Railsでカスタムサブドメイン機能を実装する時のルーティング設定

運営中のサービス「BoxToYou(https://www.box2you.com)」でカスタムサブドメイン機能をリリースしました。

いくつかハマったところがあったので、数回に分けてメモしていきまする。

今回は、routingの設定とリンクの設定方法について。



サブドメインの条件定義

まず、subdomain.rb でサブドメインの条件をかきかき。

#subdomain.rb 

class Subdomain
  def self.matches?(request)
    request.subdomain.present? && request.subdomain != "www"
  end
end

RailsのRequestオブジェクトにsubdomainメソッドが定義されているので、

request.subdomain

という風にリクエストのサブドメイン部分「http://◯◯◯.example.com」の◯◯◯を簡単に呼び出せます。ただし、「www」もサブドメインとして処理されますので、カスタムサブドメインの設定としては不適切として、

request.subdomain != "www"

という風にmatchの条件から排除しています。

ルーティングの設定

次に、routesファイルの設定。

#routes.rb

# routes setting of subdomain
# should be placed above the "root :to" path
require "#{Rails.root}/app/helpers/subdomain"
  constraints(Subdomain) do
    match "/" => 'users#show'
    match "/*a" => 'application#render_error404'
  end

# other routes settings
root :to => "users#index" #

上記のsubdomain.rbを読み込み、
constraints で条件がマッチした際には、別のactionに飛ばすようにしています。

match "/" => 'users#show'
match "/*a" => 'application#render_error404'

については、アプリの仕様で、root_path の後ろには何も来ない場合の処理です。404 error のページへ飛ぶようにcontroller側で設定しています。

コントローラー側の制御

ちなみに、subdomain の controller 側の処理はこんな感じです。

# users_controller.rb

# if no users exist who has the requested.subdomain, 
# redirect the request to the top page.
unless User.where(:subdomain => request.subdomain).present?
  return redirect_to url_for(:subdomain => false)
 end

# specific a user from request.subdomain
@user = User.where(:subdomain => request.subdomain).first

リクエストされたサブドメインを持ったユーザーが存在しなかった場合は、トップページにリダイレクトしています。
url_for(:subdomain => false)に関しては、subdomain_url_helper.rb というヘルパーを作って設定しています。(詳細はこちら

そして、次に、subdomain は各ユーザーがユニークで持てるようにしているので、

@user = User.where(:subdomain => request.subdomain).first

で特定のユーザーを特定して、インスタンス変数に入れています。

こんな感じで、だいたいの設定はできるかと。


関連記事

参考記事



Rails - mockを使って1つの属性のみにvalidationを走らせてみる

ユニークなユーザー名やサブドメインを付与するときに、ajaxで入力されたその場で有効な値かどうかを判断してあげれば、ユーザビリティは向上するだろう。ツイッターなど大規模なウェブサービスでは実装されていることが多いかと思う。

しかし、.valid? メソッドを使ってしまうと、そのオブジェクト全体にvalidationがかかってしまい不都合が生じてしまうので、今回は、1つの属性に対してvalidationをする方法について扱う。

具体的には、以下のように、検証を行いたい1つの属性を持った新しいオブジェクト(ここでは、mock)を作り、mock.valid? でエラーを発生させ、そのエラーに調べたい属性のkeyがあるかどうかを見る。

def valid_attribute?(attr, value, present_username)
  mock = User.new(attr => value)
  unless mock.valid?
    if mock.errors.has_key?(attr) && value != present_username
      return false
    else
      return true
    end
  end
  true
end

attr が調べたい属性の名前、value がその属性に与えられた値。
さらに、ここでは、ユーザーネームの検証を行うと仮定して、present_username という引数を与えてみた。

ポイントは、

mock = User.new(attr => value)

で、ユーザーが入力した値を用いて、新しいユーザー mock を擬似的につくり、

unless mock.valid?

で、エラーを発生させ(全ての属性の検証にクリアすれば true が返る)、

if mock.errors.has_key?(attr) && value != present_username

で、エラーに attr という key があり、かつ、入力された値 value が現在のユーザーネーム present_username と異なる、という条件で value が不正な条件を作り出している点。

個人的に、mock をつくるのと、errors.has_key? を使うあたり、勉強になった。

色んな方法があるのだなーと。

参考にしたのは、stackoverflow の以下の記事。
Is there a way to validate a specific attribute on an ActiveRecord without instantiating an object first?

また、ActiveRecord を使用している場合は、以下の記事で触れられている方法が使えそう。
Rails - 状況によってsave時に実行するバリデーションを切り替える


view側の実装は別記事にする予定。

Rails で jquery.cookie.js を使って閲覧履歴を表示してみた

jquery.cookie.js と Rails の cookies を使うと、簡単に履歴表示機能を実装することができた。
item オブジェクトが id 属性と name 属性を持っている場合の実装例を書いてみた。

jquery.cookie.jsでクッキーを保存

$(function(){
  var item = "<%= @item.id %>";
  var cookie_name = 'recently_viewed_items';
  var viewed_items = [];
  var delete_item = false;
  $.cookie.defaults.path = "/";

  // 既にクッキーが存在している場合は、ストリングを配列にする
  if($.cookie(cookie_name)){
    viewed_items = $.cookie(cookie_name).split(",");
  }

  // 重複していなければ、itemを配列に追加
  if($.inArray(item, viewed_items)<0){
    viewed_items.push(item);
  }

  // 5個以上ならば1つ削除
  if (viewed_items.length >= 5){
    viewed_items.shift();
  }

  // 配列をクッキ―に保存
  $.cookie(cookie_name, viewed_items);

});


Railsのcookiesを利用してview側で表示を制御

<h2>
  最近チェックしたアイテム
</h2>
<% items = [] %>
<% items = cookies[:recently_viewed_items].split(",") unless cookies[:recently_viewed_items].nil? %>
<% items.each do |id| %>
  <% item = Item.find(id) %>
    <%= item.name %>
<% end %>


jquery 側の実装で item が持つ id を1つの string としてクッキーに保存し、そのクッキーの情報を Rails の view側で1つ1つの id に分解しそれぞれの item の name を表示してみた。

jqueryとRailsのクッキーを使えばこんな簡単にできてしまうという。すごいすごい。



参考にさせてもらった記事

Rails cookies の細かな設定などは上記の記事を確認してみてください。
まだまだ修行中の身なので、おかしな点やもっと効率良くできる点などありましたら、教えていただけると幸いです。

@motokiyoshida

Facebookログインボタンを外したらコンバージョン率が3%アップしたという話

Eコマースを運営する上で、コンバージョン率はKPIの1つとなることが多い。それだけ、色々とA/Bテストが繰り返されている。

ノルウェーの化粧品メーカーのA/Bテストの結果が顕著で面白かったので少し触れることにする。
原文:Facebook Login Reduces Ecommerce Sales (Case Study)



実験はシンプルで、8000人のユーザーに対して、半数には①「Emailフォーム+Facebookログインボタン」を表示し、もう半数には②「Emailフォーム」のみを表示するというもの。以下が実際の表示。

①「Emailフォーム+Facebookログインボタン」
f:id:show_motto:20130823210711p:plain

②「Emailフォームのみ」
f:id:show_motto:20130823210719p:plain


Facebookログインボタンなしでコンバージョン率3%増加

結果はかなり顕著。FacebookログインボタンなしでEmailフォームのみの②の場合の方が、コンバージョン率が3%も高かったそうだ。これは、当サイトの1週間あたりの売上に換算すると、100万円にも及ぶという。もちろん、規模が大きくなるにつれて、その額も大きくなる。


ブランディングやセキュリティリスクという視点

で、この記事を読んで思い出したのが、メルマガの管理が簡単にできるサービス「MailChimp」ブログの以下の記事。
Social Login Buttons Aren’t Worth It

f:id:show_motto:20130823213558p:plain

この記事は、タイトルにある通り、ソーシャルログインボタン(ここでは、Facebookログインボタンとツイッターログインボタン)の有用性について問題提起している。

内容を簡単にまとめると、

  • ソーシャルログインボタンがあるとログイン失敗率は少しだけ減少する
  • でも、ブランディングやセキュリティリスクを考えると、その少しの改善は見合うのか?
  • 正解はないけれど、この記事が議論の発端になればいいな

みたいなことを言っている。つまり、MailChimp のデータでは、ソーシャルログインボタンによってコンバージョン率はやや上昇したが、ブランディングやセキュリティという別の点におけるパフォーマンスに疑問を呈しているわけだ。


自サイトでテストしてみることがスタート

1つ目のノルウェーの化粧品メーカーの例を取り上げている記事の最後でも言われているが、このデータはあくまでも1つの例に過ぎないとのこと。他社のデータに踊らされるなと筆者は締めくくっている。

というわけで、ソーシャルログインボタンの効用については、数字で定量的に測りつつ、ブランドなど定性的な面も見ていくといいのかなと思いました。

シリコンバレーで流行りの Growth Hacking 的な記事でした。


綺麗な英語に触れたかったら「The NEW YORKER」を読むといいかも

アメリカ在住も長い尊敬する友人2人が口を揃えておすすめするメディアがある。それが「THE NEW YORKER」。ウィットの利いた「うまい」文章が他と比べ圧倒的に多いとのこと。

f:id:show_motto:20130823193525p:plain

僕もたまに読んでいるけど、「ああうまいなあ」と楽しみながら読めたりする。たまに、何が言いたいんだろうと悩んでしまう時もあるけれど、だんだんと分かるようになれたらなと思って続けている。

良質な英文に触れたいという人は読んでみるといいかも
http://www.newyorker.com/



渋谷・神泉の担々麺が最高にうまいラーメン屋「うさぎ」は1度は食すべき!

一度食べたらクセになる味。うさぎの担々麺はまさにその言葉にぴったりである。
渋谷道玄坂を登り切って少し進み路地を曲がると、ラーメン屋というよりもバーのような風貌の小さなお店が見えてくる。



「知っていなければ入らないだろうな」という印象だが、それでもお昼時はいつも人で賑わっている。きっとうさぎの虜となったリピーター達が多いのだろう。

前置きはこれくらいにして、下の担々麺は僕の1番のお気に入り。
f:id:show_motto:20180224234352p:plain



そして、汁なし担々麺もまたクセになる味。
f:id:show_motto:20180224234411p:plain



さらに、通常のラーメンも中華そばを極めて上品な味付けでうまい。

f:id:show_motto:20180224234440p:plain

食べログでも3.56の評価はさすがだなと。
ぜひ足を運んでみてください!

食べログはこちら



© 2018 Motoki Yoshida